1 /* 2 * Wrappers around mutex/cond/thread functions 3 * 4 * Copyright Red Hat, Inc. 2009 5 * 6 * Author: 7 * Marcelo Tosatti <mtosatti@redhat.com> 8 * 9 * This work is licensed under the terms of the GNU GPL, version 2 or later. 10 * See the COPYING file in the top-level directory. 11 * 12 */ 13 #include <stdlib.h> 14 #include <stdio.h> 15 #include <errno.h> 16 #include <time.h> 17 #include <signal.h> 18 #include <stdint.h> 19 #include <string.h> 20 #include <limits.h> 21 #include <unistd.h> 22 #include <sys/time.h> 23 #include "qemu/thread.h" 24 25 static void error_exit(int err, const char *msg) 26 { 27 fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err)); 28 abort(); 29 } 30 31 void qemu_mutex_init(QemuMutex *mutex) 32 { 33 int err; 34 pthread_mutexattr_t mutexattr; 35 36 pthread_mutexattr_init(&mutexattr); 37 pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK); 38 err = pthread_mutex_init(&mutex->lock, &mutexattr); 39 pthread_mutexattr_destroy(&mutexattr); 40 if (err) 41 error_exit(err, __func__); 42 } 43 44 void qemu_mutex_destroy(QemuMutex *mutex) 45 { 46 int err; 47 48 err = pthread_mutex_destroy(&mutex->lock); 49 if (err) 50 error_exit(err, __func__); 51 } 52 53 void qemu_mutex_lock(QemuMutex *mutex) 54 { 55 int err; 56 57 err = pthread_mutex_lock(&mutex->lock); 58 if (err) 59 error_exit(err, __func__); 60 } 61 62 int qemu_mutex_trylock(QemuMutex *mutex) 63 { 64 return pthread_mutex_trylock(&mutex->lock); 65 } 66 67 void qemu_mutex_unlock(QemuMutex *mutex) 68 { 69 int err; 70 71 err = pthread_mutex_unlock(&mutex->lock); 72 if (err) 73 error_exit(err, __func__); 74 } 75 76 void qemu_cond_init(QemuCond *cond) 77 { 78 int err; 79 80 err = pthread_cond_init(&cond->cond, NULL); 81 if (err) 82 error_exit(err, __func__); 83 } 84 85 void qemu_cond_destroy(QemuCond *cond) 86 { 87 int err; 88 89 err = pthread_cond_destroy(&cond->cond); 90 if (err) 91 error_exit(err, __func__); 92 } 93 94 void qemu_cond_signal(QemuCond *cond) 95 { 96 int err; 97 98 err = pthread_cond_signal(&cond->cond); 99 if (err) 100 error_exit(err, __func__); 101 } 102 103 void qemu_cond_broadcast(QemuCond *cond) 104 { 105 int err; 106 107 err = pthread_cond_broadcast(&cond->cond); 108 if (err) 109 error_exit(err, __func__); 110 } 111 112 void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex) 113 { 114 int err; 115 116 err = pthread_cond_wait(&cond->cond, &mutex->lock); 117 if (err) 118 error_exit(err, __func__); 119 } 120 121 void qemu_sem_init(QemuSemaphore *sem, int init) 122 { 123 int rc; 124 125 #if defined(__APPLE__) || defined(__NetBSD__) 126 rc = pthread_mutex_init(&sem->lock, NULL); 127 if (rc != 0) { 128 error_exit(rc, __func__); 129 } 130 rc = pthread_cond_init(&sem->cond, NULL); 131 if (rc != 0) { 132 error_exit(rc, __func__); 133 } 134 if (init < 0) { 135 error_exit(EINVAL, __func__); 136 } 137 sem->count = init; 138 #else 139 rc = sem_init(&sem->sem, 0, init); 140 if (rc < 0) { 141 error_exit(errno, __func__); 142 } 143 #endif 144 } 145 146 void qemu_sem_destroy(QemuSemaphore *sem) 147 { 148 int rc; 149 150 #if defined(__APPLE__) || defined(__NetBSD__) 151 rc = pthread_cond_destroy(&sem->cond); 152 if (rc < 0) { 153 error_exit(rc, __func__); 154 } 155 rc = pthread_mutex_destroy(&sem->lock); 156 if (rc < 0) { 157 error_exit(rc, __func__); 158 } 159 #else 160 rc = sem_destroy(&sem->sem); 161 if (rc < 0) { 162 error_exit(errno, __func__); 163 } 164 #endif 165 } 166 167 void qemu_sem_post(QemuSemaphore *sem) 168 { 169 int rc; 170 171 #if defined(__APPLE__) || defined(__NetBSD__) 172 pthread_mutex_lock(&sem->lock); 173 if (sem->count == INT_MAX) { 174 rc = EINVAL; 175 } else if (sem->count++ < 0) { 176 rc = pthread_cond_signal(&sem->cond); 177 } else { 178 rc = 0; 179 } 180 pthread_mutex_unlock(&sem->lock); 181 if (rc != 0) { 182 error_exit(rc, __func__); 183 } 184 #else 185 rc = sem_post(&sem->sem); 186 if (rc < 0) { 187 error_exit(errno, __func__); 188 } 189 #endif 190 } 191 192 static void compute_abs_deadline(struct timespec *ts, int ms) 193 { 194 struct timeval tv; 195 gettimeofday(&tv, NULL); 196 ts->tv_nsec = tv.tv_usec * 1000 + (ms % 1000) * 1000000; 197 ts->tv_sec = tv.tv_sec + ms / 1000; 198 if (ts->tv_nsec >= 1000000000) { 199 ts->tv_sec++; 200 ts->tv_nsec -= 1000000000; 201 } 202 } 203 204 int qemu_sem_timedwait(QemuSemaphore *sem, int ms) 205 { 206 int rc; 207 struct timespec ts; 208 209 #if defined(__APPLE__) || defined(__NetBSD__) 210 compute_abs_deadline(&ts, ms); 211 pthread_mutex_lock(&sem->lock); 212 --sem->count; 213 while (sem->count < 0) { 214 rc = pthread_cond_timedwait(&sem->cond, &sem->lock, &ts); 215 if (rc == ETIMEDOUT) { 216 ++sem->count; 217 break; 218 } 219 if (rc != 0) { 220 error_exit(rc, __func__); 221 } 222 } 223 pthread_mutex_unlock(&sem->lock); 224 return (rc == ETIMEDOUT ? -1 : 0); 225 #else 226 if (ms <= 0) { 227 /* This is cheaper than sem_timedwait. */ 228 do { 229 rc = sem_trywait(&sem->sem); 230 } while (rc == -1 && errno == EINTR); 231 if (rc == -1 && errno == EAGAIN) { 232 return -1; 233 } 234 } else { 235 compute_abs_deadline(&ts, ms); 236 do { 237 rc = sem_timedwait(&sem->sem, &ts); 238 } while (rc == -1 && errno == EINTR); 239 if (rc == -1 && errno == ETIMEDOUT) { 240 return -1; 241 } 242 } 243 if (rc < 0) { 244 error_exit(errno, __func__); 245 } 246 return 0; 247 #endif 248 } 249 250 void qemu_sem_wait(QemuSemaphore *sem) 251 { 252 #if defined(__APPLE__) || defined(__NetBSD__) 253 pthread_mutex_lock(&sem->lock); 254 --sem->count; 255 while (sem->count < 0) { 256 pthread_cond_wait(&sem->cond, &sem->lock); 257 } 258 pthread_mutex_unlock(&sem->lock); 259 #else 260 int rc; 261 262 do { 263 rc = sem_wait(&sem->sem); 264 } while (rc == -1 && errno == EINTR); 265 if (rc < 0) { 266 error_exit(errno, __func__); 267 } 268 #endif 269 } 270 271 void qemu_thread_create(QemuThread *thread, 272 void *(*start_routine)(void*), 273 void *arg, int mode) 274 { 275 sigset_t set, oldset; 276 int err; 277 pthread_attr_t attr; 278 279 err = pthread_attr_init(&attr); 280 if (err) { 281 error_exit(err, __func__); 282 } 283 if (mode == QEMU_THREAD_DETACHED) { 284 err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 285 if (err) { 286 error_exit(err, __func__); 287 } 288 } 289 290 /* Leave signal handling to the iothread. */ 291 sigfillset(&set); 292 pthread_sigmask(SIG_SETMASK, &set, &oldset); 293 err = pthread_create(&thread->thread, &attr, start_routine, arg); 294 if (err) 295 error_exit(err, __func__); 296 297 pthread_sigmask(SIG_SETMASK, &oldset, NULL); 298 299 pthread_attr_destroy(&attr); 300 } 301 302 void qemu_thread_get_self(QemuThread *thread) 303 { 304 thread->thread = pthread_self(); 305 } 306 307 bool qemu_thread_is_self(QemuThread *thread) 308 { 309 return pthread_equal(pthread_self(), thread->thread); 310 } 311 312 void qemu_thread_exit(void *retval) 313 { 314 pthread_exit(retval); 315 } 316 317 void *qemu_thread_join(QemuThread *thread) 318 { 319 int err; 320 void *ret; 321 322 err = pthread_join(thread->thread, &ret); 323 if (err) { 324 error_exit(err, __func__); 325 } 326 return ret; 327 } 328