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 "qemu-thread.h"
21
22static void error_exit(int err, const char *msg)
23{
24    fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
25    exit(1);
26}
27
28void qemu_mutex_init(QemuMutex *mutex)
29{
30    int err;
31
32    err = pthread_mutex_init(&mutex->lock, NULL);
33    if (err)
34        error_exit(err, __func__);
35}
36
37void qemu_mutex_destroy(QemuMutex *mutex)
38{
39    int err;
40
41    err = pthread_mutex_destroy(&mutex->lock);
42    if (err)
43        error_exit(err, __func__);
44}
45
46void qemu_mutex_lock(QemuMutex *mutex)
47{
48    int err;
49
50    err = pthread_mutex_lock(&mutex->lock);
51    if (err)
52        error_exit(err, __func__);
53}
54
55int qemu_mutex_trylock(QemuMutex *mutex)
56{
57    return pthread_mutex_trylock(&mutex->lock);
58}
59
60static void timespec_add_ms(struct timespec *ts, uint64_t msecs)
61{
62    ts->tv_sec = ts->tv_sec + (long)(msecs / 1000);
63    ts->tv_nsec = (ts->tv_nsec + ((long)msecs % 1000) * 1000000);
64    if (ts->tv_nsec >= 1000000000) {
65        ts->tv_nsec -= 1000000000;
66        ts->tv_sec++;
67    }
68}
69
70int qemu_mutex_timedlock(QemuMutex *mutex, uint64_t msecs)
71{
72    int err;
73    struct timespec ts;
74
75    clock_gettime(CLOCK_REALTIME, &ts);
76    timespec_add_ms(&ts, msecs);
77
78    err = pthread_mutex_timedlock(&mutex->lock, &ts);
79    if (err && err != ETIMEDOUT)
80        error_exit(err, __func__);
81    return err;
82}
83
84void qemu_mutex_unlock(QemuMutex *mutex)
85{
86    int err;
87
88    err = pthread_mutex_unlock(&mutex->lock);
89    if (err)
90        error_exit(err, __func__);
91}
92
93void qemu_cond_init(QemuCond *cond)
94{
95    int err;
96
97    err = pthread_cond_init(&cond->cond, NULL);
98    if (err)
99        error_exit(err, __func__);
100}
101
102void qemu_cond_destroy(QemuCond *cond)
103{
104    int err;
105
106    err = pthread_cond_destroy(&cond->cond);
107    if (err)
108        error_exit(err, __func__);
109}
110
111void qemu_cond_signal(QemuCond *cond)
112{
113    int err;
114
115    err = pthread_cond_signal(&cond->cond);
116    if (err)
117        error_exit(err, __func__);
118}
119
120void qemu_cond_broadcast(QemuCond *cond)
121{
122    int err;
123
124    err = pthread_cond_broadcast(&cond->cond);
125    if (err)
126        error_exit(err, __func__);
127}
128
129void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
130{
131    int err;
132
133    err = pthread_cond_wait(&cond->cond, &mutex->lock);
134    if (err)
135        error_exit(err, __func__);
136}
137
138int qemu_cond_timedwait(QemuCond *cond, QemuMutex *mutex, uint64_t msecs)
139{
140    struct timespec ts;
141    int err;
142
143    clock_gettime(CLOCK_REALTIME, &ts);
144    timespec_add_ms(&ts, msecs);
145
146    err = pthread_cond_timedwait(&cond->cond, &mutex->lock, &ts);
147    if (err && err != ETIMEDOUT)
148        error_exit(err, __func__);
149    return err;
150}
151
152void qemu_thread_create(QemuThread *thread,
153                       void *(*start_routine)(void*),
154                       void *arg)
155{
156    int err;
157
158    /* Leave signal handling to the iothread.  */
159    sigset_t set, oldset;
160
161    sigfillset(&set);
162    pthread_sigmask(SIG_SETMASK, &set, &oldset);
163    err = pthread_create(&thread->thread, NULL, start_routine, arg);
164    if (err)
165        error_exit(err, __func__);
166
167    pthread_sigmask(SIG_SETMASK, &oldset, NULL);
168}
169
170void qemu_thread_signal(QemuThread *thread, int sig)
171{
172    int err;
173
174    err = pthread_kill(thread->thread, sig);
175    if (err)
176        error_exit(err, __func__);
177}
178
179void qemu_thread_self(QemuThread *thread)
180{
181    thread->thread = pthread_self();
182}
183
184int qemu_thread_equal(QemuThread *thread1, QemuThread *thread2)
185{
186   return pthread_equal(thread1->thread, thread2->thread);
187}
188
189void qemu_thread_exit(void *retval)
190{
191    pthread_exit(retval);
192}
193