Skip to content

Commit 341e052

Browse files
committed
unix: rework thread barrier implementation
* dissolve include/uv/pthread-barrier.h * use libuv mutexes and condition variables, not pthreads's * drive-by cleanup and simplification enabled by the first two items
1 parent 6781db5 commit 341e052

4 files changed

Lines changed: 88 additions & 150 deletions

File tree

Makefile.am

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -340,8 +340,7 @@ libuv_la_SOURCES += src/unix/aix.c src/unix/aix-common.c
340340
endif
341341

342342
if ANDROID
343-
uvinclude_HEADERS += include/uv/android-ifaddrs.h \
344-
include/uv/pthread-barrier.h
343+
uvinclude_HEADERS += include/uv/android-ifaddrs.h
345344
libuv_la_SOURCES += src/unix/android-ifaddrs.c \
346345
src/unix/pthread-fixes.c
347346
endif
@@ -361,8 +360,7 @@ libuv_la_SOURCES += src/unix/cygwin.c \
361360
endif
362361

363362
if DARWIN
364-
uvinclude_HEADERS += include/uv/darwin.h \
365-
include/uv/pthread-barrier.h
363+
uvinclude_HEADERS += include/uv/darwin.h
366364
libuv_la_CFLAGS += -D_DARWIN_USE_64_BIT_INODE=1
367365
libuv_la_CFLAGS += -D_DARWIN_UNLIMITED_SELECT=1
368366
libuv_la_SOURCES += src/unix/bsd-ifaddrs.c \
@@ -445,7 +443,6 @@ libuv_la_SOURCES += src/unix/no-proctitle.c \
445443
endif
446444

447445
if OS390
448-
uvinclude_HEADERS += include/uv/pthread-barrier.h
449446
libuv_la_CFLAGS += -D_UNIX03_THREADS \
450447
-D_UNIX03_SOURCE \
451448
-D_OPEN_SYS_IF_EXT=1 \

include/uv/pthread-barrier.h

Lines changed: 0 additions & 69 deletions
This file was deleted.

include/uv/unix.h

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,6 @@
6666
# include "uv/posix.h"
6767
#endif
6868

69-
#ifndef PTHREAD_BARRIER_SERIAL_THREAD
70-
# include "uv/pthread-barrier.h"
71-
#endif
72-
7369
#ifndef NI_MAXHOST
7470
# define NI_MAXHOST 1025
7571
#endif
@@ -136,8 +132,28 @@ typedef pthread_rwlock_t uv_rwlock_t;
136132
typedef UV_PLATFORM_SEM_T uv_sem_t;
137133
typedef pthread_cond_t uv_cond_t;
138134
typedef pthread_key_t uv_key_t;
139-
typedef pthread_barrier_t uv_barrier_t;
140135

136+
/* Note: guard clauses should match uv_barrier_init's in src/unix/thread.c. */
137+
#if !defined(PTHREAD_BARRIER_SERIAL_THREAD)
138+
/* TODO(bnoordhuis) Merge into uv_barrier_t in v2. */
139+
struct _uv_barrier {
140+
uv_mutex_t mutex;
141+
uv_cond_t cond;
142+
unsigned threshold;
143+
unsigned in;
144+
unsigned out;
145+
};
146+
147+
typedef struct {
148+
struct _uv_barrier* b;
149+
# if defined(PTHREAD_BARRIER_SERIAL_THREAD)
150+
/* TODO(bnoordhuis) Remove padding in v2. */
151+
char pad[sizeof(pthread_barrier_t) - sizeof(struct _uv_barrier*)];
152+
# endif
153+
} uv_barrier_t;
154+
#else
155+
typedef pthread_barrier_t uv_barrier_t;
156+
#endif
141157

142158
/* Platform-specific definitions for uv_spawn support. */
143159
typedef gid_t uv_gid_t;

src/unix/thread.c

Lines changed: 65 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -44,108 +44,121 @@
4444
#undef NANOSEC
4545
#define NANOSEC ((uint64_t) 1e9)
4646

47+
#if defined(PTHREAD_BARRIER_SERIAL_THREAD)
48+
STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t));
49+
#endif
4750

48-
#if defined(UV__PTHREAD_BARRIER_FALLBACK)
49-
/* TODO: support barrier_attr */
50-
int pthread_barrier_init(pthread_barrier_t* barrier,
51-
const void* barrier_attr,
52-
unsigned count) {
51+
/* Note: guard clauses should match uv_barrier_t's in include/uv/uv-unix.h. */
52+
#if !defined(PTHREAD_BARRIER_SERIAL_THREAD)
53+
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
54+
struct _uv_barrier* b;
5355
int rc;
54-
_uv_barrier* b;
5556

5657
if (barrier == NULL || count == 0)
57-
return EINVAL;
58-
59-
if (barrier_attr != NULL)
60-
return ENOTSUP;
58+
return UV_EINVAL;
6159

6260
b = uv__malloc(sizeof(*b));
6361
if (b == NULL)
64-
return ENOMEM;
62+
return UV_ENOMEM;
6563

6664
b->in = 0;
6765
b->out = 0;
6866
b->threshold = count;
6967

70-
if ((rc = pthread_mutex_init(&b->mutex, NULL)) != 0)
68+
rc = uv_mutex_init(&b->mutex);
69+
if (rc != 0)
7170
goto error2;
72-
if ((rc = pthread_cond_init(&b->cond, NULL)) != 0)
71+
72+
rc = uv_cond_init(&b->cond);
73+
if (rc != 0)
7374
goto error;
7475

7576
barrier->b = b;
7677
return 0;
7778

7879
error:
79-
pthread_mutex_destroy(&b->mutex);
80+
uv_mutex_destroy(&b->mutex);
8081
error2:
8182
uv__free(b);
8283
return rc;
8384
}
8485

