mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-02-06 20:00:05 +00:00
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:
parent
ab6979430a
commit
0240d94c36
15
configure.ac
15
configure.ac
@ -270,12 +270,21 @@ AC_CHECK_FUNCS_ONCE([cfmakeraw fallocate geteuid getgid getgrnam_r \
|
||||
posix_memalign prlimit regexec sched_getaffinity setgroups setns \
|
||||
setrlimit symlink sysctlbyname])
|
||||
|
||||
dnl Availability of pthread functions (if missing, win32 threading is
|
||||
dnl assumed). Because of $LIB_PTHREAD, we cannot use AC_CHECK_FUNCS_ONCE.
|
||||
dnl LIB_PTHREAD and LIBMULTITHREAD were set during gl_INIT by gnulib.
|
||||
dnl Availability of pthread functions. Because of $LIB_PTHREAD, we
|
||||
dnl cannot use AC_CHECK_FUNCS_ONCE. LIB_PTHREAD and LIBMULTITHREAD
|
||||
dnl were set during gl_INIT by gnulib.
|
||||
old_LIBS=$LIBS
|
||||
LIBS="$LIBS $LIB_PTHREAD $LIBMULTITHREAD"
|
||||
|
||||
pthread_found=yes
|
||||
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 which in turn causes compilation to complain about unused variables.
|
||||
dnl Expose this broken implementation, so we can work around it.
|
||||
|
@ -141,8 +141,6 @@ UTIL_SOURCES = \
|
||||
util/virsysinfo.c util/virsysinfo.h \
|
||||
util/virsystemd.c util/virsystemd.h \
|
||||
util/virthread.c util/virthread.h \
|
||||
util/virthreadpthread.h \
|
||||
util/virthreadwin32.h \
|
||||
util/virthreadpool.c util/virthreadpool.h \
|
||||
util/virtime.h util/virtime.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 \
|
||||
<$(srcdir)/util/keymaps.csv >$(srcdir)/util/virkeymaps.h
|
||||
|
||||
EXTRA_DIST += util/virthreadpthread.c util/virthreadwin32.c
|
||||
|
||||
# Internal generic driver infrastructure
|
||||
NODE_INFO_SOURCES = nodeinfo.h nodeinfo.c nodeinfopriv.h
|
||||
DATATYPES_SOURCES = datatypes.h datatypes.c
|
||||
|
@ -23,12 +23,291 @@
|
||||
|
||||
#include "virthread.h"
|
||||
|
||||
/* On mingw, we prefer native threading over the sometimes-broken
|
||||
* pthreads-win32 library wrapper. */
|
||||
#ifdef WIN32
|
||||
# include "virthreadwin32.c"
|
||||
#elif defined HAVE_PTHREAD_MUTEXATTR_INIT
|
||||
# include "virthreadpthread.c"
|
||||
#else
|
||||
# error "Either pthreads or Win32 threads are required"
|
||||
#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;
|
||||
}
|
||||
|
@ -25,24 +25,57 @@
|
||||
# include "internal.h"
|
||||
# include "virerror.h"
|
||||
|
||||
# include <pthread.h>
|
||||
|
||||
typedef struct virMutex virMutex;
|
||||
typedef virMutex *virMutexPtr;
|
||||
|
||||
struct virMutex {
|
||||
pthread_mutex_t lock;
|
||||
};
|
||||
|
||||
typedef struct virRWLock virRWLock;
|
||||
typedef virRWLock *virRWLockPtr;
|
||||
|
||||
struct virRWLock {
|
||||
pthread_rwlock_t lock;
|
||||
};
|
||||
|
||||
|
||||
typedef struct virCond virCond;
|
||||
typedef virCond *virCondPtr;
|
||||
|
||||
struct virCond {
|
||||
pthread_cond_t cond;
|
||||
};
|
||||
|
||||
typedef struct virThreadLocal virThreadLocal;
|
||||
typedef virThreadLocal *virThreadLocalPtr;
|
||||
|
||||
struct virThreadLocal {
|
||||
pthread_key_t key;
|
||||
};
|
||||
|
||||
typedef struct virThread virThread;
|
||||
typedef virThread *virThreadPtr;
|
||||
|
||||
struct virThread {
|
||||
pthread_t thread;
|
||||
};
|
||||
|
||||
typedef struct virOnceControl virOnceControl;
|
||||
typedef virOnceControl *virOnceControlPtr;
|
||||
|
||||
struct virOnceControl {
|
||||
pthread_once_t once;
|
||||
};
|
||||
|
||||
|
||||
# define VIR_ONCE_CONTROL_INITIALIZER \
|
||||
{ \
|
||||
.once = PTHREAD_ONCE_INIT \
|
||||
}
|
||||
|
||||
typedef void (*virOnceFunc)(void);
|
||||
|
||||
int virThreadInitialize(void) ATTRIBUTE_RETURN_CHECK;
|
||||
@ -121,14 +154,6 @@ int virThreadLocalInit(virThreadLocalPtr l,
|
||||
void *virThreadLocalGet(virThreadLocalPtr l);
|
||||
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:
|
||||
|
@ -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;
|
||||
}
|
@ -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 \
|
||||
}
|
@ -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;
|
||||
}
|
@ -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 }
|
Loading…
x
Reference in New Issue
Block a user