summaryrefslogtreecommitdiff
path: root/include/mach/cthreads.h
blob: d44fa200bfbc78bf5e70a984b32ac1710e2b7223 (plain)
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_) */