1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
|
/*
* Mach Operating System
* Copyright (c) 1993,1992,1991,1990,1989 Carnegie Mellon University
* All Rights Reserved.
*
* Permission to use, copy, modify and distribute this software and its
* documentation is hereby granted, provided that both the copyright
* notice and this permission notice appear in all copies of the
* software, derivative works or modified versions, and any portions
* thereof, and that both notices appear in supporting documentation.
*
* CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
* CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
* ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
*
* Carnegie Mellon requests users of this software to return to
*
* Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
* School of Computer Science
* Carnegie Mellon University
* Pittsburgh PA 15213-3890
*
* any improvements or extensions that they make and grant Carnegie Mellon
* the rights to redistribute these changes.
*/
/*
* File: cthreads.h
* Author: Eric Cooper, Carnegie Mellon University
* Date: Jul, 1987
*
* Definitions for the C Threads package.
*
*/
#ifndef _CTHREADS_
#define _CTHREADS_ 1
#include <mach/machine/cthreads.h>
#include <mach.h>
#include <mach/macro_help.h>
#include <mach/machine/vm_param.h>
#ifdef __STDC__
extern void *malloc();
#else
extern char *malloc();
#endif
typedef void *any_t; /* XXX - obsolete, should be deleted. */
#if defined(TRUE)
#else /* not defined(TRUE) */
#define TRUE 1
#define FALSE 0
#endif
/*
* C Threads package initialization.
*/
extern vm_offset_t cthread_init(void);
/*
* Queues.
*/
typedef struct cthread_queue {
struct cthread_queue_item *head;
struct cthread_queue_item *tail;
} *cthread_queue_t;
typedef struct cthread_queue_item {
struct cthread_queue_item *next;
} *cthread_queue_item_t;
#define NO_QUEUE_ITEM ((cthread_queue_item_t) 0)
#define QUEUE_INITIALIZER { NO_QUEUE_ITEM, NO_QUEUE_ITEM }
#define cthread_queue_alloc() ((cthread_queue_t) calloc(1, sizeof(struct cthread_queue)))
#define cthread_queue_init(q) ((q)->head = (q)->tail = 0)
#define cthread_queue_free(q) free((q))
#define cthread_queue_enq(q, x) \
MACRO_BEGIN \
(x)->next = 0; \
if ((q)->tail == 0) \
(q)->head = (cthread_queue_item_t) (x); \
else \
(q)->tail->next = (cthread_queue_item_t) (x); \
(q)->tail = (cthread_queue_item_t) (x); \
MACRO_END
#define cthread_queue_preq(q, x) \
MACRO_BEGIN \
if ((q)->tail == 0) \
(q)->tail = (cthread_queue_item_t) (x); \
((cthread_queue_item_t) (x))->next = (q)->head; \
(q)->head = (cthread_queue_item_t) (x); \
MACRO_END
#define cthread_queue_head(q, t) ((t) ((q)->head))
#define cthread_queue_deq(q, t, x) \
MACRO_BEGIN \
if (((x) = (t) ((q)->head)) != 0 && \
((q)->head = (cthread_queue_item_t) ((x)->next)) == 0) \
(q)->tail = 0; \
MACRO_END
#define cthread_queue_map(q, t, f) \
MACRO_BEGIN \
register cthread_queue_item_t x, next; \
for (x = (cthread_queue_item_t) ((q)->head); x != 0; x = next){\
next = x->next; \
(*(f))((t) x); \
} \
MACRO_END
/*
* Spin locks.
*/
extern void spin_lock_solid(spin_lock_t *_lock);
#if defined(spin_unlock)
#else /* not defined(spin_unlock) */
extern void spin_unlock(spin_lock_t *_lock);
#endif
#if defined(spin_try_lock)
#else /* not defined(spin_try_lock) */
extern boolean_t spin_try_lock(spin_lock_t *_lock);
#endif
#define spin_lock(p) \
MACRO_BEGIN \
if (!spin_try_lock(p)) { \
spin_lock_solid(p); \
} \
MACRO_END
/*
* Mutex objects.
*/
typedef struct mutex {
spin_lock_t lock;
const char *name;
struct cthread_queue queue;
spin_lock_t held;
/* holder is for WAIT_DEBUG. Not ifdeffed to keep size constant. */
struct cthread *holder;
} *mutex_t;
#define MUTEX_INITIALIZER { SPIN_LOCK_INITIALIZER, 0, QUEUE_INITIALIZER, SPIN_LOCK_INITIALIZER}
#define MUTEX_NAMED_INITIALIZER(Name) { SPIN_LOCK_INITIALIZER, Name, QUEUE_INITIALIZER, SPIN_LOCK_INITIALIZER}
#ifdef WAIT_DEBUG
#define mutex_set_holder(m,h) ((m)->holder = (h))
#else
#define mutex_set_holder(m,h) (0)
#endif
#define mutex_alloc() ((mutex_t) calloc(1, sizeof(struct mutex)))
#define mutex_init(m) \
MACRO_BEGIN \
spin_lock_init(&(m)->lock); \
cthread_queue_init(&(m)->queue); \
spin_lock_init(&(m)->held); \
mutex_set_holder(m, 0); \
MACRO_END
#define mutex_set_name(m, x) ((m)->name = (x))
#define mutex_name(m) ((m)->name != 0 ? (m)->name : "?")
#define mutex_clear(m) /* nop */???
#define mutex_free(m) free((m))
extern void mutex_lock_solid(mutex_t _mutex); /* blocking */
extern void mutex_unlock_solid(mutex_t _mutex);
#define mutex_try_lock(m) \
(spin_try_lock(&(m)->held) ? mutex_set_holder((m), cthread_self()), TRUE : FALSE)
#define mutex_lock(m) \
MACRO_BEGIN \
if (!spin_try_lock(&(m)->held)) { \
mutex_lock_solid(m); \
} \
mutex_set_holder(m, cthread_self()); \
MACRO_END
#define mutex_unlock(m) \
MACRO_BEGIN \
mutex_set_holder(m, 0); \
if (spin_unlock(&(m)->held), \
cthread_queue_head(&(m)->queue, vm_offset_t) != 0) { \
mutex_unlock_solid(m); \
} \
MACRO_END
/*
* Condition variables.
*/
typedef struct condition {
spin_lock_t lock;
struct cthread_queue queue;
const char *name;
} *condition_t;
#define CONDITION_INITIALIZER { SPIN_LOCK_INITIALIZER, QUEUE_INITIALIZER, 0 }
#define CONDITION_NAMED_INITIALIZER(Name) { SPIN_LOCK_INITIALIZER, QUEUE_INITIALIZER, Name }
#define condition_alloc() \
((condition_t) calloc(1, sizeof(struct condition)))
#define condition_init(c) \
MACRO_BEGIN \
spin_lock_init(&(c)->lock); \
cthread_queue_init(&(c)->queue); \
MACRO_END
#define condition_set_name(c, x) ((c)->name = (x))
#define condition_name(c) ((c)->name != 0 ? (c)->name : "?")
#define condition_clear(c) \
MACRO_BEGIN \
condition_broadcast(c); \
spin_lock(&(c)->lock); \
MACRO_END
#define condition_free(c) \
MACRO_BEGIN \
condition_clear(c); \
free((c)); \
MACRO_END
#define condition_signal(c) \
MACRO_BEGIN \
if ((c)->queue.head) { \
cond_signal(c); \
} \
MACRO_END
#define condition_broadcast(c) \
MACRO_BEGIN \
if ((c)->queue.head) { \
cond_broadcast(c); \
} \
MACRO_END
extern void cond_signal(condition_t _cond);
extern void cond_broadcast(condition_t _cond);
extern void condition_wait(condition_t _cond, mutex_t _mutex);
/*
* Threads.
*/
typedef void * (*cthread_fn_t)(void *arg);
/* XXX We really should be using the setjmp.h that goes with the libc
* that we're planning on using, since that's where the setjmp()
* functions are going to be comming from.
*/
#include <mach/setjmp.h>
typedef struct cthread {
struct cthread *next;
struct mutex lock;
struct condition done;
int state;
jmp_buf catch_exit;
cthread_fn_t func;
void *arg;
void *result;
const char *name;
void *data;
void *ldata;
void *private_data;
struct ur_cthread *ur;
} *cthread_t;
#define NO_CTHREAD ((cthread_t) 0)
extern cthread_t cthread_fork(cthread_fn_t _func, void *_arg);
extern void cthread_detach(cthread_t _thread);
extern any_t cthread_join(cthread_t _thread);
extern void cthread_yield(void);
extern void cthread_exit(void *_result);
/*
* This structure must agree with struct cproc in cthread_internals.h
*/
typedef struct ur_cthread {
struct ur_cthread *next;
cthread_t incarnation;
} *ur_cthread_t;
#ifndef cthread_sp
extern vm_offset_t
cthread_sp(void);
#endif
extern vm_offset_t cthread_stack_mask;
#if defined(STACK_GROWTH_UP)
#define ur_cthread_ptr(sp) \
(* (ur_cthread_t *) ((sp) & cthread_stack_mask))
#else /* not defined(STACK_GROWTH_UP) */
#define ur_cthread_ptr(sp) \
(* (ur_cthread_t *) ( ((sp) | cthread_stack_mask) + 1 \
- sizeof(ur_cthread_t *)) )
#endif /* defined(STACK_GROWTH_UP) */
#define ur_cthread_self() (ur_cthread_ptr(cthread_sp()))
#define cthread_assoc(id, t) ((((ur_cthread_t) (id))->incarnation = (t)), \
((t) ? ((t)->ur = (ur_cthread_t)(id)) : 0))
#define cthread_self() (ur_cthread_self()->incarnation)
extern void cthread_set_name(cthread_t _thread, const char *_name);
extern const char * cthread_name(cthread_t _thread);
extern int cthread_count(void);
extern void cthread_set_limit(int _limit);
extern int cthread_limit(void);
extern void cthread_set_kernel_limit(int _n);
extern int cthread_kernel_limit(void);
extern void cthread_wire(void);
extern void cthread_unwire(void);
extern void cthread_msg_busy(mach_port_t _port, int _min, int _max);
extern void cthread_msg_active(mach_port_t _prt, int _min, int _max);
extern mach_msg_return_t cthread_mach_msg(mach_msg_header_t *_header,
mach_msg_option_t _option,
mach_msg_size_t _send_size,
mach_msg_size_t _rcv_size,
mach_port_t _rcv_name,
mach_msg_timeout_t _timeout,
mach_port_t _notify,
int _min, int _max);
extern void cthread_fork_prepare(void);
extern void cthread_fork_parent(void);
extern void cthread_fork_child(void);
#if defined(THREAD_CALLS)
/*
* Routines to replace thread_*.
*/
extern kern_return_t cthread_get_state(cthread_t _thread);
extern kern_return_t cthread_set_state(cthread_t _thread);
extern kern_return_t cthread_abort(cthread_t _thread);
extern kern_return_t cthread_resume(cthread_t _thread);
extern kern_return_t cthread_suspend(cthread_t _thread);
extern kern_return_t cthread_call_on(cthread_t _thread);
#endif /* defined(THREAD_CALLS) */
#if defined(CTHREAD_DATA_XX)
/*
* Set or get thread specific "global" variable
*
* The thread given must be the calling thread (ie. thread_self).
* XXX This is for compatibility with the old cthread_data. XXX
*/
extern int cthread_set_data(cthread_t _thread, void *_val);
extern void * cthread_data(cthread_t _thread);
#else /* defined(CTHREAD_DATA_XX) */
#define cthread_set_data(_thread, _val) ((_thread)->data) = (void *)(_val);
#define cthread_data(_thread) ((_thread)->data)
#define cthread_set_ldata(_thread, _val) ((_thread)->ldata) = (void *)(_val);
#define cthread_ldata(_thread) ((_thread)->ldata)
#endif /* defined(CTHREAD_DATA_XX) */
/*
* Support for POSIX thread specific data
*
* Multiplexes a thread specific "global" variable
* into many thread specific "global" variables.
*/
#define CTHREAD_DATA_VALUE_NULL (void *)0
#define CTHREAD_KEY_INVALID (cthread_key_t)-1
typedef int cthread_key_t;
/*
* Create key to private data visible to all threads in task.
* Different threads may use same key, but the values bound to the key are
* maintained on a thread specific basis.
*/
extern int cthread_keycreate(cthread_key_t *_key);
/*
* Get value currently bound to key for calling thread
*/
extern int cthread_getspecific(cthread_key_t _key, void **_value);
/*
* Bind value to given key for calling thread
*/
extern int cthread_setspecific(cthread_key_t _key, void *_value);
#endif /* not defined(_CTHREADS_) */
|