X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=qemu-thread-win32.c;h=177b398cc4fe87de9abbe5293da3a5f98c17455e;hb=af506c7036003a4a860e23e694034b9a914d1d2f;hp=a27332e669fffe0f20e98acfd31a1577c3ebb0d1;hpb=f1a7104a5f435a1bf2a1158e6f737dbd89e8c153;p=qemu.git diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c index a27332e66..177b398cc 100644 --- a/qemu-thread-win32.c +++ b/qemu-thread-win32.c @@ -24,7 +24,7 @@ static void error_exit(int err, const char *msg) NULL, err, 0, (LPTSTR)&pstr, 2, NULL); fprintf(stderr, "qemu: %s: %s\n", msg, pstr); LocalFree(pstr); - exit(1); + abort(); } void qemu_mutex_init(QemuMutex *mutex) @@ -193,41 +193,74 @@ void qemu_cond_wait(QemuCond *cond, QemuMutex *mutex) } struct QemuThreadData { - QemuThread *thread; - void *(*start_routine)(void *); - void *arg; + /* Passed to win32_start_routine. */ + void *(*start_routine)(void *); + void *arg; + short mode; + + /* Only used for joinable threads. */ + bool exited; + void *ret; + CRITICAL_SECTION cs; }; static int qemu_thread_tls_index = TLS_OUT_OF_INDEXES; static unsigned __stdcall win32_start_routine(void *arg) { - struct QemuThreadData data = *(struct QemuThreadData *) arg; - QemuThread *thread = data.thread; - - free(arg); - TlsSetValue(qemu_thread_tls_index, thread); - - /* - * Use DuplicateHandle instead of assigning thread->thread in the - * creating thread to avoid races. It's simpler this way than with - * synchronization. - */ - DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), - GetCurrentProcess(), &thread->thread, - 0, FALSE, DUPLICATE_SAME_ACCESS); + QemuThreadData *data = (QemuThreadData *) arg; + void *(*start_routine)(void *) = data->start_routine; + void *thread_arg = data->arg; - qemu_thread_exit(data.start_routine(data.arg)); + if (data->mode == QEMU_THREAD_DETACHED) { + g_free(data); + data = NULL; + } + TlsSetValue(qemu_thread_tls_index, data); + qemu_thread_exit(start_routine(thread_arg)); abort(); } void qemu_thread_exit(void *arg) { - QemuThread *thread = TlsGetValue(qemu_thread_tls_index); - thread->ret = arg; - CloseHandle(thread->thread); - thread->thread = NULL; - ExitThread(0); + QemuThreadData *data = TlsGetValue(qemu_thread_tls_index); + if (data) { + assert(data->mode != QEMU_THREAD_DETACHED); + data->ret = arg; + EnterCriticalSection(&data->cs); + data->exited = true; + LeaveCriticalSection(&data->cs); + } + _endthreadex(0); +} + +void *qemu_thread_join(QemuThread *thread) +{ + QemuThreadData *data; + void *ret; + HANDLE handle; + + data = thread->data; + if (!data) { + return NULL; + } + /* + * Because multiple copies of the QemuThread can exist via + * qemu_thread_get_self, we need to store a value that cannot + * leak there. The simplest, non racy way is to store the TID, + * discard the handle that _beginthreadex gives back, and + * get another copy of the handle here. + */ + handle = qemu_thread_get_handle(thread); + if (handle) { + WaitForSingleObject(handle, INFINITE); + CloseHandle(handle); + } + ret = data->ret; + assert(data->mode != QEMU_THREAD_DETACHED); + DeleteCriticalSection(&data->cs); + g_free(data); + return ret; } static inline void qemu_thread_init(void) @@ -243,39 +276,61 @@ static inline void qemu_thread_init(void) void qemu_thread_create(QemuThread *thread, void *(*start_routine)(void *), - void *arg) + void *arg, int mode) { HANDLE hThread; struct QemuThreadData *data; qemu_thread_init(); data = g_malloc(sizeof *data); - data->thread = thread; data->start_routine = start_routine; data->arg = arg; + data->mode = mode; + data->exited = false; + + if (data->mode != QEMU_THREAD_DETACHED) { + InitializeCriticalSection(&data->cs); + } hThread = (HANDLE) _beginthreadex(NULL, 0, win32_start_routine, - data, 0, NULL); + data, 0, &thread->tid); if (!hThread) { error_exit(GetLastError(), __func__); } CloseHandle(hThread); + thread->data = (mode == QEMU_THREAD_DETACHED) ? NULL : data; } void qemu_thread_get_self(QemuThread *thread) { - if (!thread->thread) { - /* In the main thread of the process. Initialize the QemuThread - pointer in TLS, and use the dummy GetCurrentThread handle as - the identifier for qemu_thread_is_self. */ - qemu_thread_init(); - TlsSetValue(qemu_thread_tls_index, thread); - thread->thread = GetCurrentThread(); + qemu_thread_init(); + thread->data = TlsGetValue(qemu_thread_tls_index); + thread->tid = GetCurrentThreadId(); +} + +HANDLE qemu_thread_get_handle(QemuThread *thread) +{ + QemuThreadData *data; + HANDLE handle; + + data = thread->data; + if (!data) { + return NULL; + } + + assert(data->mode != QEMU_THREAD_DETACHED); + EnterCriticalSection(&data->cs); + if (!data->exited) { + handle = OpenThread(SYNCHRONIZE | THREAD_SUSPEND_RESUME, FALSE, + thread->tid); + } else { + handle = NULL; } + LeaveCriticalSection(&data->cs); + return handle; } -int qemu_thread_is_self(QemuThread *thread) +bool qemu_thread_is_self(QemuThread *thread) { - QemuThread *this_thread = TlsGetValue(qemu_thread_tls_index); - return this_thread->thread == thread->thread; + return GetCurrentThreadId() == thread->tid; }