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