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