kcondvar.c (3182B)
1 /* 2 ** kcondvar.c 3 ** Kernel Libraries 4 ** See Copyright Notice in klisp.h 5 */ 6 7 #include "kobject.h" 8 #include "kstate.h" 9 #include "kmutex.h" 10 #include "kcondvar.h" 11 #include "kmem.h" 12 #include "kgc.h" 13 #include "kerror.h" 14 15 /* GC: Assumes mutex is rooted */ 16 TValue kmake_condvar(klisp_State *K, TValue mutex) 17 { 18 Condvar *new_condvar = klispM_new(K, Condvar); 19 20 /* header + gc_fields */ 21 klispC_link(K, (GCObject *) new_condvar, K_TCONDVAR, 0); 22 23 /* condvar specific fields */ 24 new_condvar->mutex = mutex; 25 26 /* XXX no attrs for now */ 27 int32_t res = pthread_cond_init(&new_condvar->cond, NULL); 28 29 if (res != 0) { 30 klispE_throw_simple_with_irritants(K, "Can't create conndition " 31 "variable", 1, i2tv(res)); 32 return KNIL; 33 } 34 return gc2condvar(new_condvar); 35 } 36 37 /* LOCK: GIL should be acquired exactly once */ 38 /* LOCK: underlying mutex should be acquired by this thread */ 39 /* GC: condvar should be rooted */ 40 void kcondvar_wait(klisp_State *K, TValue condvar) 41 { 42 TValue thread = gc2th(K); 43 TValue mutex = kcondvar_mutex(condvar); 44 45 if (!tv_equal(thread, kmutex_owner(mutex))) { 46 klispE_throw_simple(K, "Can't wait without holding the mutex"); 47 return; 48 } 49 50 /* save mutex info to recover after awakening */ 51 uint32_t count = kmutex_count(mutex); 52 kmutex_owner(mutex) = KMUTEX_NO_OWNER; 53 kmutex_count(mutex) = 0; 54 55 /* we need to release GIL to avoid deadlocks */ 56 klisp_unlock(K); 57 int res = pthread_cond_wait(&kcondvar_cond(condvar), 58 &kmutex_mutex(mutex)); 59 klisp_lock(K); 60 61 /* recover the saved mutex info */ 62 klisp_assert(!kmutex_is_owned(mutex)); 63 64 kmutex_owner(mutex) = thread; 65 kmutex_count(mutex) = count; 66 67 /* This shouldn't happen, according to the spec */ 68 if (res != 0) { 69 klispE_throw_simple_with_irritants(K, "Couldn't wait on condvar", 70 1, i2tv(res)); 71 return; 72 } 73 } 74 75 /* LOCK: GIL should be acquired exactly once */ 76 /* LOCK: underlying mutex should be acquired by this thread */ 77 /* GC: condvar should be rooted */ 78 void kcondvar_signal(klisp_State *K, TValue condvar, bool broadcast) 79 { 80 TValue thread = gc2th(K); 81 TValue mutex = kcondvar_mutex(condvar); 82 83 if (!tv_equal(thread, kmutex_owner(mutex))) { 84 klispE_throw_simple(K, broadcast? 85 "Can't broadcast without holding the mutex" : 86 "Can't signal without holding the mutex"); 87 return; 88 } 89 90 int res = broadcast? pthread_cond_broadcast(&kcondvar_cond(condvar)) : 91 pthread_cond_signal(&kcondvar_cond(condvar)); 92 93 /* This shouldn't happen, according to the spec */ 94 if (res != 0) { 95 klispE_throw_simple_with_irritants(K, broadcast? 96 "Couldn't broadcast on condvar" : 97 "Couldn't signal on condvar", 98 1, i2tv(res)); 99 return; 100 } 101 } 102 103 void klispV_free(klisp_State *K, Condvar *m) 104 { 105 UNUSED(pthread_cond_destroy(&m->cond)); 106 klispM_free(K, m); 107 }