Remove windows thread implementation in favour of pthreads

There are a number of pthreads impls available on Win32
these days, in particular the mingw64 project has a good
impl. Delete the native windows thread implementation and
rely on using pthreads everywhere.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
This commit is contained in:
Daniel P. Berrange 2014-01-22 16:17:10 +00:00
parent ab6979430a
commit 0240d94c36
8 changed files with 332 additions and 859 deletions

View File

@ -270,12 +270,21 @@ AC_CHECK_FUNCS_ONCE([cfmakeraw fallocate geteuid getgid getgrnam_r \
posix_memalign prlimit regexec sched_getaffinity setgroups setns \ posix_memalign prlimit regexec sched_getaffinity setgroups setns \
setrlimit symlink sysctlbyname]) setrlimit symlink sysctlbyname])
dnl Availability of pthread functions (if missing, win32 threading is dnl Availability of pthread functions. Because of $LIB_PTHREAD, we
dnl assumed). Because of $LIB_PTHREAD, we cannot use AC_CHECK_FUNCS_ONCE. dnl cannot use AC_CHECK_FUNCS_ONCE. LIB_PTHREAD and LIBMULTITHREAD
dnl LIB_PTHREAD and LIBMULTITHREAD were set during gl_INIT by gnulib. dnl were set during gl_INIT by gnulib.
old_LIBS=$LIBS old_LIBS=$LIBS
LIBS="$LIBS $LIB_PTHREAD $LIBMULTITHREAD" LIBS="$LIBS $LIB_PTHREAD $LIBMULTITHREAD"
pthread_found=yes
AC_CHECK_FUNCS([pthread_mutexattr_init]) AC_CHECK_FUNCS([pthread_mutexattr_init])
AC_CHECK_HEADER([pthread.h],,[pthread_found=no])
if test "$ac_cv_func_pthread_mutexattr_init:$pthread_found" != "yes:yes"
then
AC_MSG_ERROR([A pthreads impl is required for building libvirt])
fi
dnl At least mingw64-winpthreads #defines pthread_sigmask to 0, dnl At least mingw64-winpthreads #defines pthread_sigmask to 0,
dnl which in turn causes compilation to complain about unused variables. dnl which in turn causes compilation to complain about unused variables.
dnl Expose this broken implementation, so we can work around it. dnl Expose this broken implementation, so we can work around it.

View File

@ -141,8 +141,6 @@ UTIL_SOURCES = \
util/virsysinfo.c util/virsysinfo.h \ util/virsysinfo.c util/virsysinfo.h \
util/virsystemd.c util/virsystemd.h \ util/virsystemd.c util/virsystemd.h \
util/virthread.c util/virthread.h \ util/virthread.c util/virthread.h \
util/virthreadpthread.h \
util/virthreadwin32.h \
util/virthreadpool.c util/virthreadpool.h \ util/virthreadpool.c util/virthreadpool.h \
util/virtime.h util/virtime.c \ util/virtime.h util/virtime.c \
util/virtpm.h util/virtpm.c \ util/virtpm.h util/virtpm.c \
@ -165,8 +163,6 @@ util/virkeymaps.h: $(srcdir)/util/keymaps.csv \
$(AM_V_GEN)$(PYTHON) $(srcdir)/util/virkeycode-mapgen.py \ $(AM_V_GEN)$(PYTHON) $(srcdir)/util/virkeycode-mapgen.py \
<$(srcdir)/util/keymaps.csv >$(srcdir)/util/virkeymaps.h <$(srcdir)/util/keymaps.csv >$(srcdir)/util/virkeymaps.h
EXTRA_DIST += util/virthreadpthread.c util/virthreadwin32.c
# Internal generic driver infrastructure # Internal generic driver infrastructure
NODE_INFO_SOURCES = nodeinfo.h nodeinfo.c nodeinfopriv.h NODE_INFO_SOURCES = nodeinfo.h nodeinfo.c nodeinfopriv.h
DATATYPES_SOURCES = datatypes.h datatypes.c DATATYPES_SOURCES = datatypes.h datatypes.c

View File

