Statistics
| Branch: | Revision:

root / qemu-thread-win32.c @ 92f562ec

History | View | Annotate | Download (7.6 kB)

1 9257d46d Paolo Bonzini
/*
2 9257d46d Paolo Bonzini
 * Win32 implementation for mutex/cond/thread functions
3 9257d46d Paolo Bonzini
 *
4 9257d46d Paolo Bonzini
 * Copyright Red Hat, Inc. 2010
5 9257d46d Paolo Bonzini
 *
6 9257d46d Paolo Bonzini
 * Author:
7 9257d46d Paolo Bonzini
 *  Paolo Bonzini <pbonzini@redhat.com>
8 9257d46d Paolo Bonzini
 *
9 9257d46d Paolo Bonzini
 * This work is licensed under the terms of the GNU GPL, version 2 or later.
10 9257d46d Paolo Bonzini
 * See the COPYING file in the top-level directory.
11 9257d46d Paolo Bonzini
 *
12 9257d46d Paolo Bonzini
 */
13 9257d46d Paolo Bonzini
#include "qemu-common.h"
14 9257d46d Paolo Bonzini
#include "qemu-thread.h"
15 9257d46d Paolo Bonzini
#include <process.h>
16 9257d46d Paolo Bonzini
#include <assert.h>
17 9257d46d Paolo Bonzini
#include <limits.h>
18 9257d46d Paolo Bonzini
19 9257d46d Paolo Bonzini
static void error_exit(int err, const char *msg)
20 9257d46d Paolo Bonzini
{
21 9257d46d Paolo Bonzini
    char *pstr;
22 9257d46d Paolo Bonzini
23 9257d46d Paolo Bonzini
    FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
24 9257d46d Paolo Bonzini
                  NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
25 9257d46d Paolo Bonzini
    fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
26 9257d46d Paolo Bonzini
    LocalFree(pstr);
27 9257d46d Paolo Bonzini
    exit(1);
28 9257d46d Paolo Bonzini
}
29 9257d46d Paolo Bonzini
30 9257d46d Paolo Bonzini
void qemu_mutex_init(QemuMutex *mutex)
31 9257d46d Paolo Bonzini
{
32 9257d46d Paolo Bonzini
    mutex->owner = 0;
33 9257d46d Paolo Bonzini
    InitializeCriticalSection(&mutex->lock);
34 9257d46d Paolo Bonzini
}
35 9257d46d Paolo Bonzini
36 1a290aea Stefan Weil
void qemu_mutex_destroy(QemuMutex *mutex)
37 1a290aea Stefan Weil
{
38 1a290aea Stefan Weil
    assert(mutex->owner == 0);
39 1a290aea Stefan Weil
    DeleteCriticalSection(&mutex->lock);
40 1a290aea Stefan Weil
}
41 1a290aea Stefan Weil
42 9257d46d Paolo Bonzini
void qemu_mutex_lock(QemuMutex *mutex)
43 9257d46d Paolo Bonzini
{
44 9257d46d Paolo Bonzini
    EnterCriticalSection(&mutex->lock);
45 9257d46d Paolo Bonzini
46 9257d46d Paolo Bonzini
    /* Win32 CRITICAL_SECTIONs are recursive.  Assert that we're not
47 9257d46d Paolo Bonzini
     * using them as such.
48 9257d46d Paolo Bonzini
     */
49 9257d46d Paolo Bonzini
    assert(mutex->owner == 0);
50 9257d46d Paolo Bonzini
    mutex->owner = GetCurrentThreadId();
51 9257d46d Paolo Bonzini
}
52 9257d46d Paolo Bonzini
53 9257d46d Paolo Bonzini
int qemu_mutex_trylock(QemuMutex *mutex)
54 9257d46d Paolo Bonzini
{
55 9257d46d Paolo Bonzini
    int owned;
56 9257d46d Paolo Bonzini
57 9257d46d Paolo Bonzini
    owned = TryEnterCriticalSection(&mutex->lock);
58 9257d46d Paolo Bonzini
    if (owned) {
59 9257d46d Paolo Bonzini
        assert(mutex->owner == 0);
60 9257d46d Paolo Bonzini
        mutex->owner = GetCurrentThreadId();
61 9257d46d Paolo Bonzini
    }
62 9257d46d Paolo Bonzini
    return !owned;
63 9257d46d Paolo Bonzini
}
64 9257d46d Paolo Bonzini
65 9257d46d Paolo Bonzini
void qemu_mutex_unlock(QemuMutex *mutex)
66 9257d46d Paolo Bonzini
{
67 9257d46d Paolo Bonzini
    assert(mutex->owner == GetCurrentThreadId());
68 9257d46d Paolo Bonzini
    mutex->owner = 0;
69 9257d46d Paolo Bonzini
    LeaveCriticalSection(&mutex->lock);
70 9257d46d Paolo Bonzini
}
71 9257d46d Paolo Bonzini
72 9257d46d Paolo Bonzini
void qemu_cond_init(QemuCond *cond)
73 9257d46d Paolo Bonzini
{
74 9257d46d Paolo Bonzini
    memset(cond, 0, sizeof(*cond));
75 9257d46d Paolo Bonzini
76 9257d46d Paolo Bonzini
    cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL);
