1 /* 2 * Wrappers around mutex/cond/thread functions 3 * 4 * Copyright Red Hat, Inc. 2009 5 * 6 * Author: 7 * Marcelo Tosatti <mtosatti (at) 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 "qemu-thread.h" 21 22 static void error_exit(int err, const char *msg) 23 { 24 fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err)); 25 exit(1); 26 } 27 28 void qemu_mutex_init(QemuMutex *mutex) 29 { 30 int err; 31 32 err = pthread_mutex_init(&mutex->lock, NULL); 33 if (err) 34 error_exit(err, __func__); 35 } 36 37 void qemu_mutex_destroy(QemuMutex *mutex) 38 { 39 int err; 40 41 err = pthread_mutex_destroy(&mutex->lock); 42 if (err) 43 error_exit(err, __func__); 44 } 45 46 void qemu_mutex_lock(QemuMutex *mutex) 47 { 48 int err; 49 50 err = pthread_mutex_lock(&mutex->lock); 51 if (err) 52 error_exit(err, __func__); 53 } 54 55 int qemu_mutex_trylock(QemuMutex *mutex) 56 { 57 return pthread_mutex_trylock(&mutex->lock); 58 } 59 60 static void timespec_add_ms(struct timespec *ts, uint64_t msecs) 61 { 62 ts->tv_sec = ts->tv_sec + (long)(msecs / 1000); 63 ts->tv_nsec = (ts->tv_nsec + ((long)msecs % 1000) * 1000000); 64 if (ts->tv_nsec >= 1000000000) { 65 ts->tv_nsec -= 1000000000; 66 ts->tv_sec++; 67 } 68 } 69 70 int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs) 71 { 72 int err; 73 struct timespec ts; 74 75 clock_gettime(CLOCK_REALTIME, &ts); 76 timespec_add_ms(&ts, msecs); 77 78 err = pthread_mutex_timedlock(&mutex->lock, &ts); 79 if (err && err != ETIMEDOUT) 80 error_exit(err, __func__); 81 return err; 82 } 83 84 void qemu_mutex_unlock(QemuMutex *mutex) 85 { 86 int err; 87 88 err = pthread_mutex_unlock(&mutex->lock); 89 if (err) 90 error_exit(err, __func__); 91 } 92 93 void qemu_cond_init(QemuCond *cond) 94 { 95 int err; 96 97 err = pthread_cond_init(&cond->cond, NULL); 98 if (err) 99 error_exit(err, __func__); 100 } 101 102 void qemu_cond_destroy(QemuCond *cond) 103 { 104 int err; 105 106 err = pthread_cond_destroy(&cond->cond); 107 if (err) 108 error_exit(err, __func__); 109 } 110 111 void qemu_cond_signal(QemuCond *cond) 112 { 113 int err; 114 115 err = pthread_cond_signal(&cond->cond); 116 if (err) 117 error_exit(err, __func__); 118 } 119 120 void qemu_cond_broadcast(QemuCond *cond) 121 { 122 int err; 123 124 err = pthread_cond_broadcast(&cond->cond); 125 if (err) 126 error_exit(err, __func__); 127 } 128 129 void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex) 130 { 131 int err; 132 133 err = pthread_cond_wait(&cond->cond, &mutex->lock); 134 if (err) 135 error_exit(err, __func__); 136 } 137 138 int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs) 139 { 140 struct timespec ts; 141 int err; 142 143 clock_gettime(CLOCK_REALTIME, &ts); 144 timespec_add_ms(&ts, msecs); 145 146 err = pthread_cond_timedwait(&cond->cond, &mutex->lock, &ts); 147 if (err && err != ETIMEDOUT) 148 error_exit(err, __func__); 149 return err; 150 } 151 152 void qemu_thread_create(QemuThread *thread, 153 void *(*start_routine)(void*), 154 void *arg) 155 { 156 int err; 157 158 /* Leave signal handling to the iothread. */ 159 sigset_t set, oldset; 160 161 sigfillset(&set); 162 pthread_sigmask(SIG_SETMASK, &set, &oldset); 163 err = pthread_create(&thread->thread, NULL, start_routine, arg); 164 if (err) 165 error_exit(err, __func__); 166 167 pthread_sigmask(SIG_SETMASK, &oldset, NULL); 168 } 169 170 void qemu_thread_signal(QemuThread *thread, int sig) 171 { 172 int err; 173 174 err = pthread_kill(thread->thread, sig); 175 if (err) 176 error_exit(err, __func__); 177 } 178 179 void qemu_thread_self(QemuThread *thread) 180 { 181 thread->thread = pthread_self(); 182 } 183 184 int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2) 185 { 186 return pthread_equal(thread1->thread, thread2->thread); 187 } 188 189 void qemu_thread_exit(void *retval) 190 { 191 pthread_exit(retval); 192 } 193