@ -23,12 +23,291 @@
#include "virthread.h" #include "virthread.h"
/* On mingw, we prefer native threading over the sometimes-broken #include <unistd.h>
* pthreads-win32 library wrapper. */ #include <inttypes.h>
#ifdef WIN32 #if HAVE_SYS_SYSCALL_H
# include "virthreadwin32.c" # include <sys/syscall.h>
#elif defined HAVE_PTHREAD_MUTEXATTR_INIT
# include "virthreadpthread.c"
#else
# error "Either pthreads or Win32 threads are required"
#endif #endif
#include "viralloc.h"
/* Nothing special required for pthreads */
int virThreadInitialize(void)
{
return 0;
}
void virThreadOnExit(void)
{
}
int virOnce(virOnceControlPtr once, virOnceFunc init)
{
return pthread_once(&once->once, init);
}
int virMutexInit(virMutexPtr m)
{
int ret;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
ret = pthread_mutex_init(&m->lock, &attr);
pthread_mutexattr_destroy(&attr);
if (ret != 0) {
errno = ret;
return -1;
}
return 0;
}
int virMutexInitRecursive(virMutexPtr m)
{
int ret;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
ret = pthread_mutex_init(&m->lock, &attr);
pthread_mutexattr_destroy(&attr);
if (ret != 0) {
errno = ret;
return -1;
}
return 0;
}
void virMutexDestroy(virMutexPtr m)
{
pthread_mutex_destroy(&m->lock);
}
void virMutexLock(virMutexPtr m){
pthread_mutex_lock(&m->lock);
}
void virMutexUnlock(virMutexPtr m)
{
pthread_mutex_unlock(&m->lock);
}
int virRWLockInit(virRWLockPtr m)
{
int ret;
ret = pthread_rwlock_init(&m->lock, NULL);
if (ret != 0) {
errno = ret;
return -1;
}
return 0;
}
void virRWLockDestroy(virRWLockPtr m)
{
pthread_rwlock_destroy(&m->lock);
}
void virRWLockRead(virRWLockPtr m)
{
pthread_rwlock_rdlock(&m->lock);
}
void virRWLockWrite(virRWLockPtr m)
{
pthread_rwlock_wrlock(&m->lock);
}
void virRWLockUnlock(virRWLockPtr m)
{
pthread_rwlock_unlock(&m->lock);
}
int virCondInit(virCondPtr c)
{
int ret;
if ((ret = pthread_cond_init(&c->cond, NULL)) != 0) {
errno = ret;
return -1;
}
return 0;
}
int virCondDestroy(virCondPtr c)
{
int ret;
if ((ret = pthread_cond_destroy(&c->cond)) != 0) {
errno = ret;
return -1;
}
return 0;
}
int virCondWait(virCondPtr c, virMutexPtr m)
{
int ret;
if ((ret = pthread_cond_wait(&c->cond, &m->lock)) != 0) {
errno = ret;
return -1;
}
return 0;
}
int virCondWaitUntil(virCondPtr c, virMutexPtr m, unsigned long long whenms)
{
int ret;
struct timespec ts;
ts.tv_sec = whenms / 1000;
ts.tv_nsec = (whenms % 1000) * 1000;
if ((ret = pthread_cond_timedwait(&c->cond, &m->lock, &ts)) != 0) {
errno = ret;
return -1;
}
return 0;
}
void virCondSignal(virCondPtr c)
{
pthread_cond_signal(&c->cond);
}
void virCondBroadcast(virCondPtr c)
{
pthread_cond_broadcast(&c->cond);
}
struct virThreadArgs {
virThreadFunc func;
void *opaque;
};
static void *virThreadHelper(void *data)
{
struct virThreadArgs *args = data;
struct virThreadArgs local = *args;
/* Free args early, rather than tying it up during the entire thread. */
VIR_FREE(args);
local.func(local.opaque);
return NULL;
}
int virThreadCreate(virThreadPtr thread,
bool joinable,
virThreadFunc func,
void *opaque)
{
struct virThreadArgs *args;
pthread_attr_t attr;
int ret = -1;
int err;
if ((err = pthread_attr_init(&attr)) != 0)
goto cleanup;
if (VIR_ALLOC_QUIET(args) < 0) {
err = ENOMEM;
goto cleanup;
}
args->func = func;
args->opaque = opaque;
if (!joinable)
pthread_attr_setdetachstate(&attr, 1);
err = pthread_create(&thread->thread, &attr, virThreadHelper, args);
if (err != 0) {
VIR_FREE(args);
goto cleanup;
}
/* New thread owns 'args' in success case, so don't free */
ret = 0;
cleanup:
pthread_attr_destroy(&attr);
if (ret < 0)
errno = err;
return ret;
}
void virThreadSelf(virThreadPtr thread)
{
thread->thread = pthread_self();
}
bool virThreadIsSelf(virThreadPtr thread)
{
return pthread_equal(pthread_self(), thread->thread) ? true : false;
}
/* For debugging use only; this result is not guaranteed unique if
* pthread_t is larger than a 64-bit pointer, nor does it always match
* the pthread_self() id on Linux. */
unsigned long long virThreadSelfID(void)
{
#if defined(HAVE_SYS_SYSCALL_H) && defined(SYS_gettid)
pid_t tid = syscall(SYS_gettid);
return tid;
#else
union {
unsigned long long l;
pthread_t t;
} u;
u.t = pthread_self();
return u.l;
#endif
}
/* For debugging use only; this result is not guaranteed unique if
* pthread_t is larger than a 64-bit pointer, nor does it always match
* the thread id of virThreadSelfID on Linux. */
unsigned long long virThreadID(virThreadPtr thread)
{
union {
unsigned long long l;
pthread_t t;
} u;
u.t = thread->thread;
return u.l;
}
void virThreadJoin(virThreadPtr thread)
{
pthread_join(thread->thread, NULL);
}
void virThreadCancel(virThreadPtr thread)
{
pthread_cancel(thread->thread);
}
int virThreadLocalInit(virThreadLocalPtr l,
virThreadLocalCleanup c)
{
int ret;
if ((ret = pthread_key_create(&l->key, c)) != 0) {
errno = ret;
return -1;
}
return 0;
}
void *virThreadLocalGet(virThreadLocalPtr l)
{
return pthread_getspecific(l->key);
}
int virThreadLocalSet(virThreadLocalPtr l, void *val)
{
int err = pthread_setspecific(l->key, val);
if (err) {
errno = err;
return -1;
}
return 0;
}

