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