]>
Commit | Line | Data |
---|---|---|
e9ce8d39 A |
1 | /* |
2 | * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
59e0d9fe A |
6 | * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved. |
7 | * | |
734aad71 A |
8 | * This file contains Original Code and/or Modifications of Original Code |
9 | * as defined in and that are subject to the Apple Public Source License | |
10 | * Version 2.0 (the 'License'). You may not use this file except in | |
11 | * compliance with the License. Please obtain a copy of the License at | |
12 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
13 | * file. | |
14 | * | |
15 | * The Original Code and all software distributed under the License are | |
16 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
e9ce8d39 A |
17 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, |
18 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
734aad71 A |
19 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. |
20 | * Please see the License for the specific language governing rights and | |
21 | * limitations under the License. | |
e9ce8d39 A |
22 | * |
23 | * @APPLE_LICENSE_HEADER_END@ | |
24 | */ | |
25 | /* | |
26 | * Cthreads. | |
27 | */ | |
28 | ||
29 | #ifndef _CTHREADS_ | |
30 | #define _CTHREADS_ 1 | |
31 | ||
32 | #if defined(__cplusplus) | |
33 | #define __DECLBEGIN extern "C" { | |
34 | #define __DECLEND } | |
35 | #else | |
36 | #define __DECLBEGIN | |
37 | #define __DECLEND | |
38 | #endif | |
39 | ||
40 | typedef void *any_t; | |
41 | ||
42 | /* | |
43 | * Spin locks. | |
44 | */ | |
45 | __DECLBEGIN | |
46 | extern void spin_unlock(int *p); | |
47 | extern void spin_lock(int *p); | |
48 | __DECLEND | |
49 | ||
50 | #include <mach/mach_types.h> | |
51 | #include <mach/boolean.h> | |
52 | ||
53 | #ifndef MACRO_BEGIN | |
54 | ||
55 | #define NEVER FALSE | |
56 | ||
57 | #define MACRO_BEGIN do { | |
58 | #define MACRO_END } while (NEVER) | |
59 | ||
60 | #endif /* MACRO_BEGIN */ | |
61 | ||
62 | /* | |
63 | * C Threads package initialization. | |
64 | */ | |
65 | __DECLBEGIN | |
66 | extern void cthread_init(); | |
67 | __DECLEND | |
68 | ||
69 | #include <stdlib.h> | |
70 | ||
71 | /* | |
72 | * Queues. | |
73 | */ | |
74 | typedef struct cthread_queue { | |
75 | struct cthread_queue_item *head; | |
76 | struct cthread_queue_item *tail; | |
77 | } *cthread_queue_t; | |
78 | ||
79 | typedef struct cthread_queue_item { | |
80 | struct cthread_queue_item *next; | |
81 | } *cthread_queue_item_t; | |
82 | ||
83 | #define NO_QUEUE_ITEM ((cthread_queue_item_t) 0) | |
84 | ||
85 | #define QUEUE_INITIALIZER { NO_QUEUE_ITEM, NO_QUEUE_ITEM } | |
86 | ||
87 | #define cthread_queue_alloc() ((cthread_queue_t) calloc(1, sizeof(struct cthread_queue))) | |
88 | #define cthread_queue_init(q) ((q)->head = (q)->tail = 0) | |
89 | #define cthread_queue_free(q) free((any_t) (q)) | |
90 | ||
91 | #define cthread_queue_enq(q, x) \ | |
92 | MACRO_BEGIN \ | |
93 | (x)->next = 0; \ | |
94 | if ((q)->tail == 0) \ | |
95 | (q)->head = (cthread_queue_item_t) (x); \ | |
96 | else \ | |
97 | (q)->tail->next = (cthread_queue_item_t) (x); \ | |
98 | (q)->tail = (cthread_queue_item_t) (x); \ | |
99 | MACRO_END | |
100 | ||
101 | #define cthread_queue_preq(q, x) \ | |
102 | MACRO_BEGIN \ | |
103 | if ((q)->tail == 0) \ | |
104 | (q)->tail = (cthread_queue_item_t) (x); \ | |
105 | ((cthread_queue_item_t) (x))->next = (q)->head; \ | |
106 | (q)->head = (cthread_queue_item_t) (x); \ | |
107 | MACRO_END | |
108 | ||
109 | #define cthread_queue_head(q, t) ((t) ((q)->head)) | |
110 | ||
111 | #define cthread_queue_deq(q, t, x) \ | |
112 | MACRO_BEGIN \ | |
113 | if (((x) = (t) ((q)->head)) != 0 && \ | |
114 | ((q)->head = (cthread_queue_item_t) ((x)->next)) == 0) \ | |
115 | (q)->tail = 0; \ | |
116 | MACRO_END | |
117 | ||
118 | #define cthread_queue_map(q, t, f) \ | |
119 | MACRO_BEGIN \ | |
120 | register cthread_queue_item_t x, next; \ | |
121 | for (x = (cthread_queue_item_t) ((q)->head); x != 0; x = next) { \ | |
122 | next = x->next; \ | |
123 | (*(f))((t) x); \ | |
124 | } \ | |
125 | MACRO_END | |
126 | ||
127 | ||
128 | /* | |
129 | * Mutex objects. | |
130 | */ | |
131 | typedef struct mutex { | |
132 | int lock; | |
133 | char *name; | |
134 | } *mutex_t; | |
135 | ||
136 | #define MUTEX_INITIALIZER { 0, 0 } | |
137 | ||
138 | #define mutex_alloc() ((mutex_t) calloc(1, sizeof(struct mutex))) | |
139 | #define mutex_init(m) ((m)->lock = 0) | |
140 | #define mutex_set_name(m, x) ((m)->name = (x)) | |
141 | #define mutex_name(m) ((m)->name != 0 ? (m)->name : "?") | |
142 | #define mutex_clear(m) /* nop */ | |
143 | #define mutex_free(m) free((any_t) (m)) | |
144 | ||
145 | #define mutex_lock(m) \ | |
146 | MACRO_BEGIN \ | |
147 | if (! mutex_try_lock(m)) mutex_wait_lock(m); \ | |
148 | MACRO_END | |
149 | ||
150 | __DECLBEGIN | |
151 | extern int mutex_try_lock(mutex_t m); /* nonblocking */ | |
152 | extern void mutex_wait_lock(mutex_t m); /* blocking */ | |
153 | extern void mutex_unlock(mutex_t m); | |
154 | __DECLEND | |
155 | ||
156 | /* | |
157 | * Condition variables. | |
158 | */ | |
159 | typedef struct condition { | |
160 | int lock; | |
161 | struct cthread_queue queue; | |
162 | char *name; | |
163 | } *condition_t; | |
164 | ||
165 | #define CONDITION_INITIALIZER { 0, QUEUE_INITIALIZER, 0 } | |
166 | ||
167 | #define condition_alloc() ((condition_t) calloc(1, sizeof(struct condition))) | |
168 | #define condition_init(c) MACRO_BEGIN (c)->lock = 0; cthread_queue_init(&(c)->queue); MACRO_END | |
169 | #define condition_set_name(c, x) ((c)->name = (x)) | |
170 | #define condition_name(c) ((c)->name != 0 ? (c)->name : "?") | |
171 | #define condition_clear(c) MACRO_BEGIN condition_broadcast(c); spin_lock(&(c)->lock); MACRO_END | |
172 | #define condition_free(c) MACRO_BEGIN condition_clear(c); free((any_t) (c)); MACRO_END | |
173 | ||
174 | #define condition_signal(c) \ | |
175 | MACRO_BEGIN \ | |
176 | if ((c)->queue.head) cond_signal(c); \ | |
177 | MACRO_END | |
178 | ||
179 | #define condition_broadcast(c) \ | |
180 | MACRO_BEGIN \ | |
181 | if ((c)->queue.head) cond_broadcast(c); \ | |
182 | MACRO_END | |
183 | ||
184 | __DECLBEGIN | |
185 | extern void cond_signal(condition_t c); | |
186 | extern void cond_broadcast(condition_t c); | |
187 | extern void condition_wait(condition_t c, mutex_t m); | |
188 | __DECLEND | |
189 | ||
190 | /* | |
191 | * Threads. | |
192 | */ | |
193 | ||
194 | typedef any_t (*cthread_fn_t)(any_t arg); | |
195 | ||
196 | #import <setjmp.h> | |
197 | ||
198 | typedef struct cthread { | |
199 | struct cthread *next; | |
200 | thread_port_t real_thread; | |
201 | struct mutex lock; | |
202 | struct condition done; | |
203 | int state; | |
204 | #if defined(__cplusplus) | |
205 | jmp_buf catchBuf; | |
206 | #else | |
207 | jmp_buf catch; | |
208 | #endif | |
209 | cthread_fn_t func; | |
210 | any_t arg; | |
211 | any_t result; | |
212 | const char *name; | |
213 | any_t data; | |
214 | } *cthread_t; | |
215 | ||
216 | #define NO_CTHREAD ((cthread_t) 0) | |
217 | ||
218 | __DECLBEGIN | |
219 | extern cthread_t cthread_fork(cthread_fn_t func, any_t arg); | |
220 | extern void cthread_detach(cthread_t t); | |
221 | extern any_t cthread_join(cthread_t t); | |
222 | extern void cthread_yield(void); | |
223 | extern void cthread_exit(any_t result); | |
224 | extern kern_return_t cthread_priority( | |
225 | cthread_t t, | |
226 | int priority, | |
227 | boolean_t set_max); | |
228 | extern kern_return_t cthread_max_priority( | |
229 | cthread_t t, | |
230 | mach_port_t pset, | |
231 | int max_priority); | |
232 | extern kern_return_t cthread_abort(cthread_t t); | |
233 | __DECLEND | |
234 | ||
235 | /* | |
236 | * This structure must agree with struct cproc in cthread_internals.h | |
237 | */ | |
238 | typedef struct ur_cthread { | |
239 | struct ur_cthread *next; | |
240 | cthread_t incarnation; | |
241 | } *ur_cthread_t; | |
242 | ||
243 | __DECLBEGIN | |
244 | extern int cthread_sp(void); | |
245 | ||
246 | extern int cthread_stack_mask; | |
247 | ||
248 | extern ur_cthread_t ur_cthread_self(void); | |
249 | #define cthread_thread(c) (c->real_thread) | |
250 | extern void cthread_set_errno_self(int e); | |
251 | extern int cthread_errno(void); | |
252 | #define cthread_assoc(id, t) (((ur_cthread_t) (id))->incarnation = (t)) | |
253 | #define cthread_self() (ur_cthread_self()->incarnation) | |
254 | ||
255 | extern void cthread_set_name(cthread_t t, const char *name); | |
256 | extern const char *cthread_name(cthread_t t); | |
257 | extern int cthread_count(void); | |
258 | extern void cthread_set_limit(int n); | |
259 | extern int cthread_limit(void); | |
260 | __DECLEND | |
261 | ||
262 | #define cthread_set_data(t, x) ((t)->data = (x)) | |
263 | #define cthread_data(t) ((t)->data) | |
264 | ||
265 | /* | |
266 | * Spin locks. | |
267 | */ | |
268 | #define spin_unlock(p) (*(p) = 0) | |
269 | ||
270 | /* | |
271 | * Mutex locks. | |
272 | */ | |
273 | #define mutex_unlock(m) ((m)->lock = 0) | |
274 | ||
275 | ||
276 | /* | |
277 | * Debugging support. | |
278 | */ | |
279 | #ifdef CTHREADS_DEBUG | |
280 | ||
281 | #ifndef ASSERT | |
282 | /* | |
283 | * Assertion macro, similar to <assert.h> | |
284 | */ | |
285 | #import <stdio.h> | |
286 | #define ASSERT(p) \ | |
287 | MACRO_BEGIN \ | |
288 | if (!(p)) { \ | |
289 | fprintf(stderr, \ | |
290 | "File %s, line %d: assertion p failed.\n", \ | |
291 | __FILE__, __LINE__); \ | |
292 | abort(); \ | |
293 | } \ | |
294 | MACRO_END | |
295 | ||
296 | #endif /* ASSERT */ | |
297 | ||
298 | #define SHOULDNT_HAPPEN 0 | |
299 | ||
300 | extern int cthread_debug; | |
301 | ||
302 | #else /* CTHREADS_DEBUG */ | |
303 | ||
304 | #ifndef ASSERT | |
305 | #define ASSERT(p) | |
306 | #endif /* ASSERT */ | |
307 | ||
308 | #endif /* CTHREADS_DEBUG */ | |
309 | ||
310 | #endif /* _CTHREADS_ */ |