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
37typedef 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
51typedef 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 */
72typedef struct PtrdMonitor_t PtrdMonitor;
73/** Typedef */
74typedef struct PtrdMutex_t PtrdMutex;
75/** Typedef */
76typedef struct PtrdSemaphore_t PtrdSemaphore;
77/** Typedef */
78typedef 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 */
89PORTABLE_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 */
103PORTABLE_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 */
113PORTABLE_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 */
124PORTABLE_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 */
144PORTABLE_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 */
166PORTABLE_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 */
185PORTABLE_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 */
213PORTABLE_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 */
240PORTABLE_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 */
256PORTABLE_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 */
265PORTABLE_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 */
277PORTABLE_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 */
297PORTABLE_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 */
310PORTABLE_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 */
322PORTABLE_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 */
333PORTABLE_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 */
347PORTABLE_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 */
359PORTABLE_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 */
366typedef void* PtrdThreadArg;
367/**
368 * Function prototype that launched threads must conform to.
369 *
370 * @param userData Data passed in by caller of PtrdThreadCreate
371 */
372typedef 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 */
402PORTABLE_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 */
417PORTABLE_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 */
426PORTABLE_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 */
437PORTABLE_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 */
448PORTABLE_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 */
455PORTABLE_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 */
464PORTABLE_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 */
472PORTABLE_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 */
481PORTABLE_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