From 64d67507097ad109e85ec347750078d123bc517c Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Tue, 2 Nov 2010 17:17:47 +0000 Subject: [PATCH] Introduce portability APIs for creating threads The util/threads.c/h code already has APIs for mutexes, condition variables and thread locals. This commit adds in code for actually creating threads. * src/libvirt_private.syms: Export new symbols * src/util/threads.h: Define APIs virThreadCreate, virThreadSelf, virThreadIsSelf and virThreadJoin * src/util/threads-win32.c, src/util/threads-win32.h: Win32 impl of threads * src/util/threads-pthread.c, src/util/threads-pthread.h: POSIX impl of threads --- src/libvirt_private.syms | 4 ++ src/util/threads-pthread.c | 45 ++++++++++++++++++ src/util/threads-pthread.h | 4 ++ src/util/threads-win32.c | 97 +++++++++++++++++++++++++++++++++++++- src/util/threads-win32.h | 4 ++ src/util/threads.h | 15 ++++++ 6 files changed, 167 insertions(+), 2 deletions(-) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a4c41e4401..0b9794c8fd 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -722,6 +722,10 @@ virMutexInit; virMutexInitRecursive; virMutexLock; virMutexUnlock; +virThreadCreate; +virThreadIsSelf; +virThreadJoin; +virThreadSelf; # usb.h diff --git a/src/util/threads-pthread.c b/src/util/threads-pthread.c index 030b33fcaf..34d9ce8474 100644 --- a/src/util/threads-pthread.c +++ b/src/util/threads-pthread.c @@ -129,6 +129,51 @@ void virCondBroadcast(virCondPtr c) pthread_cond_broadcast(&c->cond); } +struct virThreadArgs { + virThreadFunc func; + void *opaque; +}; + +static void *virThreadHelper(void *data) +{ + struct virThreadArgs *args = data; + args->func(args->opaque); + return NULL; +} + +int virThreadCreate(virThreadPtr thread, + bool joinable, + virThreadFunc func, + void *opaque) +{ + struct virThreadArgs args = { func, opaque }; + pthread_attr_t attr; + pthread_attr_init(&attr); + if (!joinable) + pthread_attr_setdetachstate(&attr, 1); + + int ret = pthread_create(&thread->thread, &attr, virThreadHelper, &args); + if (ret != 0) { + errno = ret; + return -1; + } + return 0; +} + +void virThreadSelf(virThreadPtr thread) +{ + thread->thread = pthread_self(); +} + +bool virThreadIsSelf(virThreadPtr thread) +{ + return pthread_equal(pthread_self(), thread->thread) ? true : false; +} + +void virThreadJoin(virThreadPtr thread) +{ + pthread_join(thread->thread, NULL); +} int virThreadLocalInit(virThreadLocalPtr l, virThreadLocalCleanup c) diff --git a/src/util/threads-pthread.h b/src/util/threads-pthread.h index 6404d1dccb..b25d0c20e7 100644 --- a/src/util/threads-pthread.h +++ b/src/util/threads-pthread.h @@ -31,6 +31,10 @@ struct virCond { pthread_cond_t cond; }; +struct virThread { + pthread_t thread; +}; + struct virThreadLocal { pthread_key_t key; }; diff --git a/src/util/threads-win32.c b/src/util/threads-win32.c index fe1fcd0627..de73fd5685 100644 --- a/src/util/threads-win32.c +++ b/src/util/threads-win32.c @@ -21,6 +21,8 @@ #include +#include + #include "memory.h" struct virThreadLocalData { @@ -33,7 +35,7 @@ typedef virThreadLocalData *virThreadLocalDataPtr; virMutex virThreadLocalLock; unsigned int virThreadLocalCount = 0; virThreadLocalDataPtr virThreadLocalList = NULL; - +DWORD selfkey; virThreadLocal virCondEvent; @@ -45,7 +47,8 @@ int virThreadInitialize(void) return -1; if (virThreadLocalInit(&virCondEvent, virCondEventCleanup) < 0) return -1; - + if ((selfkey = TlsAlloc()) == TLS_OUT_OF_INDEXES) + return -1; return 0; } @@ -205,6 +208,96 @@ void virCondBroadcast(virCondPtr c) } +struct virThreadArgs { + virThreadFunc func; + void *opaque; +}; + +static void virThreadHelperDaemon(void *data) +{ + struct virThreadArgs *args = data; + virThread self; + HANDLE handle = GetCurrentThread(); + HANDLE process = GetCurrentProcess(); + + self.joinable = false; + DuplicateHandle(process, handle, process, + &self.thread, 0, FALSE, + DUPLICATE_SAME_ACCESS); + TlsSetValue(selfkey, &self); + + args->func(args->opaque); + + TlsSetValue(selfkey, NULL); + CloseHandle(self.thread); +} + +static unsigned int __stdcall virThreadHelperJoinable(void *data) +{ + struct virThreadArgs *args = data; + virThread self; + HANDLE handle = GetCurrentThread(); + HANDLE process = GetCurrentProcess(); + + self.joinable = true; + DuplicateHandle(process, handle, process, + &self.thread, 0, FALSE, + DUPLICATE_SAME_ACCESS); + TlsSetValue(selfkey, &self); + + args->func(args->opaque); + + TlsSetValue(selfkey, NULL); + CloseHandle(self.thread); + return 0; +} + +int virThreadCreate(virThreadPtr thread, + bool joinable, + virThreadFunc func, + void *opaque) +{ + struct virThreadArgs args = { func, opaque }; + thread->joinable = joinable; + if (joinable) { + thread->thread = (HANDLE)_beginthreadex(NULL, 0, + virThreadHelperJoinable, + &args, 0, NULL); + if (thread->thread == 0) + return -1; + } else { + thread->thread = (HANDLE)_beginthread(virThreadHelperDaemon, + 0, &args); + if (thread->thread == (HANDLE)-1L) + return -1; + } + return 0; +} + +void virThreadSelf(virThreadPtr thread) +{ + virThreadPtr self = TlsGetValue(selfkey); + thread->thread = self->thread; + thread->joinable = self->joinable; +} + +bool virThreadIsSelf(virThreadPtr thread) +{ + virThread self; + virThreadSelf(&self); + return self.thread == thread->thread ? true : false; +} + +void virThreadJoin(virThreadPtr thread) +{ + if (thread->joinable) { + WaitForSingleObject(thread->thread, INFINITE); + CloseHandle(thread->thread); + thread->thread = 0; + thread->joinable = false; + } +} + int virThreadLocalInit(virThreadLocalPtr l, virThreadLocalCleanup c) diff --git a/src/util/threads-win32.h b/src/util/threads-win32.h index 783d91d7eb..bb7c455e96 100644 --- a/src/util/threads-win32.h +++ b/src/util/threads-win32.h @@ -33,6 +33,10 @@ struct virCond { HANDLE *waiters; }; +struct virThread { + HANDLE thread; + bool joinable; +}; struct virThreadLocal { DWORD key; diff --git a/src/util/threads.h b/src/util/threads.h index db54ea011d..b3b827d3e5 100644 --- a/src/util/threads.h +++ b/src/util/threads.h @@ -22,6 +22,8 @@ #ifndef __THREADS_H_ # define __THREADS_H_ +# include + # include "internal.h" typedef struct virMutex virMutex; @@ -33,10 +35,23 @@ typedef virCond *virCondPtr; typedef struct virThreadLocal virThreadLocal; typedef virThreadLocal *virThreadLocalPtr; +typedef struct virThread virThread; +typedef virThread *virThreadPtr; + int virThreadInitialize(void) ATTRIBUTE_RETURN_CHECK; void virThreadOnExit(void); +typedef void (*virThreadFunc)(void *opaque); + +int virThreadCreate(virThreadPtr thread, + bool joinable, + virThreadFunc func, + void *opaque) ATTRIBUTE_RETURN_CHECK; +void virThreadSelf(virThreadPtr thread); +bool virThreadIsSelf(virThreadPtr thread); +void virThreadJoin(virThreadPtr thread); + int virMutexInit(virMutexPtr m) ATTRIBUTE_RETURN_CHECK; int virMutexInitRecursive(virMutexPtr m) ATTRIBUTE_RETURN_CHECK; void virMutexDestroy(virMutexPtr m);