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