aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorTom Tromey2012-08-19 03:23:03 -0600
committerTom Tromey2012-08-19 03:23:03 -0600
commit5651640d578fa2efa40be4789d9fa61813ccb1fa (patch)
treea59e33464016e88cb3f0501d6c47baf8aa5e07aa /src
parentee1464eab19311ab7708b135bdb6eb989909e4cc (diff)
downloademacs-5651640d578fa2efa40be4789d9fa61813ccb1fa.tar.gz
emacs-5651640d578fa2efa40be4789d9fa61813ccb1fa.zip
condition variables
This implements condition variables for elisp. This needs more tests.
Diffstat (limited to 'src')
-rw-r--r--src/alloc.c2
-rw-r--r--src/data.c17
-rw-r--r--src/lisp.h9
-rw-r--r--src/print.c12
-rw-r--r--src/thread.c219
-rw-r--r--src/thread.h16
6 files changed, 255 insertions, 20 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 80d22d61d66..19b77d567d0 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -3106,6 +3106,8 @@ sweep_vectors (void)
3106 finalize_one_thread ((struct thread_state *) vector); 3106 finalize_one_thread ((struct thread_state *) vector);
3107 else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_MUTEX)) 3107 else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_MUTEX))
3108 finalize_one_mutex ((struct Lisp_Mutex *) vector); 3108 finalize_one_mutex ((struct Lisp_Mutex *) vector);
3109 else if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_CONDVAR))
3110 finalize_one_condvar ((struct Lisp_CondVar *) vector);
3109 3111
3110 next = ADVANCE (vector, nbytes); 3112 next = ADVANCE (vector, nbytes);
3111 3113
diff --git a/src/data.c b/src/data.c
index b47c2d12aff..e6342caadf1 100644
--- a/src/data.c
+++ b/src/data.c
@@ -94,7 +94,7 @@ static Lisp_Object Qchar_table, Qbool_vector, Qhash_table;
94static Lisp_Object Qsubrp, Qmany, Qunevalled; 94static Lisp_Object Qsubrp, Qmany, Qunevalled;
95Lisp_Object Qfont_spec, Qfont_entity, Qfont_object; 95Lisp_Object Qfont_spec, Qfont_entity, Qfont_object;
96static Lisp_Object Qdefun; 96static Lisp_Object Qdefun;
97Lisp_Object Qthread, Qmutex; 97Lisp_Object Qthread, Qmutex, Qcondition_variable;
98 98
99Lisp_Object Qinteractive_form; 99Lisp_Object Qinteractive_form;
100 100
@@ -216,6 +216,8 @@ for example, (type-of 1) returns `integer'. */)
216 return Qthread; 216 return Qthread;
217 if (MUTEXP (object)) 217 if (MUTEXP (object))
218 return Qmutex; 218 return Qmutex;
219 if (CONDVARP (object))
220 return Qcondition_variable;
219 return Qvector; 221 return Qvector;
220 222
221 case Lisp_Float: 223 case Lisp_Float:
@@ -482,6 +484,17 @@ DEFUN ("mutexp", Fmutexp, Smutexp, 1, 1, 0,
482 else 484 else
483 return Qnil; 485 return Qnil;
484} 486}
487
488DEFUN ("condition-variablep", Fcondition_variablep, Scondition_variablep,
489 1, 1, 0,
490 doc: /* Return t if OBJECT is a condition variable. */)
491 (Lisp_Object object)
492{
493 if (CONDVARP (object))
494 return Qt;
495 else
496 return Qnil;
497}
485 498
486/* Extract and set components of lists */ 499/* Extract and set components of lists */
487 500
@@ -3117,6 +3130,7 @@ syms_of_data (void)
3117 DEFSYM (Qhash_table, "hash-table"); 3130 DEFSYM (Qhash_table, "hash-table");
3118 DEFSYM (Qthread, "thread"); 3131 DEFSYM (Qthread, "thread");
3119 DEFSYM (Qmutex, "mutex"); 3132 DEFSYM (Qmutex, "mutex");
3133 DEFSYM (Qcondition_variable, "condition-variable");
3120 /* Used by Fgarbage_collect. */ 3134 /* Used by Fgarbage_collect. */
3121 DEFSYM (Qinterval, "interval"); 3135 DEFSYM (Qinterval, "interval");
3122 DEFSYM (Qmisc, "misc"); 3136 DEFSYM (Qmisc, "misc");
@@ -3161,6 +3175,7 @@ syms_of_data (void)
3161 defsubr (&Schar_or_string_p); 3175 defsubr (&Schar_or_string_p);
3162 defsubr (&Sthreadp); 3176 defsubr (&Sthreadp);
3163 defsubr (&Smutexp); 3177 defsubr (&Smutexp);
3178 defsubr (&Scondition_variablep);
3164 defsubr (&Scar); 3179 defsubr (&Scar);
3165 defsubr (&Scdr); 3180 defsubr (&Scdr);
3166 defsubr (&Scar_safe); 3181 defsubr (&Scar_safe);
diff --git a/src/lisp.h b/src/lisp.h
index 34ecfe697d6..2a75dfcbc7d 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -367,6 +367,7 @@ enum pvec_type
367 PVEC_OTHER, 367 PVEC_OTHER,
368 PVEC_THREAD, 368 PVEC_THREAD,
369 PVEC_MUTEX, 369 PVEC_MUTEX,
370 PVEC_CONDVAR,
370 /* These last 4 are special because we OR them in fns.c:internal_equal, 371 /* These last 4 are special because we OR them in fns.c:internal_equal,
371 so they have to use a disjoint bit pattern: 372 so they have to use a disjoint bit pattern:
372 if (!(size & (PVEC_COMPILED | PVEC_CHAR_TABLE 373 if (!(size & (PVEC_COMPILED | PVEC_CHAR_TABLE
@@ -557,6 +558,7 @@ clip_to_bounds (ptrdiff_t lower, EMACS_INT num, ptrdiff_t upper)
557 XUNTAG (a, Lisp_Vectorlike))) 558 XUNTAG (a, Lisp_Vectorlike)))
558#define XTHREAD(a) (eassert (THREADP (a)), (struct thread_state *) XPNTR(a)) 559#define XTHREAD(a) (eassert (THREADP (a)), (struct thread_state *) XPNTR(a))
559#define XMUTEX(a) (eassert (MUTEXP (a)), (struct Lisp_Mutex *) XPNTR(a)) 560#define XMUTEX(a) (eassert (MUTEXP (a)), (struct Lisp_Mutex *) XPNTR(a))
561#define XCONDVAR(a) (eassert (CONDVARP (a)), (struct Lisp_CondVar *) XPNTR(a))
560 562
561/* Construct a Lisp_Object from a value or address. */ 563/* Construct a Lisp_Object from a value or address. */
562 564
@@ -609,6 +611,7 @@ clip_to_bounds (ptrdiff_t lower, EMACS_INT num, ptrdiff_t upper)
609#define XSETSUB_CHAR_TABLE(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_SUB_CHAR_TABLE)) 611#define XSETSUB_CHAR_TABLE(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_SUB_CHAR_TABLE))
610#define XSETTHREAD(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_THREAD)) 612#define XSETTHREAD(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_THREAD))
611#define XSETMUTEX(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_MUTEX)) 613#define XSETMUTEX(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_MUTEX))
614#define XSETCONDVAR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_CONDVAR))
612 615
613/* Convenience macros for dealing with Lisp arrays. */ 616/* Convenience macros for dealing with Lisp arrays. */
614 617
@@ -1709,6 +1712,7 @@ typedef struct {
1709#define FRAMEP(x) PSEUDOVECTORP (x, PVEC_FRAME) 1712#define FRAMEP(x) PSEUDOVECTORP (x, PVEC_FRAME)
1710#define THREADP(x) PSEUDOVECTORP (x, PVEC_THREAD) 1713#define THREADP(x) PSEUDOVECTORP (x, PVEC_THREAD)
1711#define MUTEXP(x) PSEUDOVECTORP (x, PVEC_MUTEX) 1714#define MUTEXP(x) PSEUDOVECTORP (x, PVEC_MUTEX)
1715#define CONDVARP(x) PSEUDOVECTORP (x, PVEC_CONDVAR)
1712 1716
1713/* Test for image (image . spec) */ 1717/* Test for image (image . spec) */
1714#define IMAGEP(x) (CONSP (x) && EQ (XCAR (x), Qimage)) 1718#define IMAGEP(x) (CONSP (x) && EQ (XCAR (x), Qimage))
@@ -1833,6 +1837,9 @@ typedef struct {
1833#define CHECK_MUTEX(x) \ 1837#define CHECK_MUTEX(x) \
1834 CHECK_TYPE (MUTEXP (x), Qmutexp, x) 1838 CHECK_TYPE (MUTEXP (x), Qmutexp, x)
1835 1839
1840#define CHECK_CONDVAR(x) \
1841 CHECK_TYPE (CONDVARP (x), Qcondition_variablep, x)
1842
1836/* Since we can't assign directly to the CAR or CDR fields of a cons 1843/* Since we can't assign directly to the CAR or CDR fields of a cons
1837 cell, use these when checking that those fields contain numbers. */ 1844 cell, use these when checking that those fields contain numbers. */
1838#define CHECK_NUMBER_CAR(x) \ 1845#define CHECK_NUMBER_CAR(x) \
@@ -2455,7 +2462,7 @@ extern Lisp_Object Qchar_or_string_p, Qmarkerp, Qinteger_or_marker_p, Qvectorp;
2455extern Lisp_Object Qbuffer_or_string_p; 2462extern Lisp_Object Qbuffer_or_string_p;
2456extern Lisp_Object Qfboundp; 2463extern Lisp_Object Qfboundp;
2457extern Lisp_Object Qchar_table_p, Qvector_or_char_table_p; 2464extern Lisp_Object Qchar_table_p, Qvector_or_char_table_p;
2458extern Lisp_Object Qthreadp, Qmutexp; 2465extern Lisp_Object Qthreadp, Qmutexp, Qcondition_variablep;
2459 2466
2460extern Lisp_Object Qcdr; 2467extern Lisp_Object Qcdr;
2461 2468
diff --git a/src/print.c b/src/print.c
index b14a769dc74..78a0707627c 100644
--- a/src/print.c
+++ b/src/print.c
@@ -1967,6 +1967,18 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag
1967 } 1967 }
1968 PRINTCHAR ('>'); 1968 PRINTCHAR ('>');
1969 } 1969 }
1970 else if (CONDVARP (obj))
1971 {
1972 strout ("#<condvar ", -1, -1, printcharfun);
1973 if (STRINGP (XCONDVAR (obj)->name))
1974 print_string (XCONDVAR (obj)->name, printcharfun);
1975 else
1976 {
1977 int len = sprintf (buf, "%p", XCONDVAR (obj));
1978 strout (buf, len, len, printcharfun);
1979 }
1980 PRINTCHAR ('>');
1981 }
1970 else 1982 else
1971 { 1983 {
1972 ptrdiff_t size = ASIZE (obj); 1984 ptrdiff_t size = ASIZE (obj);
diff --git a/src/thread.c b/src/thread.c
index 9c39b84eb50..4657d6a797e 100644
--- a/src/thread.c
+++ b/src/thread.c
@@ -32,7 +32,7 @@ static struct thread_state *all_threads = &primary_thread;
32 32
33static sys_mutex_t global_lock; 33static sys_mutex_t global_lock;
34 34
35Lisp_Object Qthreadp, Qmutexp; 35Lisp_Object Qthreadp, Qmutexp, Qcondition_variablep;
36 36
37 37
38 38
@@ -89,36 +89,41 @@ lisp_mutex_init (lisp_mutex_t *mutex)
89 sys_cond_init (&mutex->condition); 89 sys_cond_init (&mutex->condition);
90} 90}
91 91
92static void 92static int
93lisp_mutex_lock (lisp_mutex_t *mutex) 93lisp_mutex_lock (lisp_mutex_t *mutex, int new_count)
94{ 94{
95 struct thread_state *self; 95 struct thread_state *self;
96 96
97 if (mutex->owner == NULL) 97 if (mutex->owner == NULL)
98 { 98 {
99 mutex->owner = current_thread; 99 mutex->owner = current_thread;
100 mutex->count = 1; 100 mutex->count = new_count == 0 ? 1 : new_count;
101 return; 101 return 0;
102 } 102 }
103 if (mutex->owner == current_thread) 103 if (mutex->owner == current_thread)
104 { 104 {
105 eassert (new_count == 0);
105 ++mutex->count; 106 ++mutex->count;
106 return; 107 return 0;
107 } 108 }
108 109
109 self = current_thread; 110 self = current_thread;
110 self->wait_condvar = &mutex->condition; 111 self->wait_condvar = &mutex->condition;
111 while (mutex->owner != NULL && EQ (self->error_symbol, Qnil)) 112 while (mutex->owner != NULL && (new_count != 0
113 || EQ (self->error_symbol, Qnil)))
112 sys_cond_wait (&mutex->condition, &global_lock); 114 sys_cond_wait (&mutex->condition, &global_lock);
113 self->wait_condvar = NULL; 115 self->wait_condvar = NULL;
114 116
115 post_acquire_global_lock (self); 117 if (new_count == 0 && !NILP (self->error_symbol))
118 return 1;
116 119
117 mutex->owner = self; 120 mutex->owner = self;
118 mutex->count = 1; 121 mutex->count = new_count == 0 ? 1 : new_count;
122
123 return 1;
119} 124}
120 125
121static void 126static int
122lisp_mutex_unlock (lisp_mutex_t *mutex) 127lisp_mutex_unlock (lisp_mutex_t *mutex)
123{ 128{
124 struct thread_state *self = current_thread; 129 struct thread_state *self = current_thread;
@@ -127,12 +132,28 @@ lisp_mutex_unlock (lisp_mutex_t *mutex)
127 error ("blah"); 132 error ("blah");
128 133
129 if (--mutex->count > 0) 134 if (--mutex->count > 0)
130 return; 135 return 0;
131 136
132 mutex->owner = NULL; 137 mutex->owner = NULL;
133 sys_cond_broadcast (&mutex->condition); 138 sys_cond_broadcast (&mutex->condition);
134 139
135 post_acquire_global_lock (self); 140 return 1;
141}
142
143static unsigned int
144lisp_mutex_unlock_for_wait (lisp_mutex_t *mutex)
145{
146 struct thread_state *self = current_thread;
147 unsigned int result = mutex->count;
148
149 /* Ensured by condvar code. */
150 eassert (mutex->owner == current_thread);
151
152 mutex->count = 0;
153 mutex->owner = NULL;
154 sys_cond_broadcast (&mutex->condition);
155
156 return result;
136} 157}
137 158
138static void 159static void
@@ -141,6 +162,12 @@ lisp_mutex_destroy (lisp_mutex_t *mutex)
141 sys_cond_destroy (&mutex->condition); 162 sys_cond_destroy (&mutex->condition);
142} 163}
143 164
165static int
166lisp_mutex_owned_p (lisp_mutex_t *mutex)
167{
168 return mutex->owner == current_thread;
169}
170
144 171
145 172
146DEFUN ("make-mutex", Fmake_mutex, Smake_mutex, 0, 1, 0, 173DEFUN ("make-mutex", Fmake_mutex, Smake_mutex, 0, 1, 0,
@@ -173,9 +200,10 @@ static void
173mutex_lock_callback (void *arg) 200mutex_lock_callback (void *arg)
174{ 201{
175 struct Lisp_Mutex *mutex = arg; 202 struct Lisp_Mutex *mutex = arg;
203 struct thread_state *self = current_thread;
176 204
177 /* This calls post_acquire_global_lock. */ 205 if (lisp_mutex_lock (&mutex->mutex, 0))
178 lisp_mutex_lock (&mutex->mutex); 206 post_acquire_global_lock (self);
179} 207}
180 208
181static Lisp_Object 209static Lisp_Object
@@ -211,9 +239,10 @@ static void
211mutex_unlock_callback (void *arg) 239mutex_unlock_callback (void *arg)
212{ 240{
213 struct Lisp_Mutex *mutex = arg; 241 struct Lisp_Mutex *mutex = arg;
242 struct thread_state *self = current_thread;
214 243
215 /* This calls post_acquire_global_lock. */ 244 if (lisp_mutex_unlock (&mutex->mutex))
216 lisp_mutex_unlock (&mutex->mutex); 245 post_acquire_global_lock (self);
217} 246}
218 247
219DEFUN ("mutex-unlock", Fmutex_unlock, Smutex_unlock, 1, 1, 0, 248DEFUN ("mutex-unlock", Fmutex_unlock, Smutex_unlock, 1, 1, 0,
@@ -253,6 +282,154 @@ finalize_one_mutex (struct Lisp_Mutex *mutex)
253 282
254 283
255 284
285DEFUN ("make-condition-variable",
286 Fmake_condition_variable, Smake_condition_variable,
287 1, 2, 0,
288 doc: /* Make a condition variable.
289A condition variable provides a way for a thread to sleep while
290waiting for a state change.
291
292MUTEX is the mutex associated with this condition variable.
293NAME, if given, is the name of this condition variable. The name is
294informational only. */)
295 (Lisp_Object mutex, Lisp_Object name)
296{
297 struct Lisp_CondVar *condvar;
298 Lisp_Object result;
299
300 CHECK_MUTEX (mutex);
301 if (!NILP (name))
302 CHECK_STRING (name);
303
304 condvar = ALLOCATE_PSEUDOVECTOR (struct Lisp_CondVar, cond, PVEC_CONDVAR);
305 memset ((char *) condvar + offsetof (struct Lisp_CondVar, cond),
306 0, sizeof (struct Lisp_CondVar) - offsetof (struct Lisp_CondVar,
307 cond));
308 condvar->mutex = mutex;
309 condvar->name = name;
310 sys_cond_init (&condvar->cond);
311
312 XSETCONDVAR (result, condvar);
313 return result;
314}
315
316static void
317condition_wait_callback (void *arg)
318{
319 struct Lisp_CondVar *cvar = arg;
320 struct Lisp_Mutex *mutex = XMUTEX (cvar->mutex);
321 struct thread_state *self = current_thread;
322 unsigned int saved_count;
323 Lisp_Object cond;
324
325 XSETCONDVAR (cond, cvar);
326 current_thread->event_object = cond;
327 saved_count = lisp_mutex_unlock_for_wait (&mutex->mutex);
328 /* If we were signalled while unlocking, we skip the wait, but we
329 still must reacquire our lock. */
330 if (NILP (self->error_symbol))
331 {
332 self->wait_condvar = &cvar->cond;
333 sys_cond_wait (&cvar->cond, &global_lock);
334 self->wait_condvar = NULL;
335 }
336 lisp_mutex_lock (&mutex->mutex, saved_count);
337 current_thread->event_object = Qnil;
338 post_acquire_global_lock (self);
339}
340
341DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0,
342 doc: /* Wait for the condition variable to be notified.
343CONDITION is the condition variable to wait on.
344
345The mutex associated with CONDITION must be held when this is called.
346It is an error if it is not held.
347
348This atomically releases the mutex and waits for CONDITION to be
349notified. When `condition-wait' returns, the mutex will again be
350locked by this thread. */)
351 (Lisp_Object condition)
352{
353 struct Lisp_CondVar *cvar;
354 struct Lisp_Mutex *mutex;
355
356 CHECK_CONDVAR (condition);
357 cvar = XCONDVAR (condition);
358
359 mutex = XMUTEX (cvar->mutex);
360 if (!lisp_mutex_owned_p (&mutex->mutex))
361 error ("fixme");
362
363 flush_stack_call_func (condition_wait_callback, cvar);
364
365 return Qnil;
366}
367
368/* Used to communicate argumnets to condition_notify_callback. */
369struct notify_args
370{
371 struct Lisp_CondVar *cvar;
372 int all;
373};
374
375static void
376condition_notify_callback (void *arg)
377{
378 struct notify_args *na = arg;
379 struct Lisp_Mutex *mutex = XMUTEX (na->cvar->mutex);
380 struct thread_state *self = current_thread;
381 unsigned int saved_count;
382 Lisp_Object cond;
383
384 XSETCONDVAR (cond, na->cvar);
385 saved_count = lisp_mutex_unlock_for_wait (&mutex->mutex);
386 if (na->all)
387 sys_cond_broadcast (&na->cvar->cond);
388 else
389 sys_cond_signal (&na->cvar->cond);
390 lisp_mutex_lock (&mutex->mutex, saved_count);
391 post_acquire_global_lock (self);
392}
393
394DEFUN ("condition-notify", Fcondition_notify, Scondition_notify, 1, 2, 0,
395 doc: /* Notify a condition variable.
396This wakes a thread waiting on CONDITION.
397If ALL is non-nil, all waiting threads are awoken.
398
399The mutex associated with CONDITION must be held when this is called.
400It is an error if it is not held.
401
402This atomically releases the mutex when notifying CONDITION. When
403`condition-notify' returns, the mutex will again be locked by this
404thread. */)
405 (Lisp_Object condition, Lisp_Object all)
406{
407 struct Lisp_CondVar *cvar;
408 struct Lisp_Mutex *mutex;
409 struct notify_args args;
410
411 CHECK_CONDVAR (condition);
412 cvar = XCONDVAR (condition);
413
414 mutex = XMUTEX (cvar->mutex);
415 if (!lisp_mutex_owned_p (&mutex->mutex))
416 error ("fixme");
417
418 args.cvar = cvar;
419 args.all = !NILP (all);
420 flush_stack_call_func (condition_notify_callback, &args);
421
422 return Qnil;
423}
424
425void
426finalize_one_condvar (struct Lisp_CondVar *condvar)
427{
428 sys_cond_destroy (&condvar->cond);
429}
430
431
432
256struct select_args 433struct select_args
257{ 434{
258 select_func *func; 435 select_func *func;
@@ -555,8 +732,8 @@ DEFUN ("thread-signal", Fthread_signal, Sthread_signal, 3, 3, 0,
555 doc: /* Signal an error in a thread. 732 doc: /* Signal an error in a thread.
556This acts like `signal', but arranges for the signal to be raised 733This acts like `signal', but arranges for the signal to be raised
557in THREAD. If THREAD is the current thread, acts just like `signal'. 734in THREAD. If THREAD is the current thread, acts just like `signal'.
558This will interrupt a blocked call to `mutex-lock' or`thread-join' in 735This will interrupt a blocked call to `mutex-lock', `condition-wait',
559the target thread. */) 736or `thread-join' in the target thread. */)
560 (Lisp_Object thread, Lisp_Object error_symbol, Lisp_Object data) 737 (Lisp_Object thread, Lisp_Object error_symbol, Lisp_Object data)
561{ 738{
562 struct thread_state *tstate; 739 struct thread_state *tstate;
@@ -597,6 +774,7 @@ DEFUN ("thread-blocker", Fthread_blocker, Sthread_blocker, 1, 1, 0,
597If THREAD is blocked in `thread-join' on a second thread, return that 774If THREAD is blocked in `thread-join' on a second thread, return that
598thread. 775thread.
599If THREAD is blocked in `mutex-lock', return the mutex. 776If THREAD is blocked in `mutex-lock', return the mutex.
777If THREAD is blocked in `condition-wait', return the condition variable.
600Otherwise, if THREAD is not blocked, return nil. */) 778Otherwise, if THREAD is not blocked, return nil. */)
601 (Lisp_Object thread) 779 (Lisp_Object thread)
602{ 780{
@@ -711,9 +889,14 @@ syms_of_threads (void)
711 defsubr (&Smutex_lock); 889 defsubr (&Smutex_lock);
712 defsubr (&Smutex_unlock); 890 defsubr (&Smutex_unlock);
713 defsubr (&Smutex_name); 891 defsubr (&Smutex_name);
892 defsubr (&Smake_condition_variable);
893 defsubr (&Scondition_wait);
894 defsubr (&Scondition_notify);
714 895
715 Qthreadp = intern_c_string ("threadp"); 896 Qthreadp = intern_c_string ("threadp");
716 staticpro (&Qthreadp); 897 staticpro (&Qthreadp);
717 Qmutexp = intern_c_string ("mutexp"); 898 Qmutexp = intern_c_string ("mutexp");
718 staticpro (&Qmutexp); 899 staticpro (&Qmutexp);
900 Qcondition_variablep = intern_c_string ("condition-variablep");
901 staticpro (&Qcondition_variablep);
719} 902}
diff --git a/src/thread.h b/src/thread.h
index 6b66ea4d1c3..989acec6afb 100644
--- a/src/thread.h
+++ b/src/thread.h
@@ -215,11 +215,27 @@ struct Lisp_Mutex
215 lisp_mutex_t mutex; 215 lisp_mutex_t mutex;
216}; 216};
217 217
218/* A condition variable as a lisp object. */
219struct Lisp_CondVar
220{
221 struct vectorlike_header header;
222
223 /* The associated mutex. */
224 Lisp_Object mutex;
225
226 /* The name of the condition variable, or nil. */
227 Lisp_Object name;
228
229 /* The lower-level condition variable object. */
230 sys_cond_t cond;
231};
232
218extern struct thread_state *current_thread; 233extern struct thread_state *current_thread;
219 234
220extern void unmark_threads (void); 235extern void unmark_threads (void);
221extern void finalize_one_thread (struct thread_state *state); 236extern void finalize_one_thread (struct thread_state *state);
222extern void finalize_one_mutex (struct Lisp_Mutex *); 237extern void finalize_one_mutex (struct Lisp_Mutex *);
238extern void finalize_one_condvar (struct Lisp_CondVar *);
223 239
224extern void init_threads_once (void); 240extern void init_threads_once (void);
225extern void init_threads (void); 241extern void init_threads (void);