As @nyh noted in #823 gcc 4.8 doesn't like both using and redefining
pthread_mutex_lock in the same file. This is a workaround for what
seems to be a compiler bug. The code using pthread_mutex_lock/unlock
(pthread_barrier_* functions) is moved to a new .cc file.

Fixes #823

Signed-off-by: Justin Cinkelj <[email protected]>
---
 Makefile                |   1 +
 libc/pthread.cc         | 116 +-------------------------------------------
 libc/pthread_barrier.cc | 126 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 128 insertions(+), 115 deletions(-)
 create mode 100644 libc/pthread_barrier.cc

diff --git a/Makefile b/Makefile
index cf58c0a..bca37eb 100644
--- a/Makefile
+++ b/Makefile
@@ -1652,6 +1652,7 @@ musl += regex/tre-mem.o
 $(out)/musl/src/regex/tre-mem.o: CFLAGS += -UNDEBUG
 
 libc += pthread.o
+libc += pthread_barrier.o
 libc += libc.o
 libc += dlfcn.o
 libc += time.o
diff --git a/libc/pthread.cc b/libc/pthread.cc
index 62de17d..a2b9292 100644
--- a/libc/pthread.cc
+++ b/libc/pthread.cc
@@ -29,7 +29,7 @@
 
 #include <api/time.h>
 #include <osv/rwlock.h>