View File

@ -25,24 +25,57 @@
# include "internal.h" # include "internal.h"
# include "virerror.h" # include "virerror.h"
# include <pthread.h>
typedef struct virMutex virMutex; typedef struct virMutex virMutex;
typedef virMutex *virMutexPtr; typedef virMutex *virMutexPtr;
struct virMutex {
pthread_mutex_t lock;
};
typedef struct virRWLock virRWLock; typedef struct virRWLock virRWLock;
typedef virRWLock *virRWLockPtr; typedef virRWLock *virRWLockPtr;
struct virRWLock {
pthread_rwlock_t lock;
};
typedef struct virCond virCond; typedef struct virCond virCond;
typedef virCond *virCondPtr; typedef virCond *virCondPtr;
struct virCond {
pthread_cond_t cond;
};
typedef struct virThreadLocal virThreadLocal; typedef struct virThreadLocal virThreadLocal;
typedef virThreadLocal *virThreadLocalPtr; typedef virThreadLocal *virThreadLocalPtr;
struct virThreadLocal {
pthread_key_t key;
};
typedef struct virThread virThread; typedef struct virThread virThread;
typedef virThread *virThreadPtr; typedef virThread *virThreadPtr;
struct virThread {
pthread_t thread;
};
typedef struct virOnceControl virOnceControl; typedef struct virOnceControl virOnceControl;
typedef virOnceControl *virOnceControlPtr; typedef virOnceControl *virOnceControlPtr;
struct virOnceControl {
pthread_once_t once;
};
# define VIR_ONCE_CONTROL_INITIALIZER \
{ \
.once = PTHREAD_ONCE_INIT \
}
typedef void (*virOnceFunc)(void); typedef void (*virOnceFunc)(void);
int virThreadInitialize(void) ATTRIBUTE_RETURN_CHECK; int virThreadInitialize(void) ATTRIBUTE_RETURN_CHECK;
@ -121,14 +154,6 @@ int virThreadLocalInit(virThreadLocalPtr l,
void *virThreadLocalGet(virThreadLocalPtr l); void *virThreadLocalGet(virThreadLocalPtr l);
int virThreadLocalSet(virThreadLocalPtr l, void*) ATTRIBUTE_RETURN_CHECK; int virThreadLocalSet(virThreadLocalPtr l, void*) ATTRIBUTE_RETURN_CHECK;
# ifdef WIN32
# include "virthreadwin32.h"
# elif defined HAVE_PTHREAD_MUTEXATTR_INIT
# include "virthreadpthread.h"
# else
# error "Either pthreads or Win32 threads are required"
# endif
/** /**
* VIR_ONCE_GLOBAL_INIT: * VIR_ONCE_GLOBAL_INIT:

View File

@ -1,311 +0,0 @@
/*
* virthreadpthread.c: basic thread synchronization primitives
*
* Copyright (C) 2009-2011, 2013 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
#include <config.h>
#include <unistd.h>
#include <inttypes.h>
#if HAVE_SYS_SYSCALL_H
# include <sys/syscall.h>
#endif
#include "viralloc.h"
/* Nothing special required for pthreads */
int virThreadInitialize(void)
{
return 0;
}
void virThreadOnExit(void)
{
}
int virOnce(virOnceControlPtr once, virOnceFunc init)
{
return pthread_once(&once->once, init);
}
int virMutexInit(virMutexPtr m)
{
int ret;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_NORMAL);
ret = pthread_mutex_init(&m->lock, &attr);
pthread_mutexattr_destroy(&attr);
if (ret != 0) {
errno = ret;
return -1;
}
return 0;
}
int virMutexInitRecursive(virMutexPtr m)
{
int ret;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
ret = pthread_mutex_init(&m->lock, &attr);
pthread_mutexattr_destroy(&attr);
if (ret != 0) {
errno = ret;
return -1;
}
return 0;
}
void virMutexDestroy(virMutexPtr m)
{
pthread_mutex_destroy(&m->lock);
}
void virMutexLock(virMutexPtr m){
pthread_mutex_lock(&m->lock);
}
void virMutexUnlock(virMutexPtr m)
{
pthread_mutex_unlock(&m->lock);
}
int virRWLockInit(virRWLockPtr m)
{
int ret;
ret = pthread_rwlock_init(&m->lock, NULL);
if (ret != 0) {
errno = ret;
return -1;
}
return 0;
}
void virRWLockDestroy(virRWLockPtr m)
{
pthread_rwlock_destroy(&m->lock);
}
void virRWLockRead(virRWLockPtr m)
{
pthread_rwlock_rdlock(&m->lock);
}
void virRWLockWrite(virRWLockPtr m)
{
pthread_rwlock_wrlock(&m->lock);
}
void virRWLockUnlock(virRWLockPtr m)
{
pthread_rwlock_unlock(&m->lock);
}
int virCondInit(virCondPtr c)
{
int ret;
if ((ret = pthread_cond_init(&c->cond, NULL)) != 0) {
errno = ret;
return -1;
}
return 0;
}
int virCondDestroy(virCondPtr c)
{
int ret;
if ((ret = pthread_cond_destroy(&c->cond)) != 0) {
errno = ret;
return -1;
}
return 0;
}
int virCondWait(virCondPtr c, virMutexPtr m)
{
int ret;
if ((ret = pthread_cond_wait(&c->cond, &m->lock)) != 0) {
errno = ret;
return -1;
}
return 0;
}
int virCondWaitUntil(virCondPtr c, virMutexPtr m, unsigned long long whenms)
{
int ret;
struct timespec ts;
ts.tv_sec = whenms / 1000;
ts.tv_nsec = (whenms % 1000) * 1000;
if ((ret = pthread_cond_timedwait(&c->cond, &m->lock, &ts)) != 0) {
errno = ret;
return -1;
}
return 0;
}
void virCondSignal(virCondPtr c)
{
pthread_cond_signal(&c->cond);
}
void virCondBroadcast(virCondPtr c)
{
pthread_cond_broadcast(&c->cond);
}
struct virThreadArgs {
virThreadFunc func;
void *opaque;
};
static void *virThreadHelper(void *data)
{
struct virThreadArgs *args = data;
struct virThreadArgs local = *args;
/* Free args early, rather than tying it up during the entire thread. */
VIR_FREE(args);
local.func(local.opaque);
return NULL;
}
int virThreadCreate(virThreadPtr thread,
bool joinable,
virThreadFunc func,
void *opaque)
{
struct virThreadArgs *args;
pthread_attr_t attr;
int ret = -1;
int err;
if ((err = pthread_attr_init(&attr)) != 0)
goto cleanup;
if (VIR_ALLOC_QUIET(args) < 0) {
err = ENOMEM;
goto cleanup;
}
args->func = func;
args->opaque = opaque;
if (!joinable)
pthread_attr_setdetachstate(&attr, 1);
err = pthread_create(&thread->thread, &attr, virThreadHelper, args);
if (err != 0) {
VIR_FREE(args);
goto cleanup;
}
/* New thread owns 'args' in success case, so don't free */
ret = 0;
cleanup:
pthread_attr_destroy(&attr);
if (ret < 0)
errno = err;
return ret;
}
void virThreadSelf(virThreadPtr thread)
{
thread->thread = pthread_self();
}
bool virThreadIsSelf(virThreadPtr thread)
{
return pthread_equal(pthread_self(), thread->thread) ? true : false;
}
/* For debugging use only; this result is not guaranteed unique if
* pthread_t is larger than a 64-bit pointer, nor does it always match
* the pthread_self() id on Linux. */
unsigned long long virThreadSelfID(void)
{
#if defined(HAVE_SYS_SYSCALL_H) && defined(SYS_gettid)
pid_t tid = syscall(SYS_gettid);
return tid;
#else
union {
unsigned long long l;
pthread_t t;
} u;
u.t = pthread_self();
return u.l;
#endif
}
/* For debugging use only; this result is not guaranteed unique if
* pthread_t is larger than a 64-bit pointer, nor does it always match
* the thread id of virThreadSelfID on Linux. */
unsigned long long virThreadID(virThreadPtr thread)
{
union {
unsigned long long l;
pthread_t t;
} u;
u.t = thread->thread;
return u.l;
}
void virThreadJoin(virThreadPtr thread)
{
pthread_join(thread->thread, NULL);
}
void virThreadCancel(virThreadPtr thread)
{
pthread_cancel(thread->thread);
}
int virThreadLocalInit(virThreadLocalPtr l,
virThreadLocalCleanup c)
{
int ret;
if ((ret = pthread_key_create(&l->key, c)) != 0) {
errno = ret;
return -1;
}
return 0;
}
void *virThreadLocalGet(virThreadLocalPtr l)
{
return pthread_getspecific(l->key);
}
int virThreadLocalSet(virThreadLocalPtr l, void *val)
{
int err = pthread_setspecific(l->key, val);
if (err) {
errno = err;
return -1;
}
return 0;
}

