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