summaryrefslogtreecommitdiff
path: root/libthreads/cthreads.h
blob: d937dcca937641419764801f3aaeca33b8e3104b (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
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
/*
 * 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.
 */
/*
 * HISTORY
 * 20-Oct-93  Tero Kivinen (kivinen) at Helsinki University of Technology
 *	Renamed cthread_t->catch to to cthread_t->catch_exit, because
 *	catch is reserved word in c++.
 *
 * 12-Oct-93  Johannes Helander (jvh) at Helsinki University of Technology
 *	Added CONDITION_NAMED_INITIALIZER and MUTEX_NAMED_INITIALIZER1
 * 	macros. They take one argument: a name string.
 *
 * $Log: cthreads.h,v $
 * Revision 1.19  2002/05/28 23:55:58  roland
 * 2002-05-28  Roland McGrath  <roland@frob.com>
 *
 * 	* cthreads.h (hurd_condition_wait, condition_implies,
 * 	condition_unimplies): Restore decls lost in merge.
 * 	(mutex_clear): Define as mutex_init instead of bogon (lost in merge).
 *
 * Revision 1.18  2002/05/27 02:50:10  roland
 * 2002-05-26  Roland McGrath  <roland@frob.com>
 *
 * 	Changes merged from CMU MK83a version:
 * 	* cthreads.h, options.h: Various cleanups.
 * 	* call.c, cthread_data.c, sync.c, mig_support.c: Likewise.
 * 	* i386/cthreads.h, i386/thread.c, i386/lock.s: Likewise.
 * 	* cthread_internals.h: Add decls for internal functions.
 * 	(struct cproc): Use vm_offset_t for stack_base and stack_size members.
 * 	Use natural_t for context member.
 * 	* cprocs.c: Use prototypes for all defns.
 * 	* cthreads.c: Likewise.
 * 	(cthread_exit): Cast any_t to integer_t before int.
 *
 * Revision 2.17  93/05/10  19:43:11  rvb
 * 	Removed include of stdlib.h and just define malloc
 * 	[93/04/27            mrt]
 *
 * Revision 2.16  93/05/10  17:51:26  rvb
 * 	Just imagine how much more useful TWO special/fast lookup
 * 	variables could be.  (Actually, I am planning on using this
 * 	for bsdss -- for multiple threads per task.  If I don't, I'll
 * 	remove the feature.)
 * 	[93/05/10            rvb]
 * 	Big mistake here! CTHREAD_DATA must always be set TRUE.
 * 	cthreads.h is included by import_mach.h by lots of files
 * 	that are not compiled with -DCTHREAD_DATA.  This means
 * 	they see a different structure for cthread_t than the
 * 	cthread library -- which is compiled with CTHREAD_DATA.
 * 	Also, make cthread_set_data and cthread_data macros.
 * 	[93/05/06            rvb]
 * 	Flush stdlib
 * 	[93/05/05            rvb]
 *
 * Revision 2.15  93/01/27  09:03:32  danner
 * 	Updated include of mach/mach.h to mach.h
 *
 *
 * Revision 2.14  93/01/24  13:24:50  danner
 * 	Get MACRO_BEGIN, MACRO_END, NEVER, ... from sys/macro_help.h
 * 	why define it here.
 * 	[92/10/20            rvb]
 *
 * Revision 2.13  93/01/14  18:05:04  danner
 * 	Added MACRO_BEGIN and MACRO_END to definition of spin_lock.
 * 	Fixed return value of cthread_set_data.
 * 	Added prototypes for other miscellaneous functions.
 * 	[92/12/18            pds]
 * 	Converted file to ANSI C.
 * 	Added declarations of cthread_fork_{prepare,parent,child}.
 * 	Added include of <sys/macro_help.h>.
 * 	[92/12/13            pds]
 *
 * 	Replaced calloc declaration with an include of stdlib.h.
 * 	[92/06/15            pds]
 * 	64bit cleanup.
 * 	[92/12/02            af]
 *
 * Revision 2.12  92/05/22  18:38:36  jfriedl
 * 	From Mike Kupfer <kupfer@sprite.Berkeley.EDU>:
 * 	Add declaration for cthread_wire().
 * 	Merge in Jonathan Chew's changes for thread-local data.
 * 	Use MACRO_BEGIN and MACRO_END.
 *
 * Revision 1.8  91/03/25  14:14:49  jjc
 * 	For compatibility with cthread_data:
 * 		1) Added private_data field to cthread structure
 * 		   for use by POSIX thread specific data routines.
 * 		2) Conditionalized old data field used by cthread_data
 * 		   under CTHREAD_DATA for binary compatibility.
 * 		3) Changed macros, cthread_set_data and cthread_data,
 * 		   into routines which use the POSIX routines for
 * 		   source compatibility.
 * 		   Also, conditionalized under CTHREAD_DATA.
 * 	[91/03/18            jjc]
 * 	Added support for multiplexing the thread specific global
 * 	variable, cthread_data, using the POSIX threads interface
 * 	for thread private data.
 * 	[91/03/14            jjc]
 *
 * Revision 2.11  91/08/03  18:20:15  jsb
 * 	Removed the infamous line 122.
 * 	[91/08/01  22:40:24  jsb]
 *
 * Revision 2.10  91/07/31  18:35:42  dbg
 * 	Fix the standard-C conditional: it's __STDC__.
 *
 * 	Allow for macro-redefinition of cthread_sp, spin_try_lock,
 * 	spin_unlock (from machine/cthreads.h).
 * 	[91/07/30  17:34:28  dbg]
 *
 * Revision 2.9  91/05/14  17:56:42  mrt
 * 	Correcting copyright
 *
 * Revision 2.8  91/02/14  14:19:52  mrt
 * 	Added new Mach copyright
 * 	[91/02/13  12:41:15  mrt]
 *
 * Revision 2.7  90/11/05  14:37:12  rpd
 * 	Include machine/cthreads.h.  Added spin_lock_t.
 * 	[90/10/31            rwd]
 *
 * Revision 2.6  90/10/12  13:07:24  rpd
 * 	Channge to allow for positive stack growth.
 * 	[90/10/10            rwd]
 *
 * Revision 2.5  90/09/09  14:34:56  rpd
 * 	Remove mutex_special and debug_mutex.
 * 	[90/08/24            rwd]
 *
 * Revision 2.4  90/08/07  14:31:14  rpd
 * 	Removed RCS keyword nonsense.
 *
 * Revision 2.3  90/01/19  14:37:18  rwd
 * 	Add back pointer to cthread structure.
 * 	[90/01/03            rwd]
 * 	Change definition of cthread_init and change ur_cthread_self macro
 * 	to reflect movement of self pointer on stack.
 * 	[89/12/18  19:18:34  rwd]
 *
 * Revision 2.2  89/12/08  19:53:49  rwd
 * 	Change spin_try_lock to int.
 * 	[89/11/30            rwd]
 * 	Changed mutex macros to deal with special mutexs
 * 	[89/11/26            rwd]
 * 	Make mutex_{set,clear}_special routines instead of macros.
 * 	[89/11/25            rwd]
 * 	Added mutex_special to specify a need to context switch on this
 * 	mutex.
 * 	[89/11/21            rwd]
 *
 * 	Made mutex_lock a macro trying to grab the spin_lock first.
 * 	[89/11/13            rwd]
 * 	Removed conditionals.  Mutexes are more like conditions now.
 * 	Changed for limited kernel thread version.
 * 	[89/10/23            rwd]
 *
 * Revision 2.1  89/08/03  17:09:40  rwd
 * Created.
 *
 *
 * 28-Oct-88  Eric Cooper (ecc) at Carnegie Mellon University
 *	Implemented spin_lock() as test and test-and-set logic
 *	(using mutex_try_lock()) in sync.c.  Changed ((char *) 0)
 *	to 0, at Mike Jones's suggestion, and turned on ANSI-style
 *	declarations in either C++ or _STDC_.
 *
 * 29-Sep-88  Eric Cooper (ecc) at Carnegie Mellon University
 *	Changed NULL to ((char *) 0) to avoid dependency on <stdio.h>,
 *	at Alessandro Forin's suggestion.
 *
 * 08-Sep-88  Alessandro Forin (af) at Carnegie Mellon University
 *	Changed queue_t to cthread_queue_t and string_t to char *
 *	to avoid conflicts.
 *
 * 01-Apr-88  Eric Cooper (ecc) at Carnegie Mellon University
 *	Changed compound statement macros to use the
 *	do { ... } while (0) trick, so that they work
 *	in all statement contexts.
 *
 * 19-Feb-88  Eric Cooper (ecc) at Carnegie Mellon University
 *	Made spin_unlock() and mutex_unlock() into procedure calls
 *	rather than macros, so that even smart compilers can't reorder
 *	the clearing of the lock.  Suggested by Jeff Eppinger.
 *	Removed the now empty <machine>/cthreads.h.
 *
 * 01-Dec-87  Eric Cooper (ecc) at Carnegie Mellon University
 *	Changed cthread_self() to mask the current SP to find
 *	the self pointer stored at the base of the stack.
 *
 * 22-Jul-87  Eric Cooper (ecc) at Carnegie Mellon University
 *	Fixed bugs in mutex_set_name and condition_set_name
 *	due to bad choice of macro formal parameter name.
 *
 * 21-Jul-87  Eric Cooper (ecc) at Carnegie Mellon University
 *	Moved #include <machine/cthreads.h> to avoid referring
 *	to types before they are declared (required by C++).
 *
 *  9-Jul-87  Michael Jones (mbj) at Carnegie Mellon University
 *	Added conditional type declarations for C++.
 *	Added _cthread_init_routine and _cthread_exit_routine variables
 *	for automatic initialization and finalization by crt0.
 */
/*
 * 	File: 	cthreads.h
 *	Author: Eric Cooper, Carnegie Mellon University
 *	Date:	Jul, 1987
 *
 * 	Definitions for the C Threads package.
 *
 */


#ifndef	_CTHREADS_
#define	_CTHREADS_ 1

#if 0
/* This is CMU's machine-dependent file.  In GNU all of the machine
   dependencies are dealt with in libc.  */
#include <machine/cthreads.h>
#include <mach.h>
#include <sys/macro_help.h>
#include <mach/machine/vm_param.h>

#ifdef __STDC__
extern void *malloc();
#else
extern char *malloc();
#endif

#else  /* GNU */
# include <stdlib.h>
# include <mach.h>
# include <mach/machine/vm_param.h>
# include <machine-sp.h>
# define cthread_sp()	((vm_address_t) __thread_stack_pointer ())
# define MACRO_BEGIN	__extension__ ({
# define MACRO_END	0; })
#endif

typedef void *any_t;	    /* XXX - obsolete, should be deleted. */

#if	defined(TRUE)
#else	/* not defined(TRUE) */
#define	TRUE	1
#define	FALSE	0
#endif

/* Enable mutex holder debugging */
/* #define WAIT_DEBUG */
/* Record function name instead of thread pointer */
/* #define WAIT_FUNC_DEBUG */

/*
 * 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

#if 1

/* In GNU, spin locks are implemented in libc.
   Just include its header file.  */
#include <spin-lock.h>

#else  /* Unused CMU code.  */

/*
 * 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

#endif /* End unused CMU code.  */

/*
 * Mutex objects.
 */
typedef struct mutex {
  /* The `held' member must be first in GNU.  The GNU C library relies on
     being able to cast a `struct mutex *' to a `spin_lock_t *' (which is
     kosher if it is the first member) and spin_try_lock that address to
     see if it gets the mutex.  */
	spin_lock_t held;
	spin_lock_t lock;
	const char *name;
	struct cthread_queue queue;
	/* holder is for WAIT_DEBUG. Not ifdeffed to keep size constant. */
#ifdef WAIT_FUNC_DEBUG
	const char *fname;
#else /* WAIT_FUNC_DEBUG */
	struct cthread *holder;
#endif /* WAIT_FUNC_DEBUG */
} *mutex_t;

#ifdef WAIT_DEBUG
#ifdef WAIT_FUNC_DEBUG
#define WAIT_CLEAR_DEBUG(m)	(m)->fname = 0
#define WAIT_SET_DEBUG(m)	(m)->fname = __FUNCTION__
#else /* WAIT_FUNC_DEBUG */
#define WAIT_CLEAR_DEBUG(m)	(m)->holder = 0
#define WAIT_SET_DEBUG(m)	(m)->holder = cthread_self()
#endif /* WAIT_FUNC_DEBUG */
#else /* WAIT_DEBUG */
#define WAIT_CLEAR_DEBUG(m)	(void) 0
#define WAIT_SET_DEBUG(m)	(void) 0
#endif /* WAIT_DEBUG */

/* Rearranged accordingly for GNU: */
#define	MUTEX_INITIALIZER	{ SPIN_LOCK_INITIALIZER, SPIN_LOCK_INITIALIZER, 0, QUEUE_INITIALIZER, }
#define	MUTEX_NAMED_INITIALIZER(Name) { SPIN_LOCK_INITIALIZER, SPIN_LOCK_INITIALIZER, Name, QUEUE_INITIALIZER, }

#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); \
	WAIT_CLEAR_DEBUG(m); \
	MACRO_END
#define	mutex_set_name(m, x)	((m)->name = (x))
#define	mutex_name(m)		((m)->name != 0 ? (m)->name : "?")
#define	mutex_clear(m)		mutex_init(m)
#define	mutex_free(m)		free((m))

#define mutex_try_lock(m) (spin_try_lock(&(m)->held) ? WAIT_SET_DEBUG(m), 1 : 0)
#define mutex_lock(m) \
	MACRO_BEGIN \
	if (!spin_try_lock(&(m)->held)) { \
		__mutex_lock_solid(m); \
	} \
	WAIT_SET_DEBUG(m); \
	MACRO_END
#define mutex_unlock(m) \
	MACRO_BEGIN \
	if (spin_unlock(&(m)->held), \
	    cthread_queue_head(&(m)->queue, vm_offset_t) != 0) { \
		__mutex_unlock_solid(m); \
	} \
	WAIT_CLEAR_DEBUG(m); \
	MACRO_END
/*
 * Condition variables.
 */
typedef struct condition {
	spin_lock_t lock;
	struct cthread_queue queue;
	const char *name;
	struct cond_imp *implications;
} *condition_t;

struct cond_imp
{
  struct condition *implicatand;
  struct cond_imp *next;
};

#define	CONDITION_INITIALIZER		{ SPIN_LOCK_INITIALIZER, QUEUE_INITIALIZER, 0, 0 }
#define	CONDITION_NAMED_INITIALIZER(Name)		{ SPIN_LOCK_INITIALIZER, QUEUE_INITIALIZER, Name, 0 }

#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); \
	(c)->name = 0; \
	(c)->implications = 0; \
	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 || (c)->implications) { \
		cond_signal(c); \
	} \
	MACRO_END

