diff options
| author | Tom Tromey | 2012-08-15 13:11:22 -0600 |
|---|---|---|
| committer | Tom Tromey | 2012-08-15 13:11:22 -0600 |
| commit | 51100bb8d36f68842ab55fd0501af56dfc58cc51 (patch) | |
| tree | 6c94b7f893304276b43c57bd12eff92d914a7cd2 /src | |
| parent | 1dcacbc64721b1a4de58aa36460b0a39e766be63 (diff) | |
| download | emacs-51100bb8d36f68842ab55fd0501af56dfc58cc51.tar.gz emacs-51100bb8d36f68842ab55fd0501af56dfc58cc51.zip | |
This supplies the mutex implementation for Emacs Lisp.
A lisp mutex is implemented using a condition variable, so that we can
interrupt a mutex-lock operation by calling thread-signal on the
blocking thread. I did things this way because pthread_mutex_lock
can't readily be interrupted.
Diffstat (limited to 'src')
| -rw-r--r-- | src/alloc.c | 2 | ||||
| -rw-r--r-- | src/data.c | 15 | ||||
| -rw-r--r-- | src/lisp.h | 9 | ||||
| -rw-r--r-- | src/print.c | 8 | ||||
| -rw-r--r-- | src/thread.c | 83 | ||||
| -rw-r--r-- | src/thread.h | 3 |
6 files changed, 117 insertions, 3 deletions
diff --git a/src/alloc.c b/src/alloc.c index 69742a325d1..80d22d61d66 100644 --- a/src/alloc.c +++ b/src/alloc.c | |||
| @@ -3104,6 +3104,8 @@ sweep_vectors (void) | |||
| 3104 | 3104 | ||
| 3105 | if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_THREAD)) | 3105 | if (PSEUDOVECTOR_TYPEP (&vector->header, PVEC_THREAD)) |
| 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)) | ||
| 3108 | finalize_one_mutex ((struct Lisp_Mutex *) vector); | ||
| 3107 | 3109 | ||
| 3108 | next = ADVANCE (vector, nbytes); | 3110 | next = ADVANCE (vector, nbytes); |
| 3109 | 3111 | ||
diff --git a/src/data.c b/src/data.c index fd2194fe1ae..b47c2d12aff 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; | 97 | Lisp_Object Qthread, Qmutex; |
| 98 | 98 | ||
| 99 | Lisp_Object Qinteractive_form; | 99 | Lisp_Object Qinteractive_form; |
| 100 | 100 | ||
| @@ -214,6 +214,8 @@ for example, (type-of 1) returns `integer'. */) | |||
| 214 | return Qfont_object; | 214 | return Qfont_object; |
| 215 | if (THREADP (object)) | 215 | if (THREADP (object)) |
| 216 | return Qthread; | 216 | return Qthread; |
| 217 | if (MUTEXP (object)) | ||
| 218 | return Qmutex; | ||
| 217 | return Qvector; | 219 | return Qvector; |
| 218 | 220 | ||
| 219 | case Lisp_Float: | 221 | case Lisp_Float: |
| @@ -471,6 +473,15 @@ DEFUN ("threadp", Fthreadp, Sthreadp, 1, 1, 0, | |||
| 471 | return Qnil; | 473 | return Qnil; |
| 472 | } | 474 | } |
| 473 | 475 | ||
| 476 | DEFUN ("mutexp", Fmutexp, Smutexp, 1, 1, 0, | ||
| 477 | doc: /* Return t if OBJECT is a mutex. */) | ||
| 478 | (Lisp_Object object) | ||
| 479 | { | ||
| 480 | if (MUTEXP (object)) | ||
| 481 | return Qt; | ||
| 482 | else | ||
| 483 | return Qnil; | ||
| 484 | } | ||
| 474 | 485 | ||
| 475 | /* Extract and set components of lists */ | 486 | /* Extract and set components of lists */ |
| 476 | 487 | ||
| @@ -3105,6 +3116,7 @@ syms_of_data (void) | |||
| 3105 | DEFSYM (Qbool_vector, "bool-vector"); | 3116 | DEFSYM (Qbool_vector, "bool-vector"); |
| 3106 | DEFSYM (Qhash_table, "hash-table"); | 3117 | DEFSYM (Qhash_table, "hash-table"); |
| 3107 | DEFSYM (Qthread, "thread"); | 3118 | DEFSYM (Qthread, "thread"); |
| 3119 | DEFSYM (Qmutex, "mutex"); | ||
| 3108 | /* Used by Fgarbage_collect. */ | 3120 | /* Used by Fgarbage_collect. */ |
| 3109 | DEFSYM (Qinterval, "interval"); | 3121 | DEFSYM (Qinterval, "interval"); |
| 3110 | DEFSYM (Qmisc, "misc"); | 3122 | DEFSYM (Qmisc, "misc"); |
| @@ -3148,6 +3160,7 @@ syms_of_data (void) | |||
| 3148 | defsubr (&Sbyte_code_function_p); | 3160 | defsubr (&Sbyte_code_function_p); |
| 3149 | defsubr (&Schar_or_string_p); | 3161 | defsubr (&Schar_or_string_p); |
| 3150 | defsubr (&Sthreadp); | 3162 | defsubr (&Sthreadp); |
| 3163 | defsubr (&Smutexp); | ||
| 3151 | defsubr (&Scar); | 3164 | defsubr (&Scar); |
| 3152 | defsubr (&Scdr); | 3165 | defsubr (&Scdr); |
| 3153 | defsubr (&Scar_safe); | 3166 | defsubr (&Scar_safe); |
diff --git a/src/lisp.h b/src/lisp.h index 52a523259db..f0c831852f6 100644 --- a/src/lisp.h +++ b/src/lisp.h | |||
| @@ -366,6 +366,7 @@ enum pvec_type | |||
| 366 | PVEC_SUBR, | 366 | PVEC_SUBR, |
| 367 | PVEC_OTHER, | 367 | PVEC_OTHER, |
| 368 | PVEC_THREAD, | 368 | PVEC_THREAD, |
| 369 | PVEC_MUTEX, | ||
| 369 | /* These last 4 are special because we OR them in fns.c:internal_equal, | 370 | /* These last 4 are special because we OR them in fns.c:internal_equal, |
| 370 | so they have to use a disjoint bit pattern: | 371 | so they have to use a disjoint bit pattern: |
| 371 | if (!(size & (PVEC_COMPILED | PVEC_CHAR_TABLE | 372 | if (!(size & (PVEC_COMPILED | PVEC_CHAR_TABLE |
| @@ -555,6 +556,7 @@ clip_to_bounds (ptrdiff_t lower, EMACS_INT num, ptrdiff_t upper) | |||
| 555 | ((struct Lisp_Bool_Vector *) \ | 556 | ((struct Lisp_Bool_Vector *) \ |
| 556 | XUNTAG (a, Lisp_Vectorlike))) | 557 | XUNTAG (a, Lisp_Vectorlike))) |
| 557 | #define XTHREAD(a) (eassert (THREADP (a)), (struct thread_state *) XPNTR(a)) | 558 | #define XTHREAD(a) (eassert (THREADP (a)), (struct thread_state *) XPNTR(a)) |
| 559 | #define XMUTEX(a) (eassert (MUTEXP (a)), (struct Lisp_Mutex *) XPNTR(a)) | ||
| 558 | 560 | ||
| 559 | /* Construct a Lisp_Object from a value or address. */ | 561 | /* Construct a Lisp_Object from a value or address. */ |
| 560 | 562 | ||
| @@ -606,6 +608,7 @@ clip_to_bounds (ptrdiff_t lower, EMACS_INT num, ptrdiff_t upper) | |||
| 606 | #define XSETBOOL_VECTOR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_BOOL_VECTOR)) | 608 | #define XSETBOOL_VECTOR(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_BOOL_VECTOR)) |
| 607 | #define XSETSUB_CHAR_TABLE(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_SUB_CHAR_TABLE)) | 609 | #define XSETSUB_CHAR_TABLE(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_SUB_CHAR_TABLE)) |
| 608 | #define XSETTHREAD(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_THREAD)) | 610 | #define XSETTHREAD(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_THREAD)) |
| 611 | #define XSETMUTEX(a, b) (XSETPSEUDOVECTOR (a, b, PVEC_MUTEX)) | ||
| 609 | 612 | ||
| 610 | /* Convenience macros for dealing with Lisp arrays. */ | 613 | /* Convenience macros for dealing with Lisp arrays. */ |
| 611 | 614 | ||
| @@ -1705,6 +1708,7 @@ typedef struct { | |||
| 1705 | #define BOOL_VECTOR_P(x) PSEUDOVECTORP (x, PVEC_BOOL_VECTOR) | 1708 | #define BOOL_VECTOR_P(x) PSEUDOVECTORP (x, PVEC_BOOL_VECTOR) |
| 1706 | #define FRAMEP(x) PSEUDOVECTORP (x, PVEC_FRAME) | 1709 | #define FRAMEP(x) PSEUDOVECTORP (x, PVEC_FRAME) |
| 1707 | #define THREADP(x) PSEUDOVECTORP (x, PVEC_THREAD) | 1710 | #define THREADP(x) PSEUDOVECTORP (x, PVEC_THREAD) |
| 1711 | #define MUTEXP(x) PSEUDOVECTORP (x, PVEC_MUTEX) | ||
| 1708 | 1712 | ||
| 1709 | /* Test for image (image . spec) */ | 1713 | /* Test for image (image . spec) */ |
| 1710 | #define IMAGEP(x) (CONSP (x) && EQ (XCAR (x), Qimage)) | 1714 | #define IMAGEP(x) (CONSP (x) && EQ (XCAR (x), Qimage)) |
| @@ -1826,6 +1830,9 @@ typedef struct { | |||
| 1826 | #define CHECK_THREAD(x) \ | 1830 | #define CHECK_THREAD(x) \ |
| 1827 | CHECK_TYPE (THREADP (x), Qthreadp, x) | 1831 | CHECK_TYPE (THREADP (x), Qthreadp, x) |
| 1828 | 1832 | ||
| 1833 | #define CHECK_MUTEX(x) \ | ||
| 1834 | CHECK_TYPE (MUTEXP (x), Qmutexp, x) | ||
| 1835 | |||
| 1829 | /* Since we can't assign directly to the CAR or CDR fields of a cons | 1836 | /* Since we can't assign directly to the CAR or CDR fields of a cons |
| 1830 | cell, use these when checking that those fields contain numbers. */ | 1837 | cell, use these when checking that those fields contain numbers. */ |
| 1831 | #define CHECK_NUMBER_CAR(x) \ | 1838 | #define CHECK_NUMBER_CAR(x) \ |
| @@ -2448,7 +2455,7 @@ extern Lisp_Object Qchar_or_string_p, Qmarkerp, Qinteger_or_marker_p, Qvectorp; | |||
| 2448 | extern Lisp_Object Qbuffer_or_string_p; | 2455 | extern Lisp_Object Qbuffer_or_string_p; |
| 2449 | extern Lisp_Object Qfboundp; | 2456 | extern Lisp_Object Qfboundp; |
| 2450 | extern Lisp_Object Qchar_table_p, Qvector_or_char_table_p; | 2457 | extern Lisp_Object Qchar_table_p, Qvector_or_char_table_p; |
| 2451 | extern Lisp_Object Qthreadp; | 2458 | extern Lisp_Object Qthreadp, Qmutexp; |
| 2452 | 2459 | ||
| 2453 | extern Lisp_Object Qcdr; | 2460 | extern Lisp_Object Qcdr; |
| 2454 | 2461 | ||
diff --git a/src/print.c b/src/print.c index 4537521b9fa..42e7241ecba 100644 --- a/src/print.c +++ b/src/print.c | |||
| @@ -1955,6 +1955,14 @@ print_object (Lisp_Object obj, register Lisp_Object printcharfun, int escapeflag | |||
| 1955 | } | 1955 | } |
| 1956 | PRINTCHAR ('>'); | 1956 | PRINTCHAR ('>'); |
| 1957 | } | 1957 | } |
| 1958 | else if (MUTEXP (obj)) | ||
| 1959 | { | ||
| 1960 | int len; | ||
| 1961 | strout ("#<mutex ", -1, -1, printcharfun); | ||
| 1962 | len = sprintf (buf, "%p", XMUTEX (obj)); | ||
| 1963 | strout (buf, len, len, printcharfun); | ||
| 1964 | PRINTCHAR ('>'); | ||
| 1965 | } | ||
| 1958 | else | 1966 | else |
| 1959 | { | 1967 | { |
| 1960 | ptrdiff_t size = ASIZE (obj); | 1968 | ptrdiff_t size = ASIZE (obj); |
diff --git a/src/thread.c b/src/thread.c index 5da2e10f1ae..80557e5d5ee 100644 --- a/src/thread.c +++ b/src/thread.c | |||
| @@ -35,7 +35,83 @@ static struct thread_state *all_threads = &primary_thread; | |||
| 35 | 35 | ||
| 36 | sys_mutex_t global_lock; | 36 | sys_mutex_t global_lock; |
| 37 | 37 | ||
| 38 | Lisp_Object Qthreadp; | 38 | Lisp_Object Qthreadp, Qmutexp; |
| 39 | |||
| 40 | |||
| 41 | |||
| 42 | struct Lisp_Mutex | ||
| 43 | { | ||
| 44 | struct vectorlike_header header; | ||
| 45 | |||
| 46 | lisp_mutex_t mutex; | ||
| 47 | }; | ||
| 48 | |||
| 49 | DEFUN ("make-mutex", Fmake_mutex, Smake_mutex, 0, 0, 0, | ||
| 50 | doc: /* FIXME */) | ||
| 51 | (void) | ||
| 52 | { | ||
| 53 | struct Lisp_Mutex *mutex; | ||
| 54 | Lisp_Object result; | ||
| 55 | |||
| 56 | mutex = ALLOCATE_PSEUDOVECTOR (struct Lisp_Mutex, mutex, PVEC_MUTEX); | ||
| 57 | memset ((char *) mutex + offsetof (struct Lisp_Mutex, mutex), | ||
| 58 | 0, sizeof (struct Lisp_Mutex) - offsetof (struct Lisp_Mutex, | ||
| 59 | mutex)); | ||
| 60 | lisp_mutex_init (&mutex->mutex); | ||
| 61 | |||
| 62 | XSETMUTEX (result, mutex); | ||
| 63 | return result; | ||
| 64 | } | ||
| 65 | |||
| 66 | static void | ||
| 67 | mutex_lock_callback (void *arg) | ||
| 68 | { | ||
| 69 | struct Lisp_Mutex *mutex = arg; | ||
| 70 | |||
| 71 | /* This calls post_acquire_global_lock. */ | ||
| 72 | lisp_mutex_lock (&mutex->mutex); | ||
| 73 | } | ||
| 74 | |||
| 75 | DEFUN ("mutex-lock", Fmutex_lock, Smutex_lock, 1, 1, 0, | ||
| 76 | doc: /* FIXME */) | ||
| 77 | (Lisp_Object obj) | ||
| 78 | { | ||
| 79 | struct Lisp_Mutex *mutex; | ||
| 80 | |||
| 81 | CHECK_MUTEX (obj); | ||
| 82 | mutex = XMUTEX (obj); | ||
| 83 | |||
| 84 | flush_stack_call_func (mutex_lock_callback, mutex); | ||
| 85 | return Qnil; | ||
| 86 | } | ||
| 87 | |||
| 88 | static void | ||
| 89 | mutex_unlock_callback (void *arg) | ||
| 90 | { | ||
| 91 | struct Lisp_Mutex *mutex = arg; | ||
| 92 | |||
| 93 | /* This calls post_acquire_global_lock. */ | ||
| 94 | lisp_mutex_unlock (&mutex->mutex); | ||
| 95 | } | ||
| 96 | |||
| 97 | DEFUN ("mutex-unlock", Fmutex_unlock, Smutex_unlock, 1, 1, 0, | ||
| 98 | doc: /* FIXME */) | ||
| 99 | (Lisp_Object obj) | ||
| 100 | { | ||
| 101 | struct Lisp_Mutex *mutex; | ||
| 102 | |||
| 103 | CHECK_MUTEX (obj); | ||
| 104 | mutex = XMUTEX (obj); | ||
| 105 | |||
| 106 | flush_stack_call_func (mutex_unlock_callback, mutex); | ||
| 107 | return Qnil; | ||
| 108 | } | ||
| 109 | |||
| 110 | void | ||
| 111 | finalize_one_mutex (struct Lisp_Mutex *mutex) | ||
| 112 | { | ||
| 113 | lisp_mutex_destroy (&mutex->mutex); | ||
| 114 | } | ||
| 39 | 115 | ||
| 40 | 116 | ||
| 41 | 117 | ||
| @@ -463,7 +539,12 @@ syms_of_threads (void) | |||
| 463 | defsubr (&Sthread_alive_p); | 539 | defsubr (&Sthread_alive_p); |
| 464 | defsubr (&Sthread_join); | 540 | defsubr (&Sthread_join); |
| 465 | defsubr (&Sall_threads); | 541 | defsubr (&Sall_threads); |
| 542 | defsubr (&Smake_mutex); | ||
| 543 | defsubr (&Smutex_lock); | ||
| 544 | defsubr (&Smutex_unlock); | ||
| 466 | 545 | ||
| 467 | Qthreadp = intern_c_string ("threadp"); | 546 | Qthreadp = intern_c_string ("threadp"); |
| 468 | staticpro (&Qthreadp); | 547 | staticpro (&Qthreadp); |
| 548 | Qmutexp = intern_c_string ("mutexp"); | ||
| 549 | staticpro (&Qmutexp); | ||
| 469 | } | 550 | } |
diff --git a/src/thread.h b/src/thread.h index 3b533316817..d3ec38a22b9 100644 --- a/src/thread.h +++ b/src/thread.h | |||
| @@ -168,6 +168,8 @@ struct thread_state | |||
| 168 | struct thread_state *next_thread; | 168 | struct thread_state *next_thread; |
| 169 | }; | 169 | }; |
| 170 | 170 | ||
| 171 | struct Lisp_Mutex; | ||
| 172 | |||
| 171 | extern struct thread_state *current_thread; | 173 | extern struct thread_state *current_thread; |
| 172 | 174 | ||
| 173 | extern sys_mutex_t global_lock; | 175 | extern sys_mutex_t global_lock; |
| @@ -175,6 +177,7 @@ extern void post_acquire_global_lock (struct thread_state *); | |||
| 175 | 177 | ||
| 176 | extern void unmark_threads (void); | 178 | extern void unmark_threads (void); |
| 177 | extern void finalize_one_thread (struct thread_state *state); | 179 | extern void finalize_one_thread (struct thread_state *state); |
| 180 | extern void finalize_one_mutex (struct Lisp_Mutex *); | ||
| 178 | 181 | ||
| 179 | extern void init_threads_once (void); | 182 | extern void init_threads_once (void); |
| 180 | extern void init_threads (void); | 183 | extern void init_threads (void); |