]> xenbits.xensource.com Git - libvirt.git/commitdiff
threads: add one-time initialization support
authorEric Blake <eblake@redhat.com>
Wed, 20 Apr 2011 22:26:00 +0000 (16:26 -0600)
committerEric Blake <eblake@redhat.com>
Mon, 25 Apr 2011 14:53:09 +0000 (08:53 -0600)
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.

src/libvirt_private.syms
src/util/threads-pthread.c
src/util/threads-pthread.h
src/util/threads-win32.c
src/util/threads-win32.h
src/util/threads.h

index ba7739dd1d82a2543b5d4190e5d89c25f65c4ff2..cb67861a36a0dfd8c0f83eea0762cc6a20c5cc6d 100644 (file)
@@ -866,6 +866,7 @@ virMutexInit;
 virMutexInitRecursive;
 virMutexLock;
 virMutexUnlock;
+virOnce;
 virThreadCreate;
 virThreadID;
 virThreadIsSelf;
index 898c4d48b08e20062572248f8f0139771060f508..82ce5c6ee8bde44c994bf20e80d9ba5680f5467a 100644 (file)
@@ -40,6 +40,11 @@ void virThreadOnExit(void)
 {
 }
 
+int virOnce(virOnceControlPtr once, virOnceFunc init)
+{
+    return pthread_once(&once->once, init);
+}
+
 
 int virMutexInit(virMutexPtr m)
 {
index b25d0c20e7c18ab56c157b6f2e028563b68b2aa0..dcaacb7d1474684d07adf3fa75a3537728e4f29b 100644 (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        \
+}
index 566143793fdedf413ef01dafea26103154e1c534..63f699b2fe4a0375018d9c3689d01fd1365aaf58 100644 (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)
 {
index bb7c455e968e63580f118abf20fe40bb69de4c6e..8109afd271595845423a66d19c1ea247b43d7072 100644 (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 }
index c129301545d88883146747393219178d2a472f75..b72610cf7a18e472b02dc2c119f9fda800d4b650 100644 (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);