85-
int pthread_barrier_wait(pthread_barrier_t* barrier) {
86-
int rc;
87-
_uv_barrier* b;
86+
87+
int uv_barrier_wait(uv_barrier_t* barrier) {
88+
struct _uv_barrier* b;
8889

8990
if (barrier == NULL || barrier->b == NULL)
90-
return EINVAL;
91+
return UV_EINVAL;
9192

9293
b = barrier->b;
93-
/* Lock the mutex*/
94-
if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
95-
return rc;
94+
uv_mutex_lock(&b->mutex);
9695

97-
/* Increment the count. If this is the first thread to reach the threshold,
98-
wake up waiters, unlock the mutex, then return
99-
PTHREAD_BARRIER_SERIAL_THREAD. */
10096
if (++b->in == b->threshold) {
10197
b->in = 0;
10298
b->out = b->threshold - 1;
103-
rc = pthread_cond_signal(&b->cond);
104-
assert(rc == 0);
105-
106-
pthread_mutex_unlock(&b->mutex);
107-
return PTHREAD_BARRIER_SERIAL_THREAD;
99+
uv_cond_signal(&b->cond);
100+
uv_mutex_unlock(&b->mutex);
101+
return 1; /* This is the first thread to reach the threshold. */
108102
}
103+
109104
/* Otherwise, wait for other threads until in is set to 0,
110105
then return 0 to indicate this is not the first thread. */
111-
do {
112-
if ((rc = pthread_cond_wait(&b->cond, &b->mutex)) != 0)
113-
break;
114-
} while (b->in != 0);
106+
do
107+
uv_cond_wait(&b->cond, &b->mutex);
108+
while (b->in != 0);
115109

116110
/* mark thread exit */
117111
b->out--;
118-
pthread_cond_signal(&b->cond);
119-
pthread_mutex_unlock(&b->mutex);
120-
return rc;
112+
uv_cond_signal(&b->cond);
113+
uv_mutex_unlock(&b->mutex);
114+
return 0;
121115
}
122116

123-
int pthread_barrier_destroy(pthread_barrier_t* barrier) {
124-
int rc;
125-
_uv_barrier* b;
126117

127-
if (barrier == NULL || barrier->b == NULL)
128-
return EINVAL;
118+
void uv_barrier_destroy(uv_barrier_t* barrier) {
119+
struct _uv_barrier* b;
129120

130121
b = barrier->b;
122+
uv_mutex_lock(&b->mutex);
131123

132-
if ((rc = pthread_mutex_lock(&b->mutex)) != 0)
133-
return rc;
134-
135-
if (b->in > 0 || b->out > 0)
136-
rc = EBUSY;
124+
assert(b->in == 0);
125+
assert(b->out == 0);
137126

138-
pthread_mutex_unlock(&b->mutex);
127+
if (b->in != 0 || b->out != 0)
128+
abort();
139129

140-
if (rc)
141-
return rc;
130+
uv_mutex_unlock(&b->mutex);
131+
uv_mutex_destroy(&b->mutex);
132+
uv_cond_destroy(&b->cond);
142133

143-
pthread_cond_destroy(&b->cond);
144-
pthread_mutex_destroy(&b->mutex);
145134
uv__free(barrier->b);
146135
barrier->b = NULL;
147-
return 0;
148136
}
137+
138+
#else
139+
140+
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
141+
return UV__ERR(pthread_barrier_init(barrier, NULL, count));
142+
}
143+
144+
145+
int uv_barrier_wait(uv_barrier_t* barrier) {
146+
int rc;
147+
148+
rc = pthread_barrier_wait(barrier);
149+
if (rc != 0)
150+
if (rc != PTHREAD_BARRIER_SERIAL_THREAD)
151+
abort();
152+
153+
return rc == PTHREAD_BARRIER_SERIAL_THREAD;
154+
}
155+
156+
157+
void uv_barrier_destroy(uv_barrier_t* barrier) {
158+
if (pthread_barrier_destroy(barrier))
159+
abort();
160+
}
161+
149162
#endif
150163

151164

@@ -771,25 +784,6 @@ int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
771784
}
772785

773786

774-
int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
775-
return UV__ERR(pthread_barrier_init(barrier, NULL, count));
776-
}
777-
778-
779-
void uv_barrier_destroy(uv_barrier_t* barrier) {
780-
if (pthread_barrier_destroy(barrier))
781-
abort();
782-
}
783-
784-
785-
int uv_barrier_wait(uv_barrier_t* barrier) {
786-
int r = pthread_barrier_wait(barrier);
787-
if (r && r != PTHREAD_BARRIER_SERIAL_THREAD)
788-
abort();
789-
return r == PTHREAD_BARRIER_SERIAL_THREAD;
790-
}
791-
792-
793787
int uv_key_create(uv_key_t* key) {
794788
return UV__ERR(pthread_key_create(key, NULL));
795789
}

0 commit comments

Comments
 (0)