threads: add one-time initialization support

mingw lacks the counterpart to PTHREAD_MUTEX_INITIALIZER, so the
best we can do is portably expose once-only runtime initialization.

* src/util/threads.h (virOnceControlPtr): New opaque type.
(virOnceFunc): New callback type.
(virOnce): New prototype.
* src/util/threads-pthread.h (virOnceControl): Declare.
(VIR_ONCE_CONTROL_INITIALIZER): Define.
* src/util/threads-win32.h (virOnceControl)
(VIR_ONCE_CONTROL_INITIALIZER): Likewise.
* src/util/threads-pthread.c (virOnce): Implement in pthreads.
* src/util/threads-win32.c (virOnce): Implement in WIN32.
* src/libvirt_private.syms: Export it.
This commit is contained in:
Eric Blake 2011-04-20 16:26:00 -06:00
parent 061956ccc7
commit 99de59900a
6 changed files with 66 additions and 4 deletions

View File

@ -866,6 +866,7 @@ virMutexInit;
virMutexInitRecursive;
virMutexLock;
virMutexUnlock;
virOnce;
virThreadCreate;
virThreadID;
virThreadIsSelf;

View File

@ -40,6 +40,11 @@ void virThreadOnExit(void)
{
}
int virOnce(virOnceControlPtr once, virOnceFunc init)
{
return pthread_once(&once->once, init);
}
int virMutexInit(virMutexPtr m)
{

View File

@ -1,7 +1,7 @@
/*
* threads.c: basic thread synchronization primitives
*
* Copyright (C) 2009 Red Hat, Inc.
* 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
@ -38,3 +38,12 @@ struct virThread {
struct virThreadLocal {
pthread_key_t key;
};
struct virOnceControl {
pthread_once_t once;
};
#define VIR_ONCE_CONTROL_INITIALIZER \
{ \
.once = PTHREAD_ONCE_INIT \
}

View File

@ -1,7 +1,7 @@
/*
* threads-win32.c: basic thread synchronization primitives
*
* Copyright (C) 2009-2010 Red Hat, Inc.
* 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
@ -69,6 +69,27 @@ void virThreadOnExit(void)
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)
{

View File

@ -1,7 +1,7 @@
/*
* threads-win32.h basic thread synchronization primitives
*
* Copyright (C) 2009 Red Hat, Inc.
* 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
@ -41,3 +41,10 @@ struct virThread {
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 }

View File

@ -1,7 +1,7 @@
/*
* threads.h: basic thread synchronization primitives
*
* Copyright (C) 2009-2010 Red Hat, Inc.
* 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
@ -36,6 +36,10 @@ typedef virThreadLocal *virThreadLocalPtr;
typedef struct virThread virThread;
typedef virThread *virThreadPtr;
typedef struct virOnceControl virOnceControl;
typedef virOnceControl *virOnceControlPtr;
typedef void (*virOnceFunc)(void);
int virThreadInitialize(void) ATTRIBUTE_RETURN_CHECK;
void virThreadOnExit(void);
@ -57,6 +61,21 @@ void virThreadJoin(virThreadPtr thread);
int virThreadSelfID(void);
int virThreadID(virThreadPtr thread);
/* Static initialization of mutexes is not possible, so we instead
* provide for guaranteed one-time initialization via a callback
* function. Usage:
* static virOnceControl once = VIR_ONCE_CONTROL_INITIALIZER;
* static void initializer(void) { ... }
* void myfunc()
* {
* if (virOnce(&once, initializer) < 0)
* goto error;
* ...now guaranteed that initializer has completed exactly once
* }
*/
int virOnce(virOnceControlPtr once, virOnceFunc init)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
int virMutexInit(virMutexPtr m) ATTRIBUTE_RETURN_CHECK;
int virMutexInitRecursive(virMutexPtr m) ATTRIBUTE_RETURN_CHECK;
void virMutexDestroy(virMutexPtr m);