#define	condition_broadcast(c) \
	MACRO_BEGIN \
	if ((c)->queue.head || (c)->implications) { \
		cond_broadcast(c); \
	} \
	MACRO_END

extern int	cond_signal(condition_t _cond);

extern void	cond_broadcast(condition_t _cond);

extern void	condition_wait(condition_t _cond, mutex_t _mutex);
extern int	hurd_condition_wait(condition_t _cond, mutex_t _mutex);

extern void	condition_implies(condition_t _implicator,
				  condition_t _implicatand);
extern void	condition_unimplies(condition_t _implicator,
				    condition_t _implicatand);

/*
 * Threads.
 */

typedef void *	(*cthread_fn_t)(void *arg);

#include <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);

/*
 * Debugging support.
 */
#if	defined(DEBUG)

#if	defined(ASSERT)
#else	/* not defined(ASSERT) */
/*
 * Assertion macro, similar to <assert.h>
 */
#include <stdio.h>
#define	ASSERT(p) \
	MACRO_BEGIN \
	if (!(p)) { \
		fprintf(stderr, \
			"File %s, line %d: assertion p failed.\n", \
			__FILE__, __LINE__); \
		abort(); \
	} \
	MACRO_END

#endif	/* defined(ASSERT) */

#define	SHOULDNT_HAPPEN	0

extern int cthread_debug;

#else	/* not defined(DEBUG) */

#if	defined(ASSERT)
#else	/* not defined(ASSERT) */
#define	ASSERT(p)
#endif	/* defined(ASSERT) */

#endif	/* defined(DEBUG) */

#endif	/* not defined(_CTHREADS_) */