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
|
/*
* 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 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
#define WAIT_DEBUG /* XXX should be defined somewhere else */
#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
/*
* 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. */
struct cthread *holder;
} *mutex_t;
/* 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); \
(m)->holder = 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))
#define mutex_try_lock(m) spin_try_lock(&(m)->held)
#if defined(WAIT_DEBUG)
#define mutex_lock(m) \
MACRO_BEGIN \
if (!spin_try_lock(&(m)->held)) { \
__mutex_lock_solid(m); \
} \
(m)->holder = cthread_self(); \
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); \
} \
(m)->holder = 0; \
MACRO_END
#else /* defined(WAIT_DEBUG */
#define mutex_lock(m) \
MACRO_BEGIN \
if (!spin_try_lock(&(m)->held)) { \
__mutex_lock_solid(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); \
} \
MACRO_END
#endif /* defined(WAIT_DEBUG) */
/*
* 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);
/*
* 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_) */
|