xref: /relibc/pthreads-emb/implement.h (revision 7af8bdd54f609ebec03115d05be2bcc851986fad)
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