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