1 /*
2 * Win32 implementation for mutex/cond/thread functions
3 *
4 * Copyright Red Hat, Inc. 2010
5 *
6 * Author:
7 * Paolo Bonzini <pbonzini@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 "qemu-common.h"
14 #include "qemu/thread.h"
15 #include <process.h>
16 #include <assert.h>
17 #include <limits.h>
18
19 #include "uc_priv.h"
20
21
error_exit(int err,const char * msg)22 static void error_exit(int err, const char *msg)
23 {
24 char *pstr;
25
26 FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
27 NULL, err, 0, (LPTSTR)&pstr, 2, NULL);
28 fprintf(stderr, "qemu: %s: %s\n", msg, pstr);
29 LocalFree(pstr);
30 //abort();
31 }
32
33 struct QemuThreadData {
34 /* Passed to win32_start_routine. */
35 void *(*start_routine)(void *);
36 void *arg;
37 short mode;
38
39 /* Only used for joinable threads. */
40 bool exited;
41 void *ret;
42 CRITICAL_SECTION cs;
43 struct uc_struct *uc;
44 };
45
win32_start_routine(void * arg)46 static unsigned __stdcall win32_start_routine(void *arg)
47 {
48 QemuThreadData *data = (QemuThreadData *) arg;
49 void *(*start_routine)(void *) = data->start_routine;
50 void *thread_arg = data->arg;
51
52 if (data->mode == QEMU_THREAD_DETACHED) {
53 data->uc->qemu_thread_data = NULL;
54 g_free(data);
55 data = NULL;
56 }
57 qemu_thread_exit(data->uc, start_routine(thread_arg));
58 abort();
59 }
60
qemu_thread_exit(struct uc_struct * uc,void * arg)61 void qemu_thread_exit(struct uc_struct *uc, void *arg)
62 {
63 QemuThreadData *data = uc->qemu_thread_data;
64
65 if (data) {
66 assert(data->mode != QEMU_THREAD_DETACHED);
67 data->ret = arg;
68 EnterCriticalSection(&data->cs);
69 data->exited = true;
70 LeaveCriticalSection(&data->cs);
71 }
72 _endthreadex(0);
73 }
74
qemu_thread_join(QemuThread * thread)75 void *qemu_thread_join(QemuThread *thread)
76 {
77 QemuThreadData *data;
78 void *ret;
79 HANDLE handle;
80
81 data = thread->data;
82 if (!data) {
83 return NULL;
84 }
85 /*
86 * Because multiple copies of the QemuThread can exist via
87 * qemu_thread_get_self, we need to store a value that cannot
88 * leak there. The simplest, non racy way is to store the TID,
89 * discard the handle that _beginthreadex gives back, and
90 * get another copy of the handle here.
91 */
92 handle = qemu_thread_get_handle(thread);
93 if (handle) {
94 WaitForSingleObject(handle, INFINITE);
95 CloseHandle(handle);
96 }
97 ret = data->ret;
98 assert(data->mode != QEMU_THREAD_DETACHED);
99 DeleteCriticalSection(&data->cs);
100 data->uc->qemu_thread_data = NULL;
101 g_free(data);
102 data = NULL;
103 return ret;
104 }
105
qemu_thread_create(struct uc_struct * uc,QemuThread * thread,const char * name,void * (* start_routine)(void *),void * arg,int mode)106 int qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *name,
107 void *(*start_routine)(void *),
108 void *arg, int mode)
109 {
110 HANDLE hThread;
111 struct QemuThreadData *data;
112
113 data = g_malloc(sizeof *data);
114 data->start_routine = start_routine;
115 data->arg = arg;
116 data->mode = mode;
117 data->exited = false;
118 data->uc = uc;
119
120 uc->qemu_thread_data = data;
121
122 if (data->mode != QEMU_THREAD_DETACHED) {
123 InitializeCriticalSection(&data->cs);
124 }
125
126 hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine,
127 data, 0, &thread->tid);
128 if (!hThread) {
129 error_exit(GetLastError(), __func__);
130 return -1;
131 }
132
133 CloseHandle(hThread);
134 thread->data = (mode == QEMU_THREAD_DETACHED) ? NULL : data;
135
136 return 0;
137 }
138
qemu_thread_get_handle(QemuThread * thread)139 HANDLE qemu_thread_get_handle(QemuThread *thread)
140 {
141 QemuThreadData *data;
142 HANDLE handle;
143
144 data = thread->data;
145 if (!data) {
146 return NULL;
147 }
148
149 assert(data->mode != QEMU_THREAD_DETACHED);
150 EnterCriticalSection(&data->cs);
151 if (!data->exited) {
152 handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME, FALSE,
153 thread->tid);
154 } else {
155 handle = NULL;
156 }
157 LeaveCriticalSection(&data->cs);
158 return handle;
159 }
160