Statistics
| Branch: | Revision:

root / qemu-thread-posix.c @ 396d2cfc

History | View | Annotate | Download (6.8 kB)

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
}