[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 3/4] qemu-thread: implement joinable threads for
From: |
Jan Kiszka |
Subject: |
Re: [Qemu-devel] [PATCH 3/4] qemu-thread: implement joinable threads for Win32 |
Date: |
Tue, 06 Dec 2011 18:39:36 +0100 |
User-agent: |
Mozilla/5.0 (X11; U; Linux i686 (x86_64); de; rv:1.8.1.12) Gecko/20080226 SUSE/2.0.0.12-1.1 Thunderbird/2.0.0.12 Mnenhy/0.7.5.666 |
On 2011-12-06 18:05, Paolo Bonzini wrote:
> Rewrite the handshaking between qemu_thread_create and the
> win32_start_routine, so that the thread can be joined without races.
> Similar handshaking is done now between qemu_thread_exit and
> qemu_thread_join.
>
> This also simplifies how QemuThreads are initialized.
>
> Signed-off-by: Paolo Bonzini <address@hidden>
> ---
> qemu-thread-win32.c | 107
> +++++++++++++++++++++++++++++++++------------------
> qemu-thread-win32.h | 5 +-
> roms/seabios | 2 +-
> 3 files changed, 73 insertions(+), 41 deletions(-)
>
> diff --git a/qemu-thread-win32.c b/qemu-thread-win32.c
> index ff80e84..a13ffcc 100644
> --- a/qemu-thread-win32.c
> +++ b/qemu-thread-win32.c
> @@ -193,41 +193,78 @@ 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);
> -
> - qemu_thread_exit(data.start_routine(data.arg));
> + QemuThreadData *data = (QemuThreadData *) arg;
> + void *(*start_routine)(void *) = data->start_routine;
> + void *thread_arg = data->arg;
> +
> + if (data->mode == QEMU_THREAD_DETACHED) {
> + g_free(data);
> + data = NULL;
> + } else {
> + InitializeCriticalSection(&data->cs);
> + }
> + 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) {
> + 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.
> + */
> + EnterCriticalSection(&data->cs);
> + if (!data->exited) {
> + handle = OpenThread(SYNCHRONIZE, FALSE, thread->tid);
> + LeaveCriticalSection(&data->cs);
> + WaitForSingleObject(handle, INFINITE);
> + CloseHandle(handle);
> + } else {
> + LeaveCriticalSection(&data->cs);
> + }
> + ret = data->ret;
> + DeleteCriticalSection(&data->cs);
> + g_free(data);
> + return ret;
> }
>
> static inline void qemu_thread_init(void)
> @@ -247,37 +284,31 @@ void qemu_thread_create(QemuThread *thread,
> {
> HANDLE hThread;
>
> - assert(mode == QEMU_THREAD_DETACHED);
> -
> 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;
>
> 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();
> }
>
> int qemu_thread_is_self(QemuThread *thread)
> {
> - QemuThread *this_thread = TlsGetValue(qemu_thread_tls_index);
> - return this_thread->thread == thread->thread;
> + return GetCurrentThreadId() == thread->tid;
> }
> diff --git a/qemu-thread-win32.h b/qemu-thread-win32.h
> index 878f86a..2983490 100644
> --- a/qemu-thread-win32.h
> +++ b/qemu-thread-win32.h
> @@ -13,9 +13,10 @@ struct QemuCond {
> HANDLE continue_event;
> };
>
> +typedef struct QemuThreadData QemuThreadData;
> struct QemuThread {
> - HANDLE thread;
> - void *ret;
> + QemuThreadData *data;
> + unsigned tid;
> };
>
> #endif
> diff --git a/roms/seabios b/roms/seabios
> index 8e30147..cc97564 160000
> --- a/roms/seabios
> +++ b/roms/seabios
> @@ -1 +1 @@
> -Subproject commit 8e301472e324b6d6496d8b4ffc66863e99d7a505
> +Subproject commit cc975646af69f279396d4d5e1379ac6af80ee637
Spurious change, I suppose. :)
Locking looks ok from the distance.
Jan
--
Siemens AG, Corporate Technology, CT T DE IT 1
Corporate Competence Center Embedded Linux
- [Qemu-devel] [PATCH 0/4] add qemu_thread_join, use it to fix bug in ccid, Paolo Bonzini, 2011/12/06
- [Qemu-devel] [PATCH 3/4] qemu-thread: implement joinable threads for Win32, Paolo Bonzini, 2011/12/06
- Re: [Qemu-devel] [PATCH 3/4] qemu-thread: implement joinable threads for Win32,
Jan Kiszka <=
- [Qemu-devel] [PATCH 1/4] qemu-thread: add API for joinable threads, Paolo Bonzini, 2011/12/06
- [Qemu-devel] [PATCH 2/4] qemu-thread: implement joinable threads for POSIX, Paolo Bonzini, 2011/12/06
- [Qemu-devel] [PATCH 4/4] ccid: make threads joinable, Paolo Bonzini, 2011/12/06
- Re: [Qemu-devel] [PATCH 0/4] add qemu_thread_join, use it to fix bug in ccid, Jan Kiszka, 2011/12/06