1 /*
2 **  GNU Pth - The GNU Portable Threads
3 **  Copyright (c) 1999-2006 Ralf S. Engelschall <rse@engelschall.com>
4 **
5 **  This file is part of GNU Pth, a non-preemptive thread scheduling
6 **  library which can be found at http://www.gnu.org/software/pth/.
7 **
8 **  This library is free software; you can redistribute it and/or
9 **  modify it under the terms of the GNU Lesser General Public
10 **  License as published by the Free Software Foundation; either
11 **  version 2.1 of the License, or (at your option) any later version.
12 **
13 **  This library is distributed in the hope that it will be useful,
14 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 **  Lesser General Public License for more details.
17 **
18 **  You should have received a copy of the GNU Lesser General Public
19 **  License along with this library; if not, write to the Free Software
20 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 **  USA, or contact Ralf S. Engelschall <rse@engelschall.com>.
22 **
23 **  pth_tcb.c: Pth thread control block handling
24 */
25                              /* Patient: Doctor, it hurts when I do this!
26                                 Doctor: Well, then don't do it. */
27 #include "pth_p.h"
28 
29 #if cpp
30 
31 #define PTH_TCB_NAMELEN 40
32 
33     /* thread control block */
34 struct pth_st {
35     /* priority queue handling */
36     pth_t          q_next;               /* next thread in pool                         */
37     pth_t          q_prev;               /* previous thread in pool                     */
38     int            q_prio;               /* (relative) priority of thread when queued   */
39 
40     /* standard thread control block ingredients */
41     int            prio;                 /* base priority of thread                     */
42     char           name[PTH_TCB_NAMELEN];/* name of thread (mainly for debugging)       */
43     int            dispatches;           /* total number of thread dispatches           */
44     pth_state_t    state;                /* current state indicator for thread          */
45 
46     /* timing */
47     pth_time_t     spawned;              /* time point at which thread was spawned      */
48     pth_time_t     lastran;              /* time point at which thread was last running */
49     pth_time_t     running;              /* time range the thread was already running   */
50 
51     /* event handling */
52     pth_event_t    events;               /* events the tread is waiting for             */
53 
54     /* per-thread signal handling */
55     sigset_t       sigpending;           /* set    of pending signals                   */
56     int            sigpendcnt;           /* number of pending signals                   */
57 
58     /* machine context */
59     pth_mctx_t     mctx;                 /* last saved machine state of thread          */
60     char          *stack;                /* pointer to thread stack                     */
61     unsigned int   stacksize;            /* size of thread stack                        */
62     long          *stackguard;           /* stack overflow guard                        */
63     int            stackloan;            /* stack type                                  */
64     void        *(*start_func)(void *);  /* start routine                               */
65     void          *start_arg;            /* start argument                              */
66 
67     /* thread joining */
68     int            joinable;             /* whether thread is joinable                  */
69     void          *join_arg;             /* joining argument                            */
70 
71     /* per-thread specific storage */
72     const void   **data_value;           /* thread specific  values                     */
73     int            data_count;           /* number of stored values                     */
74 
75     /* cancellation support */
76     int            cancelreq;            /* cancellation request is pending             */
77     unsigned int   cancelstate;          /* cancellation state of thread                */
78     pth_cleanup_t *cleanups;             /* stack of thread cleanup handlers            */
79 
80     /* mutex ring */
81     pth_ring_t     mutexring;            /* ring of aquired mutex structures            */
82 
83 #ifdef PTH_EX
84     /* per-thread exception handling */
85     ex_ctx_t       ex_ctx;               /* exception handling context                  */
86 #endif
87 };
88 
89 #endif /* cpp */
90 
91 intern const char *pth_state_names[] = {
92     "scheduler", "new", "ready", "running", "waiting", "dead"
93 };
94 
95 #if defined(MINSIGSTKSZ) && !defined(SIGSTKSZ)
96 #define SIGSTKSZ MINSIGSTKSZ
97 #endif
98 #if !defined(SIGSTKSZ)
99 #define SIGSTKSZ 8192
100 #endif
101 
102 /* allocate a thread control block */
pth_tcb_alloc(unsigned int stacksize,void * stackaddr)103 intern pth_t pth_tcb_alloc(unsigned int stacksize, void *stackaddr)
104 {
105     pth_t t;
106 
107     if (stacksize > 0 && stacksize < SIGSTKSZ)
108         stacksize = SIGSTKSZ;
109     if ((t = (pth_t)malloc(sizeof(struct pth_st))) == NULL)
110         return NULL;
111     t->stacksize  = stacksize;
112     t->stack      = NULL;
113     t->stackguard = NULL;
114     t->stackloan  = (stackaddr != NULL ? TRUE : FALSE);
115     if (stacksize > 0) { /* stacksize == 0 means "main" thread */
116         if (stackaddr != NULL)
117             t->stack = (char *)(stackaddr);
118         else {
119             if ((t->stack = (char *)malloc(stacksize)) == NULL) {
120                 pth_shield { free(t); }
121                 return NULL;
122             }
123         }
124 #if PTH_STACKGROWTH < 0
125         /* guard is at lowest address (alignment is guarrantied) */
126         t->stackguard = (long *)((long)t->stack); /* double cast to avoid alignment warning */
127 #else
128         /* guard is at highest address (be careful with alignment) */
129         t->stackguard = (long *)(t->stack+(((stacksize/sizeof(long))-1)*sizeof(long)));
130 #endif
131         *t->stackguard = 0xDEAD;
132     }
133     return t;
134 }
135 
136 /* free a thread control block */
pth_tcb_free(pth_t t)137 intern void pth_tcb_free(pth_t t)
138 {
139     if (t == NULL)
140         return;
141     if (t->stack != NULL && !t->stackloan)
142         free(t->stack);
143     if (t->data_value != NULL)
144         free(t->data_value);
145     if (t->cleanups != NULL)
146         pth_cleanup_popall(t, FALSE);
147     free(t);
148     return;
149 }
150 
151