thread_pthread.c (3258B)
1 /* Written by Kris Maglione <maglione.k at Gmail> */ 2 /* Public domain */ 3 #define _XOPEN_SOURCE 600 4 #include <errno.h> 5 #include <pthread.h> 6 #include <stdlib.h> 7 #include <unistd.h> 8 #include "ixp_local.h" 9 10 static IxpThread ixp_pthread; 11 static pthread_key_t errstr_k; 12 13 /** 14 * Function: ixp_pthread_init 15 * 16 * This function initializes libixp for use in multithreaded 17 * programs using the POSIX thread system. When using libixp in such 18 * programs, this function must be called before any other libixp 19 * functions. This function is part of libixp_pthread, which you 20 * must explicitly link against. 21 */ 22 int 23 ixp_pthread_init() { 24 int ret; 25 26 IXP_ASSERT_VERSION; 27 28 ret = pthread_key_create(&errstr_k, free); 29 if(ret) { 30 werrstr("can't create TLS value: %s", ixp_errbuf()); 31 return 1; 32 } 33 34 ixp_thread = &ixp_pthread; 35 return 0; 36 } 37 38 static char* 39 errbuf(void) { 40 char *ret; 41 42 ret = pthread_getspecific(errstr_k); 43 if(ret == nil) { 44 ret = emallocz(IXP_ERRMAX); 45 pthread_setspecific(errstr_k, (void*)ret); 46 } 47 return ret; 48 } 49 50 static void 51 mlock(IxpMutex *m) { 52 pthread_mutex_lock(m->aux); 53 } 54 55 static int 56 mcanlock(IxpMutex *m) { 57 return !pthread_mutex_trylock(m->aux); 58 } 59 60 static void 61 munlock(IxpMutex *m) { 62 pthread_mutex_unlock(m->aux); 63 } 64 65 static void 66 mdestroy(IxpMutex *m) { 67 pthread_mutex_destroy(m->aux); 68 free(m->aux); 69 } 70 71 static int 72 initmutex(IxpMutex *m) { 73 pthread_mutex_t *mutex; 74 75 mutex = emalloc(sizeof *mutex); 76 if(pthread_mutex_init(mutex, nil)) { 77 free(mutex); 78 return 1; 79 } 80 81 m->aux = mutex; 82 return 0; 83 } 84 85 static void 86 rlock(IxpRWLock *rw) { 87 pthread_rwlock_rdlock(rw->aux); 88 } 89 90 static int 91 canrlock(IxpRWLock *rw) { 92 return !pthread_rwlock_tryrdlock(rw->aux); 93 } 94 95 static void 96 wlock(IxpRWLock *rw) { 97 pthread_rwlock_rdlock(rw->aux); 98 } 99 100 static int 101 canwlock(IxpRWLock *rw) { 102 return !pthread_rwlock_tryrdlock(rw->aux); 103 } 104 105 static void 106 rwunlock(IxpRWLock *rw) { 107 pthread_rwlock_unlock(rw->aux); 108 } 109 110 static void 111 rwdestroy(IxpRWLock *rw) { 112 pthread_rwlock_destroy(rw->aux); 113 free(rw->aux); 114 } 115 116 static int 117 initrwlock(IxpRWLock *rw) { 118 pthread_rwlock_t *rwlock; 119 120 rwlock = emalloc(sizeof *rwlock); 121 if(pthread_rwlock_init(rwlock, nil)) { 122 free(rwlock); 123 return 1; 124 } 125 126 rw->aux = rwlock; 127 return 0; 128 } 129 130 static void 131 rsleep(IxpRendez *r) { 132 pthread_cond_wait(r->aux, r->mutex->aux); 133 } 134 135 static int 136 rwake(IxpRendez *r) { 137 pthread_cond_signal(r->aux); 138 return 0; 139 } 140 141 static int 142 rwakeall(IxpRendez *r) { 143 pthread_cond_broadcast(r->aux); 144 return 0; 145 } 146 147 static void 148 rdestroy(IxpRendez *r) { 149 pthread_cond_destroy(r->aux); 150 free(r->aux); 151 } 152 153 static int 154 initrendez(IxpRendez *r) { 155 pthread_cond_t *cond; 156 157 cond = emalloc(sizeof *cond); 158 if(pthread_cond_init(cond, nil)) { 159 free(cond); 160 return 1; 161 } 162 163 r->aux = cond; 164 return 0; 165 } 166 167 static IxpThread ixp_pthread = { 168 /* Mutex */ 169 .initmutex = initmutex, 170 .lock = mlock, 171 .canlock = mcanlock, 172 .unlock = munlock, 173 .mdestroy = mdestroy, 174 /* RWLock */ 175 .initrwlock = initrwlock, 176 .rlock = rlock, 177 .canrlock = canrlock, 178 .wlock = wlock, 179 .canwlock = canwlock, 180 .runlock = rwunlock, 181 .wunlock = rwunlock, 182 .rwdestroy = rwdestroy, 183 /* Rendez */ 184 .initrendez = initrendez, 185 .sleep = rsleep, 186 .wake = rwake, 187 .wakeall = rwakeall, 188 .rdestroy = rdestroy, 189 /* Other */ 190 .errbuf = errbuf, 191 .read = read, 192 .write = write, 193 .select = select, 194 }; 195