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