diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a4c41e4401cc8ddc03a06fd840ddfabc3cba0455..0b9794c8fdad724360a4e9e431c71118f624ce36 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 030b33fcafbf324b986067324809ab1600a28d88..34d9ce847483defa75e8305dbe85848e0590728d 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 6404d1dccbc2ad555c738233dc3e2334e1a6f130..b25d0c20e7c18ab56c157b6f2e028563b68b2aa0 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 fe1fcd062781b18dd7a6c719422adfb943c8a3c5..de73fd56857a03a2a5bd7febec7db9c33c930fa6 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 783d91d7eb6848f5d6b0a074b397b87150399e82..bb7c455e968e63580f118abf20fe40bb69de4c6e 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 db54ea011d21638b0de6f5a3b836e94bafe4acd0..b3b827d3e538c4dff36e2ea731d12eb24edb6c8e 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);