diff options
| author | Tom Tromey | 2012-08-19 03:23:03 -0600 |
|---|---|---|
| committer | Tom Tromey | 2012-08-19 03:23:03 -0600 |
| commit | 5651640d578fa2efa40be4789d9fa61813ccb1fa (patch) | |
| tree | a59e33464016e88cb3f0501d6c47baf8aa5e07aa /src | |
| parent | ee1464eab19311ab7708b135bdb6eb989909e4cc (diff) | |
| download | emacs-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.c | 2 | ||||
| -rw-r--r-- | src/data.c | 17 | ||||
| -rw-r--r-- | src/lisp.h | 9 | ||||
| -rw-r--r-- | src/print.c | 12 | ||||
| -rw-r--r-- | src/thread.c | 219 | ||||
| -rw-r--r-- | src/thread.h | 16 |
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; | |||
| 94 | static Lisp_Object Qsubrp, Qmany, Qunevalled; | 94 | static Lisp_Object Qsubrp, Qmany, Qunevalled; |
| 95 | Lisp_Object Qfont_spec, Qfont_entity, Qfont_object; | 95 | Lisp_Object Qfont_spec, Qfont_entity, Qfont_object; |
| 96 | static Lisp_Object Qdefun; | 96 | static Lisp_Object Qdefun; |
| 97 | Lisp_Object Qthread, Qmutex; | 97 | Lisp_Object Qthread, Qmutex, Qcondition_variable; |
| 98 | 98 | ||
| 99 | Lisp_Object Qinteractive_form; | 99 | Lisp_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 | |||
| 488 | DEFUN ("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; | |||
| 2455 | extern Lisp_Object Qbuffer_or_string_p; | 2462 | extern Lisp_Object Qbuffer_or_string_p; |
| 2456 | extern Lisp_Object Qfboundp; | 2463 | extern Lisp_Object Qfboundp; |
| 2457 | extern Lisp_Object Qchar_table_p, Qvector_or_char_table_p; | 2464 | extern Lisp_Object Qchar_table_p, Qvector_or_char_table_p; |
| 2458 | extern Lisp_Object Qthreadp, Qmutexp; | 2465 | extern Lisp_Object Qthreadp, Qmutexp, Qcondition_variablep; |
| 2459 | 2466 | ||
| 2460 | extern Lisp_Object Qcdr; | 2467 | extern 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 | ||
| 33 | static sys_mutex_t global_lock; | 33 | static sys_mutex_t global_lock; |
| 34 | 34 | ||
| 35 | Lisp_Object Qthreadp, Qmutexp; | 35 | Lisp_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 | ||
| 92 | static void | 92 | static int |
| 93 | lisp_mutex_lock (lisp_mutex_t *mutex) | 93 | lisp_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 | ||
| 121 | static void | 126 | static int |
| 122 | lisp_mutex_unlock (lisp_mutex_t *mutex) | 127 | lisp_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 | |||
| 143 | static unsigned int | ||
| 144 | lisp_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 | ||
| 138 | static void | 159 | static 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 | ||
| 165 | static int | ||
| 166 | lisp_mutex_owned_p (lisp_mutex_t *mutex) | ||
| 167 | { | ||
| 168 | return mutex->owner == current_thread; | ||
| 169 | } | ||
| 170 | |||
| 144 | 171 | ||
| 145 | 172 | ||
| 146 | DEFUN ("make-mutex", Fmake_mutex, Smake_mutex, 0, 1, 0, | 173 | DEFUN ("make-mutex", Fmake_mutex, Smake_mutex, 0, 1, 0, |
| @@ -173,9 +200,10 @@ static void | |||
| 173 | mutex_lock_callback (void *arg) | 200 | mutex_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 | ||
| 181 | static Lisp_Object | 209 | static Lisp_Object |
| @@ -211,9 +239,10 @@ static void | |||
| 211 | mutex_unlock_callback (void *arg) | 239 | mutex_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 | ||
| 219 | DEFUN ("mutex-unlock", Fmutex_unlock, Smutex_unlock, 1, 1, 0, | 248 | DEFUN ("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 | ||
| 285 | DEFUN ("make-condition-variable", | ||
| 286 | Fmake_condition_variable, Smake_condition_variable, | ||
| 287 | 1, 2, 0, | ||
| 288 | doc: /* Make a condition variable. | ||
| 289 | A condition variable provides a way for a thread to sleep while | ||
| 290 | waiting for a state change. | ||
| 291 | |||
| 292 | MUTEX is the mutex associated with this condition variable. | ||
| 293 | NAME, if given, is the name of this condition variable. The name is | ||
| 294 | informational 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 | |||
| 316 | static void | ||
| 317 | condition_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 | |||
| 341 | DEFUN ("condition-wait", Fcondition_wait, Scondition_wait, 1, 1, 0, | ||
| 342 | doc: /* Wait for the condition variable to be notified. | ||
| 343 | CONDITION is the condition variable to wait on. | ||
| 344 | |||
| 345 | The mutex associated with CONDITION must be held when this is called. | ||
| 346 | It is an error if it is not held. | ||
| 347 | |||
| 348 | This atomically releases the mutex and waits for CONDITION to be | ||
| 349 | notified. When `condition-wait' returns, the mutex will again be | ||
| 350 | locked 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. */ | ||
| 369 | struct notify_args | ||
| 370 | { | ||
| 371 | struct Lisp_CondVar *cvar; | ||
| 372 | int all; | ||
| 373 | }; | ||
| 374 | |||
| 375 | static void | ||
| 376 | condition_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 | |||
| 394 | DEFUN ("condition-notify", Fcondition_notify, Scondition_notify, 1, 2, 0, | ||
| 395 | doc: /* Notify a condition variable. | ||
| 396 | This wakes a thread waiting on CONDITION. | ||
| 397 | If ALL is non-nil, all waiting threads are awoken. | ||
| 398 | |||
| 399 | The mutex associated with CONDITION must be held when this is called. | ||
| 400 | It is an error if it is not held. | ||
| 401 | |||
| 402 | This atomically releases the mutex when notifying CONDITION. When | ||
| 403 | `condition-notify' returns, the mutex will again be locked by this | ||
| 404 | thread. */) | ||
| 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 | |||
| 425 | void | ||
| 426 | finalize_one_condvar (struct Lisp_CondVar *condvar) | ||
| 427 | { | ||
| 428 | sys_cond_destroy (&condvar->cond); | ||
| 429 | } | ||
| 430 | |||
| 431 | |||
| 432 | |||
| 256 | struct select_args | 433 | struct 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. |
| 556 | This acts like `signal', but arranges for the signal to be raised | 733 | This acts like `signal', but arranges for the signal to be raised |
| 557 | in THREAD. If THREAD is the current thread, acts just like `signal'. | 734 | in THREAD. If THREAD is the current thread, acts just like `signal'. |
| 558 | This will interrupt a blocked call to `mutex-lock' or`thread-join' in | 735 | This will interrupt a blocked call to `mutex-lock', `condition-wait', |
| 559 | the target thread. */) | 736 | or `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, | |||
| 597 | If THREAD is blocked in `thread-join' on a second thread, return that | 774 | If THREAD is blocked in `thread-join' on a second thread, return that |
| 598 | thread. | 775 | thread. |
| 599 | If THREAD is blocked in `mutex-lock', return the mutex. | 776 | If THREAD is blocked in `mutex-lock', return the mutex. |
| 777 | If THREAD is blocked in `condition-wait', return the condition variable. | ||
| 600 | Otherwise, if THREAD is not blocked, return nil. */) | 778 | Otherwise, 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. */ | ||
| 219 | struct 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 | |||
| 218 | extern struct thread_state *current_thread; | 233 | extern struct thread_state *current_thread; |
| 219 | 234 | ||
| 220 | extern void unmark_threads (void); | 235 | extern void unmark_threads (void); |
| 221 | extern void finalize_one_thread (struct thread_state *state); | 236 | extern void finalize_one_thread (struct thread_state *state); |
| 222 | extern void finalize_one_mutex (struct Lisp_Mutex *); | 237 | extern void finalize_one_mutex (struct Lisp_Mutex *); |
| 238 | extern void finalize_one_condvar (struct Lisp_CondVar *); | ||
| 223 | 239 | ||
| 224 | extern void init_threads_once (void); | 240 | extern void init_threads_once (void); |
| 225 | extern void init_threads (void); | 241 | extern void init_threads (void); |