View File

@ -1,53 +0,0 @@
/*
* virthreadpthread.c: basic thread synchronization primitives
*
* Copyright (C) 2009, 2011 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
#include "internal.h"
#include <pthread.h>
struct virMutex {
pthread_mutex_t lock;
};
struct virRWLock {
pthread_rwlock_t lock;
};
struct virCond {
pthread_cond_t cond;
};
struct virThread {
pthread_t thread;
};
struct virThreadLocal {
pthread_key_t key;
};
struct virOnceControl {
pthread_once_t once;
};
#define VIR_ONCE_CONTROL_INITIALIZER \
{ \
.once = PTHREAD_ONCE_INIT \
}

View File

@ -1,415 +0,0 @@
/*
* virthreadwin32.c: basic thread synchronization primitives
*
* Copyright (C) 2009-2011, 2013 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
#include <config.h>
#include <process.h>
#include "viralloc.h"
#define VIR_FROM_THIS VIR_FROM_NONE
struct virThreadLocalData {
DWORD key;
virThreadLocalCleanup cleanup;
};
typedef struct virThreadLocalData virThreadLocalData;
typedef virThreadLocalData *virThreadLocalDataPtr;
virMutex virThreadLocalLock;
size_t virThreadLocalCount = 0;
virThreadLocalDataPtr virThreadLocalList = NULL;
DWORD selfkey;
virThreadLocal virCondEvent;
void virCondEventCleanup(void *data);
int virThreadInitialize(void)
{
if (virMutexInit(&virThreadLocalLock) < 0)
return -1;
if (virThreadLocalInit(&virCondEvent, virCondEventCleanup) < 0)
return -1;
if ((selfkey = TlsAlloc()) == TLS_OUT_OF_INDEXES)
return -1;
return 0;
}
void virThreadOnExit(void)
{
size_t i;
virMutexLock(&virThreadLocalLock);
for (i = 0; i < virThreadLocalCount; i++) {
if (virThreadLocalList[i].cleanup) {
void *data = TlsGetValue(virThreadLocalList[i].key);
if (data) {
TlsSetValue(virThreadLocalList[i].key, NULL);
(virThreadLocalList[i].cleanup)(data);
}
}
}
virMutexUnlock(&virThreadLocalLock);
}
int virOnce(virOnceControlPtr once, virOnceFunc func)
{
if (!once->complete) {
if (InterlockedIncrement(&once->init) == 1) {
/* We're the first thread. */
func();
once->complete = 1;
} else {
/* We're a later thread. Decrement the init counter back
* to avoid overflow, then yield until the first thread
* marks that the function is complete. It is rare that
* multiple threads will be waiting here, and since each
* thread is yielding except the first, we should get out
* soon enough. */
InterlockedDecrement(&once->init);
while (!once->complete)
Sleep(0);
}
}
return 0;
}
int virMutexInit(virMutexPtr m)
{
return virMutexInitRecursive(m);
}
int virMutexInitRecursive(virMutexPtr m)
{
if (!(m->lock = CreateMutex(NULL, FALSE, NULL))) {
errno = ESRCH;
return -1;
}
return 0;
}
void virMutexDestroy(virMutexPtr m)
{
CloseHandle(m->lock);
}
void virMutexLock(virMutexPtr m)
{
WaitForSingleObject(m->lock, INFINITE);
}
void virMutexUnlock(virMutexPtr m)
{
ReleaseMutex(m->lock);
}
int virRWLockInit(virRWLockPtr m ATTRIBUTE_UNUSED)
{
errno = ENOSYS;
return -1;
}
void virRWLockDestroy(virRWLockPtr m ATTRIBUTE_UNUSED)
{}
void virRWLockRead(virRWLockPtr m ATTRIBUTE_UNUSED)
{}
void virRWLockWrite(virRWLockPtr m ATTRIBUTE_UNUSED)
{}
void virRWLockUnlock(virRWLockPtr m ATTRIBUTE_UNUSED)
{}
int virCondInit(virCondPtr c)
{
c->waiters = NULL;
if (virMutexInit(&c->lock) < 0)
return -1;
return 0;
}
int virCondDestroy(virCondPtr c)
{
if (c->waiters) {
errno = EINVAL;
return -1;
}
virMutexDestroy(&c->lock);
return 0;
}
void virCondEventCleanup(void *data)
{
HANDLE event = data;
CloseHandle(event);
}
int virCondWait(virCondPtr c, virMutexPtr m)
{
HANDLE event = virThreadLocalGet(&virCondEvent);
if (!event) {
event = CreateEvent(0, FALSE, FALSE, NULL);
if (!event) {
return -1;
}
if (virThreadLocalSet(&virCondEvent, event) < 0) {
CloseHandle(event);
return -1;
}
}
virMutexLock(&c->lock);
if (VIR_REALLOC_N(c->waiters, c->nwaiters + 1) < 0) {
virMutexUnlock(&c->lock);
return -1;
}
c->waiters[c->nwaiters] = event;
c->nwaiters++;
virMutexUnlock(&c->lock);
virMutexUnlock(m);
if (WaitForSingleObject(event, INFINITE) == WAIT_FAILED) {
virMutexLock(m);
errno = EINVAL;
return -1;
}
virMutexLock(m);
return 0;
}
int virCondWaitUntil(virCondPtr c ATTRIBUTE_UNUSED,
virMutexPtr m ATTRIBUTE_UNUSED,
unsigned long long whenms ATTRIBUTE_UNUSED)
{
/* FIXME: this function is currently only used by the QEMU driver that
* is not compiled on Windows, so it's okay for now to just
* miss an implementation */
return -1;
}
void virCondSignal(virCondPtr c)
{
virMutexLock(&c->lock);
if (c->nwaiters) {
HANDLE event = c->waiters[0];
if (c->nwaiters > 1)
memmove(c->waiters,
c->waiters + 1,
sizeof(c->waiters[0]) * (c->nwaiters-1));
if (VIR_REALLOC_N(c->waiters, c->nwaiters - 1) < 0) {
;
}
c->nwaiters--;
SetEvent(event);
}
virMutexUnlock(&c->lock);
}
void virCondBroadcast(virCondPtr c)
{
virMutexLock(&c->lock);
if (c->nwaiters) {
size_t i;
for (i = 0; i < c->nwaiters; i++) {
HANDLE event = c->waiters[i];
SetEvent(event);
}
VIR_FREE(c->waiters);
c->nwaiters = 0;
}
virMutexUnlock(&c->lock);
}
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);
VIR_FREE(args);
}
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);
VIR_FREE(args);
return 0;
}
int virThreadCreate(virThreadPtr thread,
bool joinable,
virThreadFunc func,
void *opaque)
{
struct virThreadArgs *args;
uintptr_t ret;
if (VIR_ALLOC(args) < 0)
return -1;
args->func = func;
args->opaque = opaque;
thread->joinable = joinable;
if (joinable) {
ret = _beginthreadex(NULL, 0,
virThreadHelperJoinable,
args, 0, NULL);
if (ret == 0)
return -1;
} else {
ret = _beginthread(virThreadHelperDaemon,
0, args);
if (ret == -1L)
return -1;
}
thread->thread = (HANDLE)ret;
return 0;
}
void virThreadSelf(virThreadPtr thread)
{
virThreadPtr self = TlsGetValue(selfkey);
if (self == NULL) {
/* called on a thread not created by virThreadCreate, e.g. the main thread */
thread->thread = 0;
thread->joinable = false;
} else {
thread->thread = self->thread;
thread->joinable = self->joinable;
}
}
bool virThreadIsSelf(virThreadPtr thread)
{
virThread self;
virThreadSelf(&self);
return self.thread == thread->thread ? true : false;
}
/* For debugging use only; see comments in virthreadpthread.c. */
unsigned long long virThreadSelfID(void)
{
return GetCurrentThreadId();
}
/* For debugging use only; see comments in virthreadpthread.c. */
unsigned long long virThreadID(virThreadPtr thread)
{
return (intptr_t)thread->thread;
}
void virThreadJoin(virThreadPtr thread)
{
if (thread->joinable) {
WaitForSingleObject(thread->thread, INFINITE);
CloseHandle(thread->thread);
thread->thread = 0;
thread->joinable = false;
}
}
void virThreadCancel(virThreadPtr thread ATTRIBUTE_UNUSED)
{}
int virThreadLocalInit(virThreadLocalPtr l,
virThreadLocalCleanup c)
{
if ((l->key = TlsAlloc()) == TLS_OUT_OF_INDEXES) {
errno = ESRCH;
return -1;
}
TlsSetValue(l->key, NULL);
if (c) {
virMutexLock(&virThreadLocalLock);
if (VIR_REALLOC_N(virThreadLocalList,
virThreadLocalCount + 1) < 0)
return -1;
virThreadLocalList[virThreadLocalCount].key = l->key;
virThreadLocalList[virThreadLocalCount].cleanup = c;
virThreadLocalCount++;
virMutexUnlock(&virThreadLocalLock);
}
return 0;
}
void *virThreadLocalGet(virThreadLocalPtr l)
{
return TlsGetValue(l->key);
}
int virThreadLocalSet(virThreadLocalPtr l, void *val)
{
return TlsSetValue(l->key, val) == 0 ? -1 : 0;
}

View File

@ -1,57 +0,0 @@
/*
* virthreadwin32.h basic thread synchronization primitives
*
* Copyright (C) 2009, 2011-2012 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see
* <http://www.gnu.org/licenses/>.
*
*/
#include "internal.h"
#ifdef HAVE_WINSOCK2_H
# include <winsock2.h>
#endif
#include <windows.h>
struct virMutex {
HANDLE lock;
};
struct virRWLock {
bool ignored;
};
struct virCond {
virMutex lock;
size_t nwaiters;
HANDLE *waiters;
};
struct virThread {
HANDLE thread;
bool joinable;
};
struct virThreadLocal {
DWORD key;
};
struct virOnceControl {
volatile long init; /* 0 at startup, > 0 if init has started */
volatile long complete; /* 0 until first thread completes callback */
};
#define VIR_ONCE_CONTROL_INITIALIZER { 0, 0 }