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 == UINT_MAX) { 174 rc = EINVAL; 175 } else { 176 sem->count++; 177 rc = pthread_cond_signal(&sem->cond); 178 } 179 pthread_mutex_unlock(&sem->lock); 180 if (rc != 0) { 181 error_exit(rc, __func__); 182 } 183 #else 184 rc = sem_post(&sem->sem); 185 if (rc < 0) { 186 error_exit(errno, __func__); 187 } 188 #endif 189 } 190 191 static void compute_abs_deadline(struct timespec *ts, int ms) 192 { 193 struct timeval tv; 194 gettimeofday(&tv, NULL); 195 ts->tv_nsec = tv.tv_usec * 1000 + (ms % 1000) * 1000000; 196 ts->tv_sec = tv.tv_sec + ms / 1000; 197 if (ts->tv_nsec >= 1000000000) { 198 ts->tv_sec++; 199 ts->tv_nsec -= 1000000000; 200 } 201 } 202 203 int qemu_sem_timedwait(QemuSemaphore *sem, int ms) 204 { 205 int rc; 206 struct timespec ts; 207 208 #if defined(__APPLE__) || defined(__NetBSD__) 209 rc = 0; 210 compute_abs_deadline(&ts, ms); 211 pthread_mutex_lock(&sem->lock); 212 while (sem->count == 0) { 213 rc = pthread_cond_timedwait(&sem->cond, &sem->lock, &ts); 214 if (rc == ETIMEDOUT) { 215 break; 216 } 217 if (rc != 0) { 218 error_exit(rc, __func__); 219 } 220 } 221 if (rc != ETIMEDOUT) { 222 --sem->count; 223 } 224 pthread_mutex_unlock(&sem->lock); 225 return (rc == ETIMEDOUT ? -1 : 0); 226 #else 227 if (ms <= 0) { 228 /* This is cheaper than sem_timedwait. */ 229 do { 230 rc = sem_trywait(&sem->sem); 231 } while (rc == -1 && errno == EINTR); 232 if (rc == -1 && errno == EAGAIN) { 233 return -1; 234 } 235 } else { 236 compute_abs_deadline(&ts, ms); 237 do { 238 rc = sem_timedwait(&sem->sem, &ts); 239 } while (rc == -1 && errno == EINTR); 240 if (rc == -1 && errno == ETIMEDOUT) { 241 return -1; 242 } 243 } 244 if (rc < 0) { 245 error_exit(errno, __func__); 246 } 247 return 0; 248 #endif 249 } 250 251 void qemu_sem_wait(QemuSemaphore *sem) 252 { 253 int rc; 254 255 #if defined(__APPLE__) || defined(__NetBSD__) 256 pthread_mutex_lock(&sem->lock); 257 while (sem->count == 0) { 258 rc = pthread_cond_wait(&sem->cond, &sem->lock); 259 if (rc != 0) { 260 error_exit(rc, __func__); 261 } 262 } 263 --sem->count; 264 pthread_mutex_unlock(&sem->lock); 265 #else 266 do { 267 rc = sem_wait(&sem->sem); 268 } while (rc == -1 && errno == EINTR); 269 if (rc < 0) { 270 error_exit(errno, __func__); 271 } 272 #endif 273 } 274 275 void qemu_thread_create(QemuThread *thread, 276 void *(*start_routine)(void*), 277 void *arg, int mode) 278 { 279 sigset_t set, oldset; 280 int err; 281 pthread_attr_t attr; 282 283 err = pthread_attr_init(&attr); 284 if (err) { 285 error_exit(err, __func__); 286 } 287 if (mode == QEMU_THREAD_DETACHED) { 288 err = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 289 if (err) { 290 error_exit(err, __func__); 291 } 292 } 293 294 /* Leave signal handling to the iothread. */ 295 sigfillset(&set); 296 pthread_sigmask(SIG_SETMASK, &set, &oldset); 297 err = pthread_create(&thread->thread, &attr, start_routine, arg); 298 if (err) 299 error_exit(err, __func__); 300 301 pthread_sigmask(SIG_SETMASK, &oldset, NULL); 302 303 pthread_attr_destroy(&attr); 304 } 305 306 void qemu_thread_get_self(QemuThread *thread) 307 { 308 thread->thread = pthread_self(); 309 } 310 311 bool qemu_thread_is_self(QemuThread *thread) 312 { 313 return pthread_equal(pthread_self(), thread->thread); 314 } 315 316 void qemu_thread_exit(void *retval) 317 { 318 pthread_exit(retval); 319 } 320 321 void *qemu_thread_join(QemuThread *thread) 322 { 323 int err; 324 void *ret; 325 326 err = pthread_join(thread->thread, &ret); 327 if (err) { 328 error_exit(err, __func__); 329 } 330 return ret; 331 } 332