77 9257d46d Paolo Bonzini
    if (!cond->sema) {
78 9257d46d Paolo Bonzini
        error_exit(GetLastError(), __func__);
79 9257d46d Paolo Bonzini
    }
80 9257d46d Paolo Bonzini
    cond->continue_event = CreateEvent(NULL,    /* security */
81 9257d46d Paolo Bonzini
                                       FALSE,   /* auto-reset */
82 9257d46d Paolo Bonzini
                                       FALSE,   /* not signaled */
83 9257d46d Paolo Bonzini
                                       NULL);   /* name */
84 9257d46d Paolo Bonzini
    if (!cond->continue_event) {
85 9257d46d Paolo Bonzini
        error_exit(GetLastError(), __func__);
86 9257d46d Paolo Bonzini
    }
87 9257d46d Paolo Bonzini
}
88 9257d46d Paolo Bonzini
89 1a290aea Stefan Weil
void qemu_cond_destroy(QemuCond *cond)
90 1a290aea Stefan Weil
{
91 1a290aea Stefan Weil
    BOOL result;
92 1a290aea Stefan Weil
    result = CloseHandle(cond->continue_event);
93 1a290aea Stefan Weil
    if (!result) {
94 1a290aea Stefan Weil
        error_exit(GetLastError(), __func__);
95 1a290aea Stefan Weil
    }
96 1a290aea Stefan Weil
    cond->continue_event = 0;
97 1a290aea Stefan Weil
    result = CloseHandle(cond->sema);
98 1a290aea Stefan Weil
    if (!result) {
99 1a290aea Stefan Weil
        error_exit(GetLastError(), __func__);
100 1a290aea Stefan Weil
    }
101 1a290aea Stefan Weil
    cond->sema = 0;
102 1a290aea Stefan Weil
}
103 1a290aea Stefan Weil
104 9257d46d Paolo Bonzini
void qemu_cond_signal(QemuCond *cond)
105 9257d46d Paolo Bonzini
{
106 9257d46d Paolo Bonzini
    DWORD result;
107 9257d46d Paolo Bonzini
108 9257d46d Paolo Bonzini
    /*
109 9257d46d Paolo Bonzini
     * Signal only when there are waiters.  cond->waiters is
110 9257d46d Paolo Bonzini
     * incremented by pthread_cond_wait under the external lock,
111 9257d46d Paolo Bonzini
     * so we are safe about that.
112 9257d46d Paolo Bonzini
     */
113 9257d46d Paolo Bonzini
    if (cond->waiters == 0) {
114 9257d46d Paolo Bonzini
        return;
115 9257d46d Paolo Bonzini
    }
116 9257d46d Paolo Bonzini
117 9257d46d Paolo Bonzini
    /*
118 9257d46d Paolo Bonzini
     * Waiting threads decrement it outside the external lock, but
119 9257d46d Paolo Bonzini
     * only if another thread is executing pthread_cond_broadcast and
120 9257d46d Paolo Bonzini
     * has the mutex.  So, it also cannot be decremented concurrently
121 9257d46d Paolo Bonzini
     * with this particular access.
122 9257d46d Paolo Bonzini
     */
123 9257d46d Paolo Bonzini
    cond->target = cond->waiters - 1;
124 9257d46d Paolo Bonzini
    result = SignalObjectAndWait(cond->sema, cond->continue_event,
125 9257d46d Paolo Bonzini
                                 INFINITE, FALSE);
126 9257d46d Paolo Bonzini
    if (result == WAIT_ABANDONED || result == WAIT_FAILED) {
127 9257d46d Paolo Bonzini
        error_exit(GetLastError(), __func__);
128 9257d46d Paolo Bonzini
    }
129 9257d46d Paolo Bonzini
}
130 9257d46d Paolo Bonzini
131 9257d46d Paolo Bonzini
void qemu_cond_broadcast(QemuCond *cond)
132 9257d46d Paolo Bonzini
{
133 9257d46d Paolo Bonzini
    BOOLEAN result;
134 9257d46d Paolo Bonzini
    /*
135 9257d46d Paolo Bonzini
     * As in pthread_cond_signal, access to cond->waiters and
136 9257d46d Paolo Bonzini
     * cond->target is locked via the external mutex.
137 9257d46d Paolo Bonzini
     */
138 9257d46d Paolo Bonzini
    if (cond->waiters == 0) {
139 9257d46d Paolo Bonzini
        return;
140 9257d46d Paolo Bonzini
    }
141 9257d46d Paolo Bonzini
142 9257d46d Paolo Bonzini
    cond->target = 0;
143 9257d46d Paolo Bonzini
    result = ReleaseSemaphore(cond->sema, cond->waiters, NULL);
144 9257d46d Paolo Bonzini
    if (!result) {
145 9257d46d Paolo Bonzini
        error_exit(GetLastError(), __func__);
146 9257d46d Paolo Bonzini
    }
147 9257d46d Paolo Bonzini
148 9257d46d Paolo Bonzini
    /*
149 9257d46d Paolo Bonzini
     * At this point all waiters continue. Each one takes its
150 9257d46d Paolo Bonzini
     * slice of the semaphore. Now it's our turn to wait: Since
151 9257d46d Paolo Bonzini
     * the external mutex is held, no thread can leave cond_wait,
152 9257d46d Paolo Bonzini
     * yet. For this reason, we can be sure that no thread gets
153 9257d46d Paolo Bonzini
     * a chance to eat *more* than one slice. OTOH, it means
154 9257d46d Paolo Bonzini
     * that the last waiter must send us a wake-up.
155 9257d46d Paolo Bonzini
     */
156 9257d46d Paolo Bonzini
    WaitForSingleObject(cond->continue_event, INFINITE);
157 9257d46d Paolo Bonzini
}
158 9257d46d Paolo Bonzini
159 9257d46d Paolo Bonzini
void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex)
160 9257d46d Paolo Bonzini
{
161 9257d46d Paolo Bonzini
    /*
162 9257d46d Paolo Bonzini
     * This access is protected under the mutex.
163 9257d46d Paolo Bonzini
     */
164 9257d46d Paolo Bonzini
    cond->waiters++;
165 9257d46d Paolo Bonzini
166 9257d46d Paolo Bonzini
    /*
167 9257d46d Paolo Bonzini
     * Unlock external mutex and wait for signal.
168 9257d46d Paolo Bonzini
     * NOTE: we've held mutex locked long enough to increment
169 9257d46d Paolo Bonzini
     * waiters count above, so there's no problem with
170 9257d46d Paolo Bonzini
     * leaving mutex unlocked before we wait on semaphore.
171 9257d46d Paolo Bonzini
     */
172 9257d46d Paolo Bonzini
    qemu_mutex_unlock(mutex);
173 9257d46d Paolo Bonzini
    WaitForSingleObject(cond->sema, INFINITE);
174 9257d46d Paolo Bonzini
175 9257d46d Paolo Bonzini
    /* Now waiters must rendez-vous with the signaling thread and
176 9257d46d Paolo Bonzini
     * let it continue.  For cond_broadcast this has heavy contention
177 9257d46d Paolo Bonzini
     * and triggers thundering herd.  So goes life.
178 9257d46d Paolo Bonzini
     *
179 9257d46d Paolo Bonzini
     * Decrease waiters count.  The mutex is not taken, so we have
180 9257d46d Paolo Bonzini
     * to do this atomically.
181 9257d46d Paolo Bonzini
     *
182 9257d46d Paolo Bonzini
     * All waiters contend for the mutex at the end of this function
183 9257d46d Paolo Bonzini
     * until the signaling thread relinquishes it.  To ensure
184 9257d46d Paolo Bonzini
     * each waiter consumes exactly one slice of the semaphore,
185 9257d46d Paolo Bonzini
     * the signaling thread stops until it is told by the last
186 9257d46d Paolo Bonzini
     * waiter that it can go on.
187 9257d46d Paolo Bonzini
     */
188 9257d46d Paolo Bonzini
    if (InterlockedDecrement(&cond->waiters) == cond->target) {
189 9257d46d Paolo Bonzini
        SetEvent(cond->continue_event);
190 9257d46d Paolo Bonzini
    }
191 9257d46d Paolo Bonzini
192 9257d46d Paolo Bonzini
    qemu_mutex_lock(mutex);
193 9257d46d Paolo Bonzini
}
194 9257d46d Paolo Bonzini
195 9257d46d Paolo Bonzini
struct QemuThreadData {
196 9257d46d Paolo Bonzini
    QemuThread *thread;
197 9257d46d Paolo Bonzini
    void *(*start_routine)(void *);
198 9257d46d Paolo Bonzini
    void *arg;
199 9257d46d Paolo Bonzini
};
200 9257d46d Paolo Bonzini
201 9257d46d Paolo Bonzini
static int qemu_thread_tls_index = TLS_OUT_OF_INDEXES;
202 9257d46d Paolo Bonzini
203 9257d46d Paolo Bonzini
static unsigned __stdcall win32_start_routine(void *arg)
204 9257d46d Paolo Bonzini
{
205 9257d46d Paolo Bonzini
    struct QemuThreadData data = *(struct QemuThreadData *) arg;
206 9257d46d Paolo Bonzini
    QemuThread *thread = data.thread;
207 9257d46d Paolo Bonzini
208 9257d46d Paolo Bonzini
    free(arg);
209 9257d46d Paolo Bonzini
    TlsSetValue(qemu_thread_tls_index, thread);
210 9257d46d Paolo Bonzini
211 9257d46d Paolo Bonzini
    /*
212 9257d46d Paolo Bonzini
     * Use DuplicateHandle instead of assigning thread->thread in the
213 9257d46d Paolo Bonzini
     * creating thread to avoid races.  It's simpler this way than with
214 9257d46d Paolo Bonzini
     * synchronization.
215 9257d46d Paolo Bonzini
     */
216 9257d46d Paolo Bonzini
    DuplicateHandle(GetCurrentProcess(), GetCurrentThread(),
217 9257d46d Paolo Bonzini
                    GetCurrentProcess(), &thread->thread,
218 9257d46d Paolo Bonzini
                    0, FALSE, DUPLICATE_SAME_ACCESS);
219 9257d46d Paolo Bonzini
220 9257d46d Paolo Bonzini
    qemu_thread_exit(data.start_routine(data.arg));
221 9257d46d Paolo Bonzini
    abort();
222 9257d46d Paolo Bonzini
}
223 9257d46d Paolo Bonzini
224 9257d46d Paolo Bonzini
void qemu_thread_exit(void *arg)
225 9257d46d Paolo Bonzini
{
226 9257d46d Paolo Bonzini
    QemuThread *thread = TlsGetValue(qemu_thread_tls_index);
227 9257d46d Paolo Bonzini
    thread->ret = arg;
228 9257d46d Paolo Bonzini
    CloseHandle(thread->thread);
229 9257d46d Paolo Bonzini
    thread->thread = NULL;
230 9257d46d Paolo Bonzini
    ExitThread(0);
231 9257d46d Paolo Bonzini
}
232 9257d46d Paolo Bonzini
233 9257d46d Paolo Bonzini
static inline void qemu_thread_init(void)
234 9257d46d Paolo Bonzini
{
235 9257d46d Paolo Bonzini
    if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) {
236 9257d46d Paolo Bonzini
        qemu_thread_tls_index = TlsAlloc();
237 9257d46d Paolo Bonzini
        if (qemu_thread_tls_index == TLS_OUT_OF_INDEXES) {
238 9257d46d Paolo Bonzini
            error_exit(ERROR_NO_SYSTEM_RESOURCES, __func__);
239 9257d46d Paolo Bonzini
        }
240 9257d46d Paolo Bonzini
    }
