]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
lib/lock: computational barrier
authorVMware, Inc <>
Mon, 26 Jul 2010 18:41:22 +0000 (11:41 -0700)
committerMarcelo Vanzin <mvanzin@vmware.com>
Mon, 26 Jul 2010 18:41:22 +0000 (11:41 -0700)
I had this code lying around and decided it doesn't hurt to have it
around.

Signed-off-by: Marcelo Vanzin <mvanzin@vmware.com>
open-vm-tools/lib/include/userlock.h
open-vm-tools/lib/lock/Makefile.am
open-vm-tools/lib/lock/ulBarrier.c [new file with mode: 0644]

index 6180cb306e80f84dfcde96d7dfe67748bfd8a655..537e6001ac30d1a51948b1aa8ba033953d396c27 100644 (file)
@@ -35,25 +35,7 @@ typedef struct MXUserRecLock    MXUserRecLock;
 typedef struct MXUserRWLock     MXUserRWLock;
 typedef struct MXUserCondVar    MXUserCondVar;
 typedef struct MXUserSemaphore  MXUserSemaphore;
-
-/*
- * Counting semaphore
- */
-
-MXUserSemaphore *MXUser_CreateSemaphore(const char *name,
-                                        MX_Rank rank);
-
-void MXUser_DestroySemaphore(MXUserSemaphore *sema);
-void MXUser_UpSemaphore(MXUserSemaphore *sema);
-void MXUser_DownSemaphore(MXUserSemaphore *sema);
-Bool MXUser_TryDownSemaphore(MXUserSemaphore *sema);
-
-Bool MXUser_TimedDownSemaphore(MXUserSemaphore *sema,
-                               uint32 msecWait);
-
-MXUserSemaphore *MXUser_CreateSingletonSemaphore(Atomic_Ptr *semaStorage,
-                                                 const char *name,
-                                                 MX_Rank rank);
+typedef struct MXUserBarrier    MXUserBarrier;
 
 /*
  * Exclusive ownership lock
@@ -139,6 +121,42 @@ MXUserRWLock *MXUser_CreateSingletonRWLock(Atomic_Ptr *lockStorage,
                                            const char *name,
                                            MX_Rank rank);
 
+/*
+ * Computational barrier
+ */
+
+MXUserBarrier *MXUser_CreateBarrier(const char *name,
+                                    MX_Rank rank,
+                                    uint32 count);
+
+void MXUser_DestroyBarrier(MXUserBarrier *barrier);
+void MXUser_EnterBarrier(MXUserBarrier *barrier);
+
+MXUserBarrier *MXUser_CreateSingletonBarrier(Atomic_Ptr *barrierStorage,
+                                             const char *name,
+                                             MX_Rank rank,
+                                             uint32 count);
+
+/*
+ * Counting semaphore
+ */
+
+MXUserSemaphore *MXUser_CreateSemaphore(const char *name,
+                                        MX_Rank rank);
+
+void MXUser_DestroySemaphore(MXUserSemaphore *sema);
+void MXUser_UpSemaphore(MXUserSemaphore *sema);
+void MXUser_DownSemaphore(MXUserSemaphore *sema);
+Bool MXUser_TryDownSemaphore(MXUserSemaphore *sema);
+
+Bool MXUser_TimedDownSemaphore(MXUserSemaphore *sema,
+                               uint32 msecWait);
+
+MXUserSemaphore *MXUser_CreateSingletonSemaphore(Atomic_Ptr *semaStorage,
+                                                 const char *name,
+                                                 MX_Rank rank);
+
+
 
 /*
  * Generic conditional variable functions.
index f8bc65fa9fb5e2073d425057a2436fb4909d7760..84d51b16597095ba0929432d005b0d01ca9fb466 100644 (file)
@@ -24,5 +24,6 @@ libLock_la_SOURCES += ulExcl.c
 libLock_la_SOURCES += ulRec.c
 libLock_la_SOURCES += ulRW.c
 libLock_la_SOURCES += ulSema.c
+libLock_la_SOURCES += ulBarrier.c
 
 AM_CFLAGS = @LIB_USER_CPPFLAGS@
diff --git a/open-vm-tools/lib/lock/ulBarrier.c b/open-vm-tools/lib/lock/ulBarrier.c
new file mode 100644 (file)
index 0000000..d72e253
--- /dev/null
@@ -0,0 +1,286 @@
+/*********************************************************
+ * Copyright (C) 2010 VMware, Inc. All rights reserved.
+ *
+ * This program 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 version 2.1 and no later version.
+ *
+ * This program 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 Lesser GNU General Public
+ * License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA.
+ *
+ *********************************************************/
+
+#include "vmware.h"
+#include "str.h"
+#include "util.h"
+#include "userlock.h"
+#include "ulInt.h"
+
+#define MXUSER_BARRIER_SIGNATURE 0x52524142 // 'BARR' in memory
+
+struct MXUserBarrier
+{
+   MXUserHeader     header;
+   MXUserExclLock  *lock;
+   Bool             emptying;
+   MXUserCondVar   *condVar;
+   uint32           configCount;   // Hold until this many threads arrive.
+   uint32           checkInCount;  // Number of threads currently in barrier
+};
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MXUserDumpBarrier --
+ *
+ *      Dump a barrier.
+ *
+ * Results:
+ *      A dump.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+static void
+MXUserDumpBarrier(MXUserHeader *header)  // IN:
+{
+   MXUserBarrier *barrier = (MXUserBarrier *) header;
+
+   Warning("%s: Barrier @ 0x%p\n", __FUNCTION__, barrier);
+
+   Warning("\tsignature 0x%X\n", barrier->header.signature);
+   Warning("\tname %s\n", barrier->header.name);
+   Warning("\trank 0x%X\n", barrier->header.rank);
+
+   Warning("\tlock %p\n", barrier->lock);
+   Warning("\tcondVar %p\n", barrier->condVar);
+
+   Warning("\tconfig count %u\n", barrier->configCount);
+   Warning("\tcheck in count %u\n", barrier->checkInCount);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MXUser_CreateBarrier --
+ *
+ *      Create a computational barrier.
+ *
+ *      The barriers are self regenerating - they do not need to be
+ *      initialized or reset after creation.
+ *
+ * Results:
+ *      A pointer to a barrier.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+MXUserBarrier *
+MXUser_CreateBarrier(const char *userName,  // IN:
+                     MX_Rank rank,          // IN:
+                     uint32 count)          // IN:
+{
+   char *properName;
+   MXUserBarrier *barrier;
+
+   ASSERT(count);
+
+   barrier = Util_SafeCalloc(1, sizeof(*barrier));
+
+   if (userName == NULL) {
+      properName = Str_SafeAsprintf(NULL, "Barrier-%p", GetReturnAddress());
+   } else {
+      properName = Util_SafeStrdup(userName);
+   }
+
+   barrier->lock = MXUser_CreateExclLock(properName, rank);
+
+   if (barrier->lock == NULL) {
+      free(properName);
+      free(barrier);
+
+      return NULL;
+   }
+
+   barrier->condVar = MXUser_CreateCondVarExclLock(barrier->lock);
+
+   if (barrier->condVar == NULL) {
+      MXUser_DestroyExclLock(barrier->lock);
+
+      free(properName);
+      free(barrier);
+
+      return NULL;
+   }
+
+   barrier->configCount = count;
+
+   barrier->header.name = properName;
+   barrier->header.signature = MXUSER_BARRIER_SIGNATURE;
+   barrier->header.rank = rank;
+   barrier->header.dumpFunc = MXUserDumpBarrier;
+
+#if defined(MXUSER_STATS)
+   barrier->header.statsFunc = NULL;
+   barrier->header.identifier = MXUserAllocID();
+#endif
+
+   return barrier;
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MXUser_DestroyBarrier --
+ *
+ *      Destroy a barrier.
+ *
+ * Results:
+ *      The barrier is destroyed. Don't try to use the pointer again.
+ *
+ * Side effects:
+ *      None
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+MXUser_DestroyBarrier(MXUserBarrier *barrier)  // IN:
+{
+   if (LIKELY(barrier != NULL)) {
+      ASSERT(barrier->header.signature == MXUSER_BARRIER_SIGNATURE);
+
+      if (barrier->checkInCount != 0) {
+         MXUserDumpAndPanic(&barrier->header,
+                            "%s: Attempted destroy on barrier while in use\n",
+                            __FUNCTION__);
+      }
+
+      MXUser_DestroyCondVar(barrier->condVar);
+      MXUser_DestroyExclLock(barrier->lock);
+
+      barrier->header.signature = 0;  // just in case...
+      free((void *) barrier->header.name);  // avoid const warnings
+      barrier->header.name = NULL;
+      free(barrier);
+   }
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MXUser_EnterBarrier --
+ *
+ *      Enter a barrier
+ *
+ *      All threads entering the barrier will be suspended until the number
+ *      threads that have entered reaches the configured number upon which
+ *      time all of the threads will return from this routine.
+ *
+ *      "Nobody comes out until everone goes in."
+ *
+ * Results:
+ *      None
+ *
+ * Side effects:
+ *      The caller may sleep.
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+void
+MXUser_EnterBarrier(MXUserBarrier *barrier)  // IN/OUT:
+{
+   ASSERT(barrier && (barrier->header.signature == MXUSER_BARRIER_SIGNATURE));
+   ASSERT(!barrier->emptying);
+
+   MXUser_AcquireExclLock(barrier->lock);
+
+   barrier->checkInCount++;
+
+   barrier->emptying = (barrier->checkInCount == barrier->configCount);
+
+   if (barrier->emptying) {
+      /* The last thread has entered; release the other threads */
+      MXUser_BroadcastCondVar(barrier->condVar);
+   } else {
+      /* Not the last thread in... sleep until the last thread appears */
+      MXUser_WaitCondVarExclLock(barrier->lock, barrier->condVar);
+   }
+
+   barrier->checkInCount--;
+
+   if (barrier->checkInCount == 0) {
+      barrier->emptying = FALSE;
+   }
+
+   MXUser_ReleaseExclLock(barrier->lock);
+}
+
+
+/*
+ *-----------------------------------------------------------------------------
+ *
+ * MXUser_CreateSingletonBarrier --
+ *
+ *      Ensures that the specified backing object (Atomic_Ptr) contains a
+ *      barrier. This is useful for modules that need to protect something
+ *      with a barrier but don't have an existing Init() entry point where a
+ *      barrier can be created.
+ *
+ * Results:
+ *      A pointer to the requested barrier.
+ *
+ * Side effects:
+ *      Generally the barrier's resources are intentionally leaked (by design).
+ *
+ *-----------------------------------------------------------------------------
+ */
+
+MXUserBarrier *
+MXUser_CreateSingletonBarrier(Atomic_Ptr *barrierStorage,  // IN/OUT:
+                              const char *name,            // IN:
+                              MX_Rank rank,                // IN:
+                              uint32 count)                // IN:
+{
+   MXUserBarrier *barrier;
+
+   ASSERT(barrierStorage);
+
+   barrier = (MXUserBarrier *) Atomic_ReadPtr(barrierStorage);
+
+   if (UNLIKELY(barrier == NULL)) {
+      MXUserBarrier *before;
+
+      barrier = MXUser_CreateBarrier(name, rank, count);
+
+      before = (MXUserBarrier *) Atomic_ReadIfEqualWritePtr(barrierStorage,
+                                                            NULL,
+                                                            (void *) barrier);
+
+      if (before) {
+         MXUser_DestroyBarrier(barrier);
+
+         barrier = before;
+      }
+   }
+
+   return barrier;
+}
+