1 /* 2 * implement.h 3 * 4 * Definitions that don't need to be public. 5 * 6 * Keeps all the internals out of pthread.h 7 * 8 * -------------------------------------------------------------------------- 9 * 10 * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems 11 * Copyright(C) 2008 Jason Schmidlapp 12 * 13 * Contact Email: jschmidlapp@users.sourceforge.net 14 * 15 * 16 * Pthreads-embedded (PTE) - POSIX Threads Library for embedded systems 17 * Copyright(C) 2008 Jason Schmidlapp 18 * 19 * Contact Email: jschmidlapp@users.sourceforge.net 20 * 21 * 22 * Based upon Pthreads-win32 - POSIX Threads Library for Win32 23 * Copyright(C) 1998 John E. Bossom 24 * Copyright(C) 1999,2005 Pthreads-win32 contributors 25 * 26 * Contact Email: rpj@callisto.canberra.edu.au 27 * 28 * The original list of contributors to the Pthreads-win32 project 29 * is contained in the file CONTRIBUTORS.ptw32 included with the 30 * source code distribution. The list can also be seen at the 31 * following World Wide Web location: 32 * http://sources.redhat.com/pthreads-win32/contributors.html 33 * 34 * This library is free software; you can redistribute it and/or 35 * modify it under the terms of the GNU Lesser General Public 36 * License as published by the Free Software Foundation; either 37 * version 2 of the License, or (at your option) any later version. 38 * 39 * This library is distributed in the hope that it will be useful, 40 * but WITHOUT ANY WARRANTY; without even the implied warranty of 41 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 42 * Lesser General Public License for more details. 43 * 44 * You should have received a copy of the GNU Lesser General Public 45 * License along with this library in the file COPYING.LIB; 46 * if not, write to the Free Software Foundation, Inc., 47 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA 48 */ 49 50 51 #ifndef _IMPLEMENT_H 52 #define _IMPLEMENT_H 53 54 #include "pte_osal.h" 55 56 /* use local include files during development */ 57 #include "semaphore.h" 58 #include "sched.h" 59 60 61 typedef enum 62 { 63 /* 64 * This enumeration represents the state of the thread; 65 * The thread is still "alive" if the numeric value of the 66 * state is greater or equal "PThreadStateRunning". 67 */ 68 PThreadStateInitial = 0, /* Thread not running */ 69 PThreadStateRunning, /* Thread alive & kicking */ 70 PThreadStateSuspended, /* Thread alive but suspended */ 71 PThreadStateCancelPending, /* Thread alive but is */ 72 /* has cancelation pending. */ 73 PThreadStateCanceling, /* Thread alive but is */ 74 /* in the process of terminating */ 75 /* due to a cancellation request */ 76 PThreadStateException, /* Thread alive but exiting */ 77 /* due to an exception */ 78 PThreadStateLast 79 } 80 PThreadState; 81 82 83 typedef struct pte_thread_t_ pte_thread_t; 84 85 struct pte_thread_t_ 86 { 87 pte_osThreadHandle threadId; /* OS specific thread handle */ 88 pthread_t ptHandle; /* This thread's permanent pthread_t handle */ 89 pte_thread_t * prevReuse; /* Links threads on reuse stack */ 90 volatile PThreadState state; 91 void *exitStatus; 92 void *parms; 93 int ptErrno; 94 int detachState; 95 pthread_mutex_t threadLock; /* Used for serialised access to public thread state */ 96 int sched_priority; /* As set, not as currently is */ 97 pthread_mutex_t cancelLock; /* Used for async-cancel safety */ 98 int cancelState; 99 int cancelType; 100 int cancelEvent; 101 #ifdef PTE_CLEANUP_C 102 jmp_buf start_mark; 103 #endif /* PTE_CLEANUP_C */ 104 int implicit: 105 1; 106 void *keys; 107 void *nextAssoc; 108 }; 109 110 111 /* 112 * Special value to mark attribute objects as valid. 113 */ 114 #define PTE_ATTR_VALID ((unsigned long) 0xC4C0FFEE) 115 116 struct pthread_attr_t_ 117 { 118 unsigned long valid; 119 void *stackaddr; 120 size_t stacksize; 121 int detachstate; 122 struct sched_param param; 123 int inheritsched; 124 int contentionscope; 125 }; 126 127 128 /* 129 * ==================== 130 * ==================== 131 * Semaphores, Mutexes and Condition Variables 132 * ==================== 133 * ==================== 134 */ 135 136 struct sem_t_ 137 { 138 int value; 139 pthread_mutex_t lock; 140 pte_osSemaphoreHandle sem; 141 }; 142 143 #define PTE_OBJECT_AUTO_INIT ((void *) -1) 144 #define PTE_OBJECT_INVALID 0 145 146 struct pthread_mutex_t_ 147 { 148 pte_osSemaphoreHandle handle; 149 int lock_idx; 150 /* Provides exclusive access to mutex state 151 via the Interlocked* mechanism. 152 0: unlocked/free. 153 1: locked - no other waiters. 154 -1: locked - with possible other waiters. 155 */ 156 int recursive_count; /* Number of unlocks a thread needs to perform 157 before the lock is released (recursive 158 mutexes only). */ 159 int kind; /* Mutex type. */ 160 pthread_t ownerThread; 161 }; 162 163 struct pthread_mutexattr_t_ 164 { 165 int pshared; 166 int kind; 167 }; 168 169 /* 170 * Possible values, other than PTE_OBJECT_INVALID, 171 * for the "interlock" element in a spinlock. 172 * 173 * In this implementation, when a spinlock is initialised, 174 * the number of cpus available to the process is checked. 175 * If there is only one cpu then "interlock" is set equal to 176 * PTE_SPIN_USE_MUTEX and u.mutex is a initialised mutex. 177 * If the number of cpus is greater than 1 then "interlock" 178 * is set equal to PTE_SPIN_UNLOCKED and the number is 179 * stored in u.cpus. This arrangement allows the spinlock 180 * routines to attempt an InterlockedCompareExchange on "interlock" 181 * immediately and, if that fails, to try the inferior mutex. 182 * 183 * "u.cpus" isn't used for anything yet, but could be used at 184 * some point to optimise spinlock behaviour. 185 */ 186 #define PTE_SPIN_UNLOCKED (1) 187 #define PTE_SPIN_LOCKED (2) 188 #define PTE_SPIN_USE_MUTEX (3) 189 190 struct pthread_spinlock_t_ 191 { 192 int interlock; /* Locking element for multi-cpus. */ 193 union 194 { 195 int cpus; /* No. of cpus if multi cpus, or */ 196 pthread_mutex_t mutex; /* mutex if single cpu. */ 197 } u; 198 }; 199 200 struct pthread_barrier_t_ 201 { 202 unsigned int nCurrentBarrierHeight; 203 unsigned int nInitialBarrierHeight; 204 int iStep; 205 int pshared; 206 sem_t semBarrierBreeched[2]; 207 }; 208 209 struct pthread_barrierattr_t_ 210 { 211 int pshared; 212 }; 213 214 struct pthread_key_t_ 215 { 216 unsigned key; 217 void (*destructor) (void *); 218 pthread_mutex_t keyLock; 219 void *threads; 220 }; 221 222 223 typedef struct ThreadParms ThreadParms; 224 typedef struct ThreadKeyAssoc ThreadKeyAssoc; 225 226 struct ThreadParms 227 { 228 pthread_t tid; 229 void *(*start) (void *); 230 void *arg; 231 }; 232 233 struct pthread_cond_t_ 234 { 235 long nWaitersBlocked; /* Number of threads blocked */ 236 long nWaitersGone; /* Number of threads timed out */ 237 long nWaitersToUnblock; /* Number of threads to unblock */ 238 sem_t semBlockQueue; /* Queue up threads waiting for the */ 239 /* condition to become signalled */ 240 sem_t semBlockLock; /* Semaphore that guards access to */ 241 /* | waiters blocked count/block queue */ 242 /* +-> Mandatory Sync.LEVEL-1 */ 243 pthread_mutex_t mtxUnblockLock; /* Mutex that guards access to */ 244 /* | waiters (to)unblock(ed) counts */ 245 /* +-> Optional* Sync.LEVEL-2 */ 246 pthread_cond_t next; /* Doubly linked list */ 247 pthread_cond_t prev; 248 }; 249 250 251 struct pthread_condattr_t_ 252 { 253 int pshared; 254 // TODO: use clock_id 255 clockid_t clock_id; 256 }; 257 258 #define PTE_RWLOCK_MAGIC 0xfacade2 259 260 struct pthread_rwlock_t_ 261 { 262 pthread_mutex_t mtxExclusiveAccess; 263 pthread_mutex_t mtxSharedAccessCompleted; 264 pthread_cond_t cndSharedAccessCompleted; 265 int nSharedAccessCount; 266 int nExclusiveAccessCount; 267 int nCompletedSharedAccessCount; 268 int nMagic; 269 }; 270 271 struct pthread_rwlockattr_t_ 272 { 273 int pshared; 274 }; 275 276 /* 277 * MCS lock queue node - see pte_MCS_lock.c 278 */ 279 struct pte_mcs_node_t_ 280 { 281 struct pte_mcs_node_t_ **lock; /* ptr to tail of queue */ 282 struct pte_mcs_node_t_ *next; /* ptr to successor in queue */ 283 unsigned int readyFlag; /* set after lock is released by 284 predecessor */ 285 unsigned int nextFlag; /* set after 'next' ptr is set by 286 successor */ 287 }; 288 289 typedef struct pte_mcs_node_t_ pte_mcs_local_node_t; 290 typedef struct pte_mcs_node_t_ *pte_mcs_lock_t; 291 292 293 struct ThreadKeyAssoc 294 { 295 /* 296 * Purpose: 297 * This structure creates an association between a thread and a key. 298 * It is used to implement the implicit invocation of a user defined 299 * destroy routine for thread specific data registered by a user upon 300 * exiting a thread. 301 * 302 * Graphically, the arrangement is as follows, where: 303 * 304 * K - Key with destructor 305 * (head of chain is key->threads) 306 * T - Thread that has called pthread_setspecific(Kn) 307 * (head of chain is thread->keys) 308 * A - Association. Each association is a node at the 309 * intersection of two doubly-linked lists. 310 * 311 * T1 T2 T3 312 * | | | 313 * | | | 314 * K1 -----+-----A-----A-----> 315 * | | | 316 * | | | 317 * K2 -----A-----A-----+-----> 318 * | | | 319 * | | | 320 * K3 -----A-----+-----A-----> 321 * | | | 322 * | | | 323 * V V V 324 * 325 * Access to the association is guarded by two locks: the key's 326 * general lock (guarding the row) and the thread's general 327 * lock (guarding the column). This avoids the need for a 328 * dedicated lock for each association, which not only consumes 329 * more handles but requires that: before the lock handle can 330 * be released - both the key must be deleted and the thread 331 * must have called the destructor. The two-lock arrangement 332 * allows the resources to be freed as soon as either thread or 333 * key is concluded. 334 * 335 * To avoid deadlock: whenever both locks are required, the key 336 * and thread locks are always acquired in the order: key lock 337 * then thread lock. An exception to this exists when a thread 338 * calls the destructors, however this is done carefully to 339 * avoid deadlock. 340 * 341 * An association is created when a thread first calls 342 * pthread_setspecific() on a key that has a specified 343 * destructor. 344 * 345 * An association is destroyed either immediately after the 346 * thread calls the key destructor function on thread exit, or 347 * when the key is deleted. 348 * 349 * Attributes: 350 * thread 351 * reference to the thread that owns the 352 * association. This is actually the pointer to the 353 * thread struct itself. Since the association is 354 * destroyed before the thread exits, this can never 355 * point to a different logical thread to the one that 356 * created the assoc, i.e. after thread struct reuse. 357 * 358 * key 359 * reference to the key that owns the association. 360 * 361 * nextKey 362 * The pthread_t->keys attribute is the head of a 363 * chain of associations that runs through the nextKey 364 * link. This chain provides the 1 to many relationship 365 * between a pthread_t and all pthread_key_t on which 366 * it called pthread_setspecific. 367 * 368 * prevKey 369 * Similarly. 370 * 371 * nextThread 372 * The pthread_key_t->threads attribute is the head of 373 * a chain of assoctiations that runs through the 374 * nextThreads link. This chain provides the 1 to many 375 * relationship between a pthread_key_t and all the 376 * PThreads that have called pthread_setspecific for 377 * this pthread_key_t. 378 * 379 * prevThread 380 * Similarly. 381 * 382 * Notes: 383 * 1) As soon as either the key or the thread is no longer 384 * referencing the association, it can be destroyed. The 385 * association will be removed from both chains. 386 * 387 * 2) An association is only created by 388 * pthread_setspecific if the user provided a 389 * destroyRoutine when they created the key. 390 * 391 * 392 */ 393 pte_thread_t * thread; 394 pthread_key_t key; 395 ThreadKeyAssoc *nextKey; 396 ThreadKeyAssoc *nextThread; 397 ThreadKeyAssoc *prevKey; 398 ThreadKeyAssoc *prevThread; 399 }; 400 401 /* 402 * Services available through EXCEPTION_PTE_SERVICES 403 * and also used [as parameters to pte_throw()] as 404 * generic exception selectors. 405 */ 406 407 #define PTE_EPS_EXIT (1) 408 #define PTE_EPS_CANCEL (2) 409 410 411 /* Useful macros */ 412 #define PTE_MAX(a,b) ((a)<(b)?(b):(a)) 413 #define PTE_MIN(a,b) ((a)>(b)?(b):(a)) 414 415 416 /* Thread Reuse stack bottom marker. Must not be NULL or any valid pointer to memory. */ 417 #define PTE_THREAD_REUSE_EMPTY ((pte_thread_t *) 1) 418 419 extern int pte_processInitialized; 420 extern pte_thread_t * pte_threadReuseTop; 421 extern pte_thread_t * pte_threadReuseBottom; 422 extern pthread_key_t pte_selfThreadKey; 423 extern pthread_key_t pte_cleanupKey; 424 extern pthread_cond_t pte_cond_list_head; 425 extern pthread_cond_t pte_cond_list_tail; 426 427 extern int pte_mutex_default_kind; 428 429 extern int pte_concurrency; 430 431 extern int pte_features; 432 433 extern pte_osMutexHandle pte_thread_reuse_lock; 434 extern pte_osMutexHandle pte_mutex_test_init_lock; 435 extern pte_osMutexHandle pte_cond_list_lock; 436 extern pte_osMutexHandle pte_cond_test_init_lock; 437 extern pte_osMutexHandle pte_rwlock_test_init_lock; 438 extern pte_osMutexHandle pte_spinlock_test_init_lock; 439 440 441 #ifdef __cplusplus 442 extern "C" 443 { 444 #endif /* __cplusplus */ 445 446 /* 447 * ===================== 448 * ===================== 449 * Forward Declarations 450 * ===================== 451 * ===================== 452 */ 453 454 int pte_is_attr (const pthread_attr_t * attr); 455 456 int pte_cond_check_need_init (pthread_cond_t * cond); 457 int pte_mutex_check_need_init (pthread_mutex_t * mutex); 458 int pte_rwlock_check_need_init (pthread_rwlock_t * rwlock); 459 int pte_spinlock_check_need_init (pthread_spinlock_t * lock); 460 461 int pte_processInitialize (void); 462 463 void pte_processTerminate (void); 464 465 void pte_threadDestroy (pthread_t tid); 466 void pte_threadExitAndDestroy (pthread_t tid); 467 468 void pte_pop_cleanup_all (int execute); 469 470 pthread_t pte_new (void); 471 472 pthread_t pte_threadReusePop (void); 473 474 void pte_threadReusePush (pthread_t thread); 475 476 int pte_getprocessors (int *count); 477 478 int pte_setthreadpriority (pthread_t thread, int policy, int priority); 479 480 void pte_rwlock_cancelwrwait (void *arg); 481 482 int pte_threadStart (void *vthreadParms); 483 484 void pte_callUserDestroyRoutines (pthread_t thread); 485 486 int pte_tkAssocCreate (pte_thread_t * thread, pthread_key_t key); 487 488 void pte_tkAssocDestroy (ThreadKeyAssoc * assoc); 489 490 int sem_wait_nocancel (sem_t * sem); 491 492 unsigned int pte_relmillisecs (const struct timespec * abstime); 493 494 void pte_mcs_lock_acquire (pte_mcs_lock_t * lock, pte_mcs_local_node_t * node); 495 496 void pte_mcs_lock_release (pte_mcs_local_node_t * node); 497 498 /* Declared in private.c */ 499 void pte_throw (unsigned int exception); 500 501 int pte_cancellable_wait (pte_osSemaphoreHandle semHandle, unsigned int* timeout); 502 503 #define PTE_ATOMIC_EXCHANGE pte_osAtomicExchange 504 #define PTE_ATOMIC_EXCHANGE_ADD pte_osAtomicExchangeAdd 505 #define PTE_ATOMIC_COMPARE_EXCHANGE pte_osAtomicCompareExchange 506 #define PTE_ATOMIC_DECREMENT pte_osAtomicDecrement 507 #define PTE_ATOMIC_INCREMENT pte_osAtomicIncrement 508 509 int pte_thread_detach_np(); 510 int pte_thread_detach_and_exit_np(); 511 512 513 #ifdef __cplusplus 514 } 515 #endif /* __cplusplus */ 516 517 518 #endif /* _IMPLEMENT_H */ 519