klisp

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

kmutex.c (3668B)


      1 /*
      2 ** kmutex.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 "kmem.h"
     11 #include "kgc.h"
     12 #include "kerror.h"
     13 
     14 TValue kmake_mutex(klisp_State *K) 
     15 {
     16     Mutex *new_mutex = klispM_new(K, Mutex);
     17 
     18     /* header + gc_fields */
     19     klispC_link(K, (GCObject *) new_mutex, K_TMUTEX, 0);
     20 
     21     /* mutex specific fields */
     22     new_mutex->count = 0;
     23     new_mutex->owner = KMUTEX_NO_OWNER; /* no owner */
     24 
     25     /* XXX no attrs for now */
     26     int32_t res = pthread_mutex_init(&new_mutex->mutex, NULL);
     27 
     28     if (res != 0) {
     29         klispE_throw_simple_with_irritants(K, "Can't create mutex", 1, 
     30                                            i2tv(res));
     31         return KNIL;
     32     }
     33     return gc2mutex(new_mutex);
     34 }
     35 
     36 /* LOCK: GIL should be acquired exactly once */
     37 void kmutex_lock(klisp_State *K, TValue mutex)
     38 {
     39     TValue thread = gc2th(K);
     40     if (tv_equal(thread, kmutex_owner(mutex))) {
     41         if (kmutex_count(mutex) == KMUTEX_MAX_COUNT) {
     42             klispE_throw_simple(K, "Mutex count overflow");
     43             return;
     44         }
     45         ++kmutex_count(mutex);
     46     } else {
     47         /* we need to release GIL to avoid deadlocks */
     48         klisp_unlock(K);
     49         int res = pthread_mutex_lock(&kmutex_mutex(mutex));
     50         klisp_lock(K);
     51 
     52         if (res != 0) {
     53             klispE_throw_simple_with_irritants(K, "Can't lock mutex",
     54                                                1, i2tv(res));
     55             return;
     56         }
     57 
     58         klisp_assert(!kmutex_is_owned(mutex));
     59         kmutex_owner(mutex) = thread;
     60         kmutex_count(mutex) = 1;
     61     }
     62 }
     63 
     64 /* LOCK: GIL should be acquired exactly once */
     65 void kmutex_unlock(klisp_State *K, TValue mutex)
     66 {
     67     TValue thread = gc2th(K);
     68     if (!kmutex_is_owned(mutex)) {
     69         klispE_throw_simple(K, "The mutex isn't locked");
     70         return;
     71     } else if (tv_equal(thread, kmutex_owner(mutex))) {
     72         if (kmutex_count(mutex) == 1) {
     73             int res = pthread_mutex_unlock(&kmutex_mutex(mutex));
     74 
     75             if (res != 0) {
     76                 klispE_throw_simple_with_irritants(K, "Can't unlock mutex",
     77                                                    1, i2tv(res));
     78                 return;
     79             }
     80 
     81             kmutex_owner(mutex) = KMUTEX_NO_OWNER;
     82             kmutex_count(mutex) = 0;
     83         } else {
     84             --kmutex_count(mutex);
     85         }
     86     } else {
     87         klispE_throw_simple(K, "The mutex is locked by a different thread");
     88         return;
     89     }
     90 }
     91 
     92 /* LOCK: GIL should be acquired exactly once */
     93 bool kmutex_trylock(klisp_State *K, TValue mutex)
     94 {
     95     TValue thread = gc2th(K);
     96     if (tv_equal(thread, kmutex_owner(mutex))) {
     97         kmutex_lock(K, mutex); /* this will check max_count */
     98         return true;
     99     } else if (kmutex_is_owned(mutex)) {
    100         return false;
    101     } else {
    102         /* we need to release GIL to avoid deadlocks */
    103         klisp_unlock(K);
    104         int res = pthread_mutex_trylock(&kmutex_mutex(mutex));
    105         klisp_lock(K);
    106 
    107         if (res == 0) {
    108             klisp_assert(!kmutex_is_owned(mutex));
    109             kmutex_owner(mutex) = thread;
    110             kmutex_count(mutex) = 1;
    111             return true;
    112         } else if (res == EBUSY) {
    113             return false;
    114         } else {
    115             klispE_throw_simple_with_irritants(K, "Error on trylock mutex",
    116                                                1, i2tv(res));
    117             return false;
    118         }
    119     } 
    120 }
    121 
    122 void klispX_free(klisp_State *K, Mutex *m)
    123 {
    124 /* XXX/??? Is it okay if the mutex wasn't correctly created?, 
    125    i.e. the contructor throwed an error*/
    126     UNUSED(pthread_mutex_destroy(&m->mutex));
    127     klispM_free(K, m);
    128 }