klisp

an open source interpreter for the Kernel Programming Language.
git clone http://git.hanabi.in/repos/klisp.git
Log | Files | Refs | README

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 }