241 9257d46d Paolo Bonzini
}
242 9257d46d Paolo Bonzini
243 9257d46d Paolo Bonzini
244 9257d46d Paolo Bonzini
void qemu_thread_create(QemuThread *thread,
245 9257d46d Paolo Bonzini
                       void *(*start_routine)(void *),
246 9257d46d Paolo Bonzini
                       void *arg)
247 9257d46d Paolo Bonzini
{
248 9257d46d Paolo Bonzini
    HANDLE hThread;
249 9257d46d Paolo Bonzini
250 9257d46d Paolo Bonzini
    struct QemuThreadData *data;
251 9257d46d Paolo Bonzini
    qemu_thread_init();
252 7267c094 Anthony Liguori
    data = g_malloc(sizeof *data);
253 9257d46d Paolo Bonzini
    data->thread = thread;
254 9257d46d Paolo Bonzini
    data->start_routine = start_routine;
255 9257d46d Paolo Bonzini
    data->arg = arg;
256 9257d46d Paolo Bonzini
257 9257d46d Paolo Bonzini
    hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
258 9257d46d Paolo Bonzini
                                      data, 0, NULL);
259 9257d46d Paolo Bonzini
    if (!hThread) {
260 9257d46d Paolo Bonzini
        error_exit(GetLastError(), __func__);
261 9257d46d Paolo Bonzini
    }
