• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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