Home | History | Annotate | Download | only in include
      1 /*---------------------------------------------------------------------------*
      2  *  ptrd.h  *
      3  *                                                                           *
      4  *  Copyright 2007, 2008 Nuance Communciations, Inc.                               *
      5  *                                                                           *
      6  *  Licensed under the Apache License, Version 2.0 (the 'License');          *
      7  *  you may not use this file except in compliance with the License.         *
      8  *                                                                           *
      9  *  You may obtain a copy of the License at                                  *
     10  *      http://www.apache.org/licenses/LICENSE-2.0                           *
     11  *                                                                           *
     12  *  Unless required by applicable law or agreed to in writing, software      *
     13  *  distributed under the License is distributed on an 'AS IS' BASIS,        *
     14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
     15  *  See the License for the specific language governing permissions and      *
     16  *  limitations under the License.                                           *
     17  *                                                                           *
     18  *---------------------------------------------------------------------------*/
     19 
     20 #ifndef PTRD_H
     21 #define PTRD_H
     22 
     23 
     24 
     25 
     26 #ifdef USE_THREAD
     27 
     28 #include "PortPrefix.h"
     29 #include "ptypes.h"
     30 #include "ESR_ReturnCode.h"
     31 
     32 #define STACKSIZE_S2G_SINKER      12*1024
     33 #define STACKSIZE_S2G_RECOGNIZER  25*1024
     34 #define STACKSIZE_DEFAULT         18*1024
     35 
     36 #ifdef _WIN32
     37 typedef unsigned int PTHREAD_ID;
     38 #define PtrdGetCurrentThreadId GetCurrentThreadId
     39 #elif defined(POSIX)
     40 
     41 #if defined(__vxworks) && !defined(REAL_PTHREADS)
     42 #include "pthread_vx.h"
     43 #else
     44 #include <pthread.h>
     45 
     46 #ifndef _POSIX_THREADS
     47 #error "Thread is not defined!"
     48 #endif
     49 #endif /* #if defined(__vxworks) && !defined(REAL_PTHREADS) */
     50 
     51 typedef pthread_t PTHREAD_ID;
     52 #define PtrdGetCurrentThreadId pthread_self
     53 #else
     54 #error Portable Synchronization not defined for this OS!
     55 #endif /* os dependant basic types */
     56 
     57 /**
     58  * @addtogroup PtrdModule PThread API functions
     59  * Library for basic thread and monitor functionality to ensure portability.
     60  * Call PtrdInit() to initialize and PtrdShutdown() to shutdown module.
     61  *
     62  * Every thread has a priority. Threads with higher priority are executed in preference
     63  * to threads with lower priority. When code running in some thread creates a new Thread
     64  * object, the new thread has its priority initially set equal to the priority of the creating
     65  * thread.
     66  *
     67  *
     68  * @{
     69  */
     70 
     71 /** Typedef */
     72 typedef struct PtrdMonitor_t PtrdMonitor;
     73 /** Typedef */
     74 typedef struct PtrdMutex_t PtrdMutex;
     75 /** Typedef */
     76 typedef struct PtrdSemaphore_t PtrdSemaphore;
     77 /** Typedef */
     78 typedef struct PtrdThread_t PtrdThread;
     79 
     80 
     81 /**
     82  * Blocks the current thread for the specified amount of time.
     83  *
     84  * @param sleepTimeMs number of milliseconds to sleep.  A value of 0 is
     85  * equivalent to a thread yield.
     86  *
     87  * @return ESR_SUCCESS if success, or something else to indicate a failure.
     88  */
     89 PORTABLE_API ESR_ReturnCode PtrdSleep(asr_uint32_t sleepTimeMs);
     90 
     91 /**
     92  * Creates a thread monitor.  Thread monitors can be locked, unlocked, can be
     93  * waited on and can be notified.  Monitors implement so-called recursive
     94  * locking, meaning that a thread owning the monitor can call lock without
     95  * blocking and will have to call unlock() as many times as lock() was called.
     96  *
     97  * @param  monitor  Handle to the created monitor
     98  *
     99  * @return ESR_SUCCESS if succes, or something else to indicate a failure.  In
    100  * particular, it will return ESR_INVALID_STATE if the threading API is not
    101  * properly initialized.
    102  */
    103 PORTABLE_API ESR_ReturnCode PtrdMonitorCreate(PtrdMonitor **monitor);
    104 
    105 /**
    106  * Destroys a monitor.
    107  *
    108  * @param  monitor  Handle to the monitor to destroy
    109  *
    110  * @return ESR_SUCCESS if success; ESR_INVALID_STATE if this function is called after the thread
    111  * library is shutdown, or cannot lock on mutex; ESR_INVALID_ARGUMENT if monitor is null
    112  */
    113 PORTABLE_API ESR_ReturnCode PtrdMonitorDestroy(PtrdMonitor *monitor);
    114 
    115 /**
    116  * Locks a monitor.
    117  *
    118  * @param  monitor  Handle to the monitor to lock
    119  * @param  fname Filename of code requesting a lock
    120  * @param  line Line of code requesting a lock
    121  *
    122  * @return ESR_SUCCESS if success; ESR_INVALID_ARGUMENT if monitor is null; ESR_FATAL_ERROR if waiting on the mutex failed
    123  */
    124 PORTABLE_API ESR_ReturnCode PtrdMonitorLockWithLine(PtrdMonitor *monitor, const LCHAR *fname, int line);
    125 /**
    126  * Locks a monitor.
    127  *
    128  * @param  monitor  Handle to the monitor to lock
    129  *
    130  * @return ESR_SUCCESS if success, or an an error indicating the cause of the
    131  * failure.
    132  */
    133 #define PtrdMonitorLock(monitor) PtrdMonitorLockWithLine(monitor, L(__FILE__), __LINE__)
    134 
    135 /**
    136  * Unlock a Monitor
    137  *
    138  * @param  monitor  Handle to the monitor to unlock
    139  *
    140  * @return ESR_SUCCESS if success, or an an error indicating the cause of the
    141  * failure.  In particular, it will return ESR_INVALID_STATE if the current
    142  * thread does not hold the monitor.
    143  */
    144 PORTABLE_API ESR_ReturnCode PtrdMonitorUnlock(PtrdMonitor *monitor);
    145 
    146 /**
    147  * Causes current thread to wait until another thread invokes the
    148  * <code>PtrdMonitorNotify()</code> method or the
    149  * <code>PtrdMonitorNotifyAll()</code> method for this monitor.
    150  *
    151  * <p>
    152  *
    153  * The current thread must own this monitor. The thread releases ownership of
    154  * this monitor and waits until another thread notifies threads waiting on
    155  * this object's monitor to wake up either through a call to the
    156  * <code>PtrdMonitorNotify</code> method or the
    157  * <code>PtrdMonitorNotifyAll</code> method. The thread then waits until it
    158  * can re-obtain ownership of the monitor and resumes execution.
    159  *
    160  * @param monitor The monitor on which to wait.
    161  *
    162  * @return ESR_SUCCESS if success, or an an error indicating the cause of the
    163  * failure.  In particular, it will return ESR_INVALID_STATE if the current
    164  * thread does not hold the monitor.
    165  */
    166 PORTABLE_API ESR_ReturnCode PtrdMonitorWait(PtrdMonitor *monitor);
    167 
    168 
    169 /**
    170  * Causes current thread to wait until either another thread invokes the
    171  * <code>PtrdMonitorNotify()</code> method or the
    172  * <code>PtrdMonitorNotifyAll()</code> method for this monitor, or a specified
    173  * amount of time has elapsed.
    174  *
    175  * @param monitor The monitor on which to wait.
    176  *
    177  * @param timeoutMs The amount of time (in millisecs) to wait for
    178  * notification.
    179  *
    180  * @return ESR_SUCCESS if success, or an an error indicating the cause of the
    181  * failure.  In particular, it will return ESR_INVALID_STATE if the current
    182  * thread does not hold the monitor, or ESR_TIMED_OUT if the timeout expired
    183  * without a notification.
    184  */
    185 PORTABLE_API ESR_ReturnCode PtrdMonitorWaitTimeout(PtrdMonitor *monitor,
    186     asr_uint32_t timeoutMs);
    187 
    188 /**
    189  * Wakes up a single thread that is waiting on this monitor. If more than one
    190  * thread are waiting on this object, one of them is arbitrarily chosen to be
    191  * awakened. A thread waits on the monitor by calling
    192  * <code>PtrdMonitorWait</code> or <code>PtrdMonitorWaitTimeout</code>.
    193  *
    194  * <p>
    195  *
    196  * The awakened thread will not be able to proceed until the current thread
    197  * relinquishes the lock on this object. The awakened thread will compete in
    198  * the usual manner with any other threads that might be actively competing to
    199  * synchronize on this object; for example, the awakened thread enjoys no
    200  * reliable privilege or disadvantage in being the next thread to lock this
    201  * monitor.
    202  *
    203  * <p>
    204  *
    205  * This method should only be called by a thread that is the owner of this
    206  * monitor.
    207  *
    208  * @return ESR_SUCCESS if success, or an an error indicating the cause of the
    209  * failure.  In particular, it will return ESR_INVALID_STATE if the current
    210  * thread does not hold the monitor, or ESR_TIMED_OUT if the timeout expired
    211  * without a notification.
    212  */
    213 PORTABLE_API ESR_ReturnCode PtrdMonitorNotify(PtrdMonitor *monitor);
    214 
    215 /**
    216  * Wakes up all threads that are waiting on this monitor. A thread waits on
    217  * a monitor by calling <code>PtrdMonitorWait</code> or
    218  * <code>PtrdMonitorWaitTimeout</code>
    219  *
    220  * <p>
    221  *
    222  * The awakened threads will not be able to proceed until the current thread
    223  * relinquishes the monitor. The awakened threads will compete in the usual
    224  * manner with any other threads that might be actively competing to
    225  * synchronize on this monitor; for example, the awakened threads enjoy no
    226  * reliable privilege or disadvantage in being the next thread to lock this
    227  * object.
    228  *
    229  * <p>
    230  *
    231  * This method should only be called by a thread that is the owner of this
    232  * object's monitor.
    233  *
    234  * @param monitor The monitor on which to wait.
    235  *
    236  * @return ESR_SUCCESS if success, or an an error indicating the cause of the
    237  * failure.  In particular, it will return ESR_INVALID_STATE if the current
    238  * thread does not hold the monitor.
    239  */
    240 PORTABLE_API ESR_ReturnCode PtrdMonitorNotifyAll(PtrdMonitor *monitor);
    241 
    242 /**
    243  * Creates a thread mutex.  Thread mutexes are similar to thread monitors
    244  * except that they do not support wait and notify mechanism and require less
    245  * resources from the OS.  In situations where this mechanism is not required,
    246  * using mutexes instead of monitors is preferable. Mutexes implement
    247  * so-called recursive locking, meaning that a thread owning the mutex can
    248  * call lock without blocking and will have to call unlock() as many times as
    249  * lock() was called.
    250  *
    251  * @param  mutex  Handle to the created mutex
    252  *
    253  * @return ESR_SUCCESS if success, or an an error indicating the cause of the
    254  * failure.
    255  */
    256 PORTABLE_API ESR_ReturnCode PtrdMutexCreate(PtrdMutex **mutex);
    257 
    258 /**
    259  * Destroys a mutex.
    260  *
    261  * @param  mutex  Handle to the mutex to destroy
    262  *
    263  * @return        ESR_ReturnCode 0 on success
    264  */
    265 PORTABLE_API ESR_ReturnCode PtrdMutexDestroy(PtrdMutex *mutex);
    266 
    267 /**
    268  * Lock a mutex
    269  *
    270  * @param  mutex  Handle to the mutex to lock
    271  * @param  fname Filename of code requesting a lock
    272  * @param  line Line of code requesting a lock
    273  *
    274  * @return ESR_SUCCESS if success, or an an error indicating the cause of the
    275  * failure.
    276  */
    277 PORTABLE_API ESR_ReturnCode PtrdMutexLockWithLine(PtrdMutex *mutex, const LCHAR *fname, int line);
    278 /**
    279  * Lock a mutex
    280  *
    281  * @param  mutex  Handle to the mutex to lock
    282  *
    283  * @return ESR_SUCCESS if success, or an an error indicating the cause of the
    284  * failure.
    285  */
    286 #define PtrdMutexLock(mutex) PtrdMutexLockWithLine(mutex, L(__FILE__), __LINE__)
    287 
    288 /**
    289  * Unlock a Mutex
    290  *
    291  * @param  mutex  Handle to the mutex to unlock
    292  *
    293  * @return ESR_SUCCESS if success, or an an error indicating the cause of the
    294  * failure. In particular, it will return ESR_INVALID_STATE if the current
    295  * thread does not hold the mutex.
    296  */
    297 PORTABLE_API ESR_ReturnCode PtrdMutexUnlock(PtrdMutex *mutex);
    298 
    299 
    300 /**
    301  * Creates a thread semaphore.
    302  *
    303  * @param  semaphore  Handle to the created semaphore.
    304  * @param  initValue  Initial semaphore value
    305  * @param  maxValue   Maximum semaphore value
    306  *
    307  * @return ESR_SUCCESS if success, or an an error indicating the cause of the
    308  * failure.
    309  */
    310 PORTABLE_API ESR_ReturnCode PtrdSemaphoreCreate(unsigned int initValue,
    311     unsigned int maxValue,
    312     PtrdSemaphore **semaphore);
    313 
    314 /**
    315  * Destroy a semaphore
    316  *
    317  * @param  semaphore  Handle to the semaphore to destroy
    318  *
    319  * @return ESR_SUCCESS if success, or an an error indicating the cause of the
    320  * failure.
    321  */
    322 PORTABLE_API ESR_ReturnCode PtrdSemaphoreDestroy(PtrdSemaphore *semaphore);
    323 
    324 /**
    325  * Decrements the semaphore.  If the semaphore's current value is 0, the
    326  * current thread waits until the semaphore's value is greater than 0.
    327  *
    328  * @param  semaphore  Handle to the semaphore to acquire.
    329  *
    330  * @return ESR_SUCCESS if successful, or a status code indicating the nature of
    331  * the error.
    332  */
    333 PORTABLE_API ESR_ReturnCode PtrdSemaphoreAcquire(PtrdSemaphore *semaphore);
    334 
    335 
    336 /**
    337  * Decrements the semaphore.  If the semaphore's current value is 0, the
    338  * current thread waits until the semaphore's value is greater than 0 or until
    339  * the timeout expires.
    340  *
    341  * @param  semaphore  Handle to the semaphore to acquire.
    342  * @param  timeoutMs  Timeout in milliseconds.
    343  *
    344  * @return ESR_SUCCESS if wait is successful, ESR_TIMED_OUT if timed out, or an
    345  * error status indicating the nature of the error in other situations.
    346  */
    347 PORTABLE_API ESR_ReturnCode PtrdSemaphoreAcquireTimeout(PtrdSemaphore *semaphore,
    348     asr_uint32_t timeoutMs);
    349 
    350 /**
    351  * Increments a semaphore.
    352  *
    353  * @param semaphore Handle to the semaphore to release.
    354  *
    355  * @return ESR_SUCCESS success or an error status indicating the nature of the
    356  * error.  In particular, it will return ESR_INVALID_STATE if the semaphore is
    357  * currently at its maximum value.
    358  */
    359 PORTABLE_API ESR_ReturnCode PtrdSemaphoreRelease(PtrdSemaphore *semaphore);
    360 
    361 
    362 /**
    363  * Function signature invoked on the new thread by PtrdThreadCreate(), and
    364  * the argument to that function.
    365  */
    366 typedef void* PtrdThreadArg;
    367 /**
    368  * Function prototype that launched threads must conform to.
    369  *
    370  * @param userData Data passed in by caller of PtrdThreadCreate
    371  */
    372 typedef void(*PtrdThreadStartFunc)(PtrdThreadArg userData);
    373 
    374 /**
    375  * Minimum thread priority.
    376  */
    377 #define PtrdThreadMinPriority 0
    378 
    379 /**
    380  * Maximum thread priority.
    381  */
    382 #define PtrdThreadMaxPriority UINT16_TMAX
    383 
    384 /**
    385  * Normal thread priority.
    386  */
    387 #define PtrdThreadNormalPriority (PtrdThreadMaxPriority / 2)
    388 
    389 /**
    390  * Creates a thread.
    391  *
    392  * Execution starts on the thread immediately. To pause execution use a
    393  * monitor or a mutex between the thread and the thread creator.
    394  *
    395  * @param  thread       Handle to the thread that is created
    396  * @param  startFunc    Function for the thread to start execution on
    397  * @param  arg          Argument to the thread function
    398  *
    399  * @return ESR_INVALID_ARGUMENT if thread or startFunc are null; ESR_OUT_OF_MEMORY if system is out of memory;
    400  * ESR_THREAD_CREATION_ERROR if thread cannot be created
    401  */
    402 PORTABLE_API ESR_ReturnCode PtrdThreadCreate(PtrdThreadStartFunc startFunc, PtrdThreadArg arg,
    403     PtrdThread** thread);
    404 
    405 /**
    406  * Destroys a thread handle.
    407  *
    408  * Note: this does NOT stop or destroy the thread, it just releases
    409  * the handle for accessing it. If this is not done, a memory leak
    410  * occurs, so if the creator of the thread never needs to communicate
    411  * with the thread again it should call this immediately after the
    412  * create if the create was successful.
    413  *
    414  * @return ESR_SUCCESS on failure or an error indicating the nature of the
    415  * error.
    416  */
    417 PORTABLE_API ESR_ReturnCode PtrdThreadDestroy(PtrdThread *thread);
    418 
    419 /**
    420  * Wait for the termination of a specified thread
    421  *
    422  * @param thread Handle to the thread to wait for
    423  *
    424  * @return ESR_INVALID_ARGUMENT if thread is null
    425  */
    426 PORTABLE_API ESR_ReturnCode PtrdThreadJoin(PtrdThread *thread);
    427 
    428 /**
    429  * Returns the thread priority.
    430  *
    431  * @param thread PtrdThread handle
    432  * @param value [out] Thread priority
    433  *
    434  * @return ESR_INVALID_ARGUMENT if thread or value are null; ESR_INVALID_STATE if thread priority cannot be
    435  * retrieved
    436  */
    437 PORTABLE_API ESR_ReturnCode PtrdThreadGetPriority(PtrdThread *thread, asr_uint16_t* value);
    438 
    439 /**
    440  * Sets the thread priority.
    441  *
    442  * @param thread PtrdThread handle
    443  * @param value Thread priority
    444  *
    445  * @return ESR_INVALID_ARGUMENT if thread or value are null; ESR_INVALID_STATE if thread priority cannot be
    446  * set
    447  */
    448 PORTABLE_API ESR_ReturnCode PtrdThreadSetPriority(PtrdThread *thread, asr_uint16_t value);
    449 
    450 /**
    451  * Yields execution of the current thread to other threads.
    452  *
    453  * @return ESR_SUCCESS
    454  */
    455 PORTABLE_API ESR_ReturnCode PtrdThreadYield(void);
    456 
    457 /**
    458  * Initializes the thread library.  This should be called before creating the
    459  * first thread or the first monitor.
    460  *
    461  * @return ESR_INVALID_STATE if the Ptrd module has already been initialized;
    462  * ESR_MUTEX_CREATION_ERROR if mutex cannot be created
    463  */
    464 PORTABLE_API ESR_ReturnCode PtrdInit(void);
    465 
    466 /**
    467  * Indicates if thread library has been initialized.
    468  *
    469  * @param enabled [out] True if library is initialized
    470  * @return ESR_INVALID_ARGUMENT if enabled is null
    471  */
    472 PORTABLE_API ESR_ReturnCode PtrdIsEnabled(ESR_BOOL* enabled);
    473 
    474 /**
    475  * Shutdowns the thread library.  All thread and monitor should be terminated
    476  * and destroyed before calling this function.
    477  *
    478  * @return ESR_INVALID_STATE if Ptrd module is not running
    479  * error.
    480  */
    481 PORTABLE_API ESR_ReturnCode PtrdShutdown(void);
    482 
    483 /**
    484  * @}
    485  */
    486 
    487 #else
    488 
    489 
    490 //#error "Including ptrd.h on a non-threaded platform."
    491 
    492 
    493 #endif /* USE_THREAD */
    494 #endif
    495