262 9257d46d Paolo Bonzini
    CloseHandle(hThread);
263 9257d46d Paolo Bonzini
}
264 9257d46d Paolo Bonzini
265 9257d46d Paolo Bonzini
void qemu_thread_get_self(QemuThread *thread)
266 9257d46d Paolo Bonzini
{
267 9257d46d Paolo Bonzini
    if (!thread->thread) {
268 9257d46d Paolo Bonzini
        /* In the main thread of the process.  Initialize the QemuThread
269 9257d46d Paolo Bonzini
           pointer in TLS, and use the dummy GetCurrentThread handle as
270 9257d46d Paolo Bonzini
           the identifier for qemu_thread_is_self.  */
271 9257d46d Paolo Bonzini
        qemu_thread_init();
272 9257d46d Paolo Bonzini
        TlsSetValue(qemu_thread_tls_index, thread);
273 9257d46d Paolo Bonzini
        thread->thread = GetCurrentThread();
274 9257d46d Paolo Bonzini
    }
275 9257d46d Paolo Bonzini
}
276 9257d46d Paolo Bonzini
277 9257d46d Paolo Bonzini
int qemu_thread_is_self(QemuThread *thread)
278 9257d46d Paolo Bonzini
{
279 9257d46d Paolo Bonzini
    QemuThread *this_thread = TlsGetValue(qemu_thread_tls_index);
280 9257d46d Paolo Bonzini
    return this_thread->thread == thread->thread;
281 9257d46d Paolo Bonzini
}