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