-#include <osv/latch.hh>
+
 #include "pthread.hh"
 
 namespace pthread_private {
@@ -1128,117 +1128,3 @@ int pthread_attr_getaffinity_np(const pthread_attr_t 
*attr, size_t cpusetsize,
 
     return 0;
 }
-
-// Private definitions of the internal structs backing pthread_barrier_t and
-// pthread_barrierattr_t
-typedef struct
-{
-    unsigned int out;
-    unsigned int count;
-    latch *ltch;
-    pthread_mutex_t *mtx;
-} pthread_barrier_t_int;
-
-typedef struct
-{
-    unsigned pshared;
-} pthread_barrierattr_t_int;
-
-int pthread_barrier_init(pthread_barrier_t *barrier_opq,
-                         const pthread_barrierattr_t *attr_opq,
-                         unsigned count)
-{
-    pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq;
-    static_assert(sizeof(pthread_barrier_t_int) <= sizeof(pthread_barrier_t),
-                  "pthread_barrier_t_int is larger than pthread_barrier_t");
-
-    // Linux returns EINVAL if count == 0 or INT_MAX so we do too.
-    // In theory, we could go up to UINT_MAX since count is unsigned.
-    if (!barrier || count == 0 || count >= INT_MAX) {
-        return EINVAL;
-    }
-
-    // Always ignore attr, it has no meaning in the context of a unikernel.
-    // pthread_barrierattr_t has a single member variable pshared that can be 
set
-    // to PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED. These have the
-    // same effect in a unikernel - there is only a single process and all
-    // threads can manipulate the memory area associated with the
-    // pthread_barrier_t so it doesn't matter what the value of pshared is set 
to
-    barrier->count = count;
-    barrier->out = 0;
-    barrier->ltch = new latch(count);
-    barrier->mtx = new pthread_mutex_t;
-    pthread_mutex_init(barrier->mtx, NULL);
-    return 0;
-}
-
-int pthread_barrier_wait(pthread_barrier_t *barrier_opq)
-{
-    pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq;
-    static_assert(sizeof(pthread_barrier_t_int) <= sizeof(pthread_barrier_t),
-                  "pthread_barrier_t_int is larger than pthread_barrier_t");
-
-    if (!barrier || !barrier->ltch || !barrier->mtx) {
-        return EINVAL;
-    }
-
-    int retval = 0;
-    pthread_mutex_t *mtx = barrier->mtx;
-
-    pthread_mutex_lock(mtx);
-    pthread_mutex_unlock(mtx);
-
-    latch *l  = barrier->ltch;
-    l->count_down();
-    // All threads stuck here until we get at least 'count' waiters
-    l->await();
-
-    // If the last thread (thread x) to wait on the barrier is descheduled here
-    // (immediately after being the count'th thread crossing the barrier)
-    // the barrier remains open (a new waiting thread will cross) until
-    // the barrier is reset below (when thread x is rescheduled), which doesn't
-    // seem technically incorrect. Only one of the crossing threads will get a
-    // retval of PTHREAD_BARRIER_SERIAL_THREAD, when
-    // barrier->out == barrier->count.
-    // All other crossing threads will get a retval of 0.
-
-    pthread_mutex_lock(mtx);
-    barrier->out++;
-    // Make the last thread out responsible for resetting the barrier's latch.
-    // The last thread also gets the special return value
-    // PTHREAD_BARRIER_SERIAL_THREAD. Every other thread gets a retval of 0
-    if (barrier->out == barrier->count) {
-        retval = PTHREAD_BARRIER_SERIAL_THREAD;
-        // Reset the latch for the next round of waiters. We're using an
-        // external lock (mtx) to ensure that no other thread is calling
-        // count_down or in await when we're resetting it. Without the external
-        // lock, resetting the latch isn't safe.
-        l->unsafe_reset(barrier->count);
-        // Reset the 'out' counter so that the equality check above works 
across
-        // multiple rounds of threads waiting on the barrier
-        barrier->out = 0;
-    }
-    pthread_mutex_unlock(mtx);
-    return retval;
-}
-
-int pthread_barrier_destroy(pthread_barrier_t *barrier_opq)
-{
-    pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq;
-
-    static_assert(sizeof(pthread_barrier_t_int) <= sizeof(pthread_barrier_t),
-                  "pthread_barrier_t_int is larger than pthread_barrier_t");
-
-    if (!barrier || !barrier->ltch || !barrier->mtx) {
-        return EINVAL;
-    }
-
-    delete barrier->ltch;
-    barrier->ltch = nullptr;
-
-    pthread_mutex_destroy(barrier->mtx);
-    delete barrier->mtx;
-    barrier->mtx = nullptr;
-
-    return 0;
-}
diff --git a/libc/pthread_barrier.cc b/libc/pthread_barrier.cc
new file mode 100644
index 0000000..2437d73
--- /dev/null
+++ b/libc/pthread_barrier.cc
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2013 Cloudius Systems, Ltd.
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+
+#include <pthread.h>
+#include <osv/debug.hh>
+#include <osv/rwlock.h>
+#include <osv/latch.hh>
+#include "pthread.hh"
+
+// Private definitions of the internal structs backing pthread_barrier_t and
+// pthread_barrierattr_t
+typedef struct
+{
+    unsigned int out;
+    unsigned int count;
+    latch *ltch;
+    pthread_mutex_t *mtx;
+} pthread_barrier_t_int;
+
+typedef struct
+{
+    unsigned pshared;
+} pthread_barrierattr_t_int;
+
+int pthread_barrier_init(pthread_barrier_t *barrier_opq,
+                         const pthread_barrierattr_t *attr_opq,
+                         unsigned count)
+{
+    pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq;
+    static_assert(sizeof(pthread_barrier_t_int) <= sizeof(pthread_barrier_t),
+                  "pthread_barrier_t_int is larger than pthread_barrier_t");
+
+    // Linux returns EINVAL if count == 0 or INT_MAX so we do too.
+    // In theory, we could go up to UINT_MAX since count is unsigned.
+    if (!barrier || count == 0 || count >= INT_MAX) {
+        return EINVAL;
+    }
+
+    // Always ignore attr, it has no meaning in the context of a unikernel.
+    // pthread_barrierattr_t has a single member variable pshared that can be 
set
+    // to PTHREAD_PROCESS_PRIVATE or PTHREAD_PROCESS_SHARED. These have the
+    // same effect in a unikernel - there is only a single process and all
+    // threads can manipulate the memory area associated with the
+    // pthread_barrier_t so it doesn't matter what the value of pshared is set 
to
+    barrier->count = count;
+    barrier->out = 0;
+    barrier->ltch = new latch(count);
+    barrier->mtx = new pthread_mutex_t;
+    pthread_mutex_init(barrier->mtx, NULL);
+    return 0;
+}
+
+int pthread_barrier_wait(pthread_barrier_t *barrier_opq)
+{
+    pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq;
+    static_assert(sizeof(pthread_barrier_t_int) <= sizeof(pthread_barrier_t),
+                  "pthread_barrier_t_int is larger than pthread_barrier_t");
+
+    if (!barrier || !barrier->ltch || !barrier->mtx) {
+        return EINVAL;
+    }
+
+    int retval = 0;
+    pthread_mutex_t *mtx = barrier->mtx;
+
+    pthread_mutex_lock(mtx);
+    pthread_mutex_unlock(mtx);
+
+    latch *l  = barrier->ltch;
+    l->count_down();
+    // All threads stuck here until we get at least 'count' waiters
+    l->await();
+
+    // If the last thread (thread x) to wait on the barrier is descheduled here
+    // (immediately after being the count'th thread crossing the barrier)
+    // the barrier remains open (a new waiting thread will cross) until
+    // the barrier is reset below (when thread x is rescheduled), which doesn't
+    // seem technically incorrect. Only one of the crossing threads will get a
+    // retval of PTHREAD_BARRIER_SERIAL_THREAD, when
+    // barrier->out == barrier->count.
+    // All other crossing threads will get a retval of 0.
+
+    pthread_mutex_lock(mtx);
+    barrier->out++;
+    // Make the last thread out responsible for resetting the barrier's latch.
+    // The last thread also gets the special return value
+    // PTHREAD_BARRIER_SERIAL_THREAD. Every other thread gets a retval of 0
+    if (barrier->out == barrier->count) {
+        retval = PTHREAD_BARRIER_SERIAL_THREAD;
+        // Reset the latch for the next round of waiters. We're using an
+        // external lock (mtx) to ensure that no other thread is calling
+        // count_down or in await when we're resetting it. Without the external
+        // lock, resetting the latch isn't safe.
+        l->unsafe_reset(barrier->count);
+        // Reset the 'out' counter so that the equality check above works 
across
+        // multiple rounds of threads waiting on the barrier
+        barrier->out = 0;
+    }
+    pthread_mutex_unlock(mtx);
+    return retval;
+}
+
+int pthread_barrier_destroy(pthread_barrier_t *barrier_opq)
+{
+    pthread_barrier_t_int *barrier = (pthread_barrier_t_int*) barrier_opq;
+
+    static_assert(sizeof(pthread_barrier_t_int) <= sizeof(pthread_barrier_t),
+                  "pthread_barrier_t_int is larger than pthread_barrier_t");
+
+    if (!barrier || !barrier->ltch || !barrier->mtx) {
+        return EINVAL;
+    }
+
+    delete barrier->ltch;
+    barrier->ltch = nullptr;
+
+    pthread_mutex_destroy(barrier->mtx);
+    delete barrier->mtx;
+    barrier->mtx = nullptr;
+
+    return 0;
+}
-- 
1.8.3.1

-- 
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to