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 }