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 #ifdef __linux__ 24 #include <sys/syscall.h> 25 #include <linux/futex.h> 26 #endif 27 #include "qemu/thread.h" 28 #include "qemu/atomic.h" 29 30 static void error_exit(int err, const char *msg) 31 { 32 fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err)); 33 abort(); 34 } 35 36 void qemu_mutex_init(QemuMutex *mutex) 37 { 38 int err; 39 pthread_mutexattr_t mutexattr; 40 41 pthread_mutexattr_init(&mutexattr); 42 pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_ERRORCHECK); 43 err = pthread_mutex_init(&mutex->lock, &mutexattr); 44 pthread_mutexattr_destroy(&mutexattr); 45 if (err) 46 error_exit(err, __func__); 47 } 48 49 void qemu_mutex_destroy(QemuMutex *mutex) 50 { 51 int err; 52 53 err = pthread_mutex_destroy(&mutex->lock); 54 if (err) 55 error_exit(err, __func__); 56 } 57 58 void qemu_mutex_lock(QemuMutex *mutex) 59 { 60 int err; 61 62 err = pthread_mutex_lock(&mutex->lock); 63 if (err) 64 error_exit(err, __func__); 65 } 66 67 int qemu_mutex_trylock(QemuMutex *mutex) 68 { 69 return pthread_mutex_trylock(&mutex->lock); 70 } 71 72 void qemu_mutex_unlock(QemuMutex *mutex) 73 { 74 int err; 75 76 err = pthread_mutex_unlock(&mutex->lock); 77 if (err) 78 error_exit(err, __func__); 79 } 80 81 void qemu_cond_init(QemuCond *cond) 82 { 83 int err; 84 85 err = pthread_cond_init(&cond->cond, NULL); 86 if (err) 87 error_exit(err, __func__); 88 } 89 90 void qemu_cond_destroy(QemuCond *cond) 91 { 92 int err; 93 94 err = pthread_cond_destroy(&cond->cond); 95 if (err) 96 error_exit(err, __func__); 97 } 98 99 void qemu_cond_signal(QemuCond *cond) 100 { 101 int err; 102 103 err = pthread_cond_signal(&cond->cond); 104 if (err) 105 error_exit(err, __func__); 106 } 107 108 void qemu_cond_broadcast(QemuCond *cond) 109 { 110 int err; 111 112 err = pthread_cond_broadcast(&cond->cond); 113 if (err) 114 error_exit(err, __func__); 115 } 116 117 void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex) 118 { 119 int err; 120 121 err = pthread_cond_wait(&cond->cond, &mutex->lock); 122 if (err) 123 error_exit(err, __func__); 124 } 125 126 void qemu_sem_init(QemuSemaphore *sem, int init) 127 { 128 int rc; 129 130 #if defined(__APPLE__) || defined(__NetBSD__) 131 rc = pthread_mutex_init(&sem->lock, NULL); 132 if (rc != 0) { 133 error_exit(rc, __func__); 134 } 135 rc = pthread_cond_init(&sem->cond, NULL); 136 if (rc != 0) { 137 error_exit(rc, __func__); 138 } 139 if (init < 0) { 140 error_exit(EINVAL, __func__); 141 } 142 sem->count = init; 143 #else 144 rc = sem_init(&sem->sem, 0, init); 145 if (rc < 0) { 146 error_exit(errno, __func__); 147 } 148 #endif 149 } 150 151 void qemu_sem_destroy(QemuSemaphore *sem) 152 { 153 int rc; 154 155 #if defined(__APPLE__) || defined(__NetBSD__) 156 rc = pthread_cond_destroy(&sem->cond); 157 if (rc < 0) { 158 error_exit(rc, __func__); 159 } 160 rc = pthread_mutex_destroy(&sem->lock); 161 if (rc < 0) { 162 error_exit(rc, __func__); 163 } 164 #else 165 rc = sem_destroy(&sem->sem); 166 if (rc < 0) { 167 error_exit(errno, __func__); 168 } 169 #endif 170 } 171 172 void qemu_sem_post(QemuSemaphore *sem) 173 { 174 int rc; 175 176 #if defined(__APPLE__) || defined(__NetBSD__) 177 pthread_mutex_lock(&sem->lock); 178 if (sem->count == UINT_MAX) { 179 rc = EINVAL; 180 } else { 181 sem->count++; 182 rc = pthread_cond_signal(&sem->cond); 183 } 184 pthread_mutex_unlock(&sem->lock); 185 if (rc != 0) { 186 error_exit(rc, __func__); 187 } 188 #else 189 rc = sem_post(&sem->sem); 190 if (rc < 0) { 191 error_exit(errno, __func__); 192 } 193 #endif 194 } 195 196 static void compute_abs_deadline(struct timespec *ts, int ms) 197 { 198 struct timeval tv; 199 gettimeofday(&tv, NULL); 200 ts->tv_nsec = tv.tv_usec * 1000 + (ms % 1000) * 1000000; 201 ts->tv_sec = tv.tv_sec + ms / 1000; 202 if (ts->tv_nsec >= 1000000000) { 203 ts->tv_sec++; 204 ts->tv_nsec -= 1000000000; 205 } 206 } 207 208 int qemu_sem_timedwait(QemuSemaphore *sem, int ms) 209 { 210 int rc; 211 struct timespec ts; 212 213 #if defined(__APPLE__) || defined(__NetBSD__) 214 rc = 0; 215 compute_abs_deadline(&ts, ms); 216 pthread_mutex_lock(&sem->lock); 217 while (sem->count == 0) { 218 rc = pthread_cond_timedwait(&sem->cond, &sem->lock, &ts); 219 if (rc == ETIMEDOUT) { 220 break; 221 } 222 if (rc != 0) { 223 error_exit(rc, __func__); 224 } 225 } 226 if (rc != ETIMEDOUT) { 227 --sem->count; 228 } 229 pthread_mutex_unlock(&sem->lock); 230 return (rc == ETIMEDOUT ? -1 : 0); 231 #else 232 if (ms <= 0) { 233 /* This is cheaper than sem_timedwait. */ 234 do { 235 rc = sem_trywait(&sem->sem); 236 } while (rc == -1 && errno == EINTR); 237 if (rc == -1 && errno == EAGAIN) { 238 return -1; 239 } 240 } else { 241 compute_abs_deadline(&ts, ms); 242 do { 243 rc = sem_timedwait(&sem->sem, &ts); 244 } while (rc == -1 && errno == EINTR); 245 if (rc == -1 && errno == ETIMEDOUT) { 246 return -1; 247 } 248 } 249 if (rc < 0) { 250 error_exit(errno, __func__); 251 } 252 return 0; 253 #endif 254 } 255 256 void qemu_sem_wait(QemuSemaphore *sem) 257 { 258 int rc; 259 260 #if defined(__APPLE__) || defined(__NetBSD__) 261 pthread_mutex_lock(&sem->lock); 262 while (sem->count == 0) { 263 rc = pthread_cond_wait(&sem->cond, &sem->lock); 264 if (rc != 0) { 265 error_exit(rc, __func__); 266 } 267 } 268 --sem->count; 269 pthread_mutex_unlock(&sem->lock); 270 #else 271 do { 272 rc = sem_wait(&sem->sem); 273 } while (rc == -1 && errno == EINTR); 274 if (rc < 0) { 275 error_exit(errno, __func__); 276 } 277 #endif 278 } 279 280 #ifdef __linux__ 281 #define futex(...) syscall(__NR_futex, __VA_ARGS__) 282 283 static inline void futex_wake(QemuEvent *ev, int n) 284 { 285 futex(ev, FUTEX_WAKE, n, NULL, NULL, 0); 286 } 287 288 static inline void futex_wait(QemuEvent *ev, unsigned val) 289 { 290 futex(ev, FUTEX_WAIT, (int) val, NULL, NULL, 0); 291 } 292 #else 293 static inline void futex_wake(QemuEvent *ev, int n) 294 { 295 if (n == 1) { 296 pthread_cond_signal(&ev->cond); 297 } else { 298 pthread_cond_broadcast(&ev->cond); 299 } 300 } 301 302 static inline void futex_wait(QemuEvent *ev, unsigned val) 303 { 304 pthread_mutex_lock(&ev->lock); 305 if (ev->value == val) { 306 pthread_cond_wait(&ev->cond, &ev->lock); 307 } 308 pthread_mutex_unlock(&ev->lock); 309 } 310 #endif 311 312 /* Valid transitions: 313 * - free->set, when setting the event 314 * - busy->set, when setting the event, followed by futex_wake 315 * - set->free, when resetting the event 316 * - free->busy, when waiting 317 * 318 * set->busy does not happen (it can be observed from the outside but 319 * it really is set->free->busy). 320 * 321 * busy->free provably cannot happen; to enforce it, the set->free transition 322 * is done with an OR, which becomes a no-op if the event has concurrently 323 * transitioned to free or busy. 324 */ 325 326 #define EV_SET 0 327 #define EV_FREE 1 328 #define EV_BUSY -1 329 330 void qemu_event_init(QemuEvent *ev, bool init) 331 { 332 #ifndef __linux__ 333 pthread_mutex_init(&ev->lock, NULL); 334 pthread_cond_init(&ev->cond, NULL); 335 #endif 336 337 ev->value = (init ? EV_SET : EV_FREE); 338 } 339 340 void qemu_event_destroy(QemuEvent *ev) 341 { 342 #ifndef __linux__ 343 pthread_mutex_destroy(&ev->lock); 344 pthread_cond_destroy(&ev->cond); 345 #endif 346 } 347 348 void qemu_event_set(QemuEvent *ev) 349 { 350 if (atomic_mb_read(&ev->value) != EV_SET) { 351 if (atomic_xchg(&ev->value, EV_SET) == EV_BUSY) { 352 /* There were waiters, wake them up. */ 353 futex_wake(ev, INT_MAX); 354 } 355 } 356 } 357 358 void qemu_event_reset(QemuEvent *ev) 359 { 360 if (atomic_mb_read(&ev->value) == EV_SET) { 361 /* 362 * If there was a concurrent reset (or even reset+wait), 363 * do nothing. Otherwise change EV_SET->EV_FREE. 364 */ 365 atomic_or(&ev->value, EV_FREE); 366 } 367 } 368 369 void qemu_event_wait(QemuEvent *ev) 370 { 371 unsigned value; 372 373 value = atomic_mb_read(&ev->value); 374 if (value != EV_SET) { 375 if (value == EV_FREE) { 376 /* 377 * Leave the event reset and tell qemu_event_set that there 378 * are waiters. No need to retry, because there cannot be 379 * a concurent busy->free transition. After the CAS, the 380 * event will be either set or busy. 381 */ 382 if (atomic_cmpxchg(&ev->value, EV_FREE, EV_BUSY) == EV_SET) { 383 return; 384 } 385 } 386 futex_wait(ev, EV_BUSY); 387 } 388 } 389 390 391 void qemu_thread_create(QemuThread *thread, 392 void *(*start_routine)(void*), 393 void *arg, int mode) 394 { 395 sigset_t set, oldset; 396 int err; 397 pthread_attr_t attr; 398 399 err = pthread_attr_init(&attr); 400 if (err) { 401 error_exit(err, __func__); 402 } 403 if (mode == QEMU_THREAD_DETACHED) { 404 err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 405 if (err) { 406 error_exit(err, __func__); 407 } 408 } 409 410 /* Leave signal handling to the iothread. */ 411 sigfillset(&set); 412 pthread_sigmask(SIG_SETMASK, &set, &oldset); 413 err = pthread_create(&thread->thread, &attr, start_routine, arg); 414 if (err) 415 error_exit(err, __func__); 416 417 pthread_sigmask(SIG_SETMASK, &oldset, NULL); 418 419 pthread_attr_destroy(&attr); 420 } 421 422 void qemu_thread_get_self(QemuThread *thread) 423 { 424 thread->thread = pthread_self(); 425 } 426 427 bool qemu_thread_is_self(QemuThread *thread) 428 { 429 return pthread_equal(pthread_self(), thread->thread); 430 } 431 432 void qemu_thread_exit(void *retval) 433 { 434 pthread_exit(retval); 435 } 436 437 void *qemu_thread_join(QemuThread *thread) 438 { 439 int err; 440 void *ret; 441 442 err = pthread_join(thread->thread, &ret); 443 if (err) { 444 error_exit(err, __func__); 445 } 446 return ret; 447 } 448