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