xref: /openbmc/qemu/util/qemu-thread-posix.c (revision 1b111dc1)
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