10e552da7Schristos /* Copyright Joyent, Inc. and other Node contributors. All rights reserved.
20e552da7Schristos *
30e552da7Schristos * Permission is hereby granted, free of charge, to any person obtaining a copy
40e552da7Schristos * of this software and associated documentation files (the "Software"), to
50e552da7Schristos * deal in the Software without restriction, including without limitation the
60e552da7Schristos * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
70e552da7Schristos * sell copies of the Software, and to permit persons to whom the Software is
80e552da7Schristos * furnished to do so, subject to the following conditions:
90e552da7Schristos *
100e552da7Schristos * The above copyright notice and this permission notice shall be included in
110e552da7Schristos * all copies or substantial portions of the Software.
120e552da7Schristos *
130e552da7Schristos * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
140e552da7Schristos * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
150e552da7Schristos * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
160e552da7Schristos * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
170e552da7Schristos * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
180e552da7Schristos * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
190e552da7Schristos * IN THE SOFTWARE.
200e552da7Schristos */
210e552da7Schristos
220e552da7Schristos #include "uv.h"
230e552da7Schristos #include "internal.h"
240e552da7Schristos
250e552da7Schristos #include <pthread.h>
260e552da7Schristos #include <assert.h>
270e552da7Schristos #include <errno.h>
280e552da7Schristos
290e552da7Schristos #include <sys/time.h>
300e552da7Schristos #include <sys/resource.h> /* getrlimit() */
310e552da7Schristos #include <unistd.h> /* getpagesize() */
320e552da7Schristos
330e552da7Schristos #include <limits.h>
340e552da7Schristos
350e552da7Schristos #ifdef __MVS__
360e552da7Schristos #include <sys/ipc.h>
370e552da7Schristos #include <sys/sem.h>
380e552da7Schristos #endif
390e552da7Schristos
400e552da7Schristos #if defined(__GLIBC__) && !defined(__UCLIBC__)
410e552da7Schristos #include <gnu/libc-version.h> /* gnu_get_libc_version() */
420e552da7Schristos #endif
430e552da7Schristos
440e552da7Schristos #undef NANOSEC
450e552da7Schristos #define NANOSEC ((uint64_t) 1e9)
460e552da7Schristos
470e552da7Schristos #if defined(PTHREAD_BARRIER_SERIAL_THREAD)
480e552da7Schristos STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t));
490e552da7Schristos #endif
500e552da7Schristos
510e552da7Schristos /* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */
520e552da7Schristos #if defined(_AIX) || \
530e552da7Schristos defined(__OpenBSD__) || \
540e552da7Schristos !defined(PTHREAD_BARRIER_SERIAL_THREAD)
uv_barrier_init(uv_barrier_t * barrier,unsigned int count)550e552da7Schristos int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
560e552da7Schristos struct _uv_barrier* b;
570e552da7Schristos int rc;
580e552da7Schristos
590e552da7Schristos if (barrier == NULL || count == 0)
600e552da7Schristos return UV_EINVAL;
610e552da7Schristos
620e552da7Schristos b = uv__malloc(sizeof(*b));
630e552da7Schristos if (b == NULL)
640e552da7Schristos return UV_ENOMEM;
650e552da7Schristos
660e552da7Schristos b->in = 0;
670e552da7Schristos b->out = 0;
680e552da7Schristos b->threshold = count;
690e552da7Schristos
700e552da7Schristos rc = uv_mutex_init(&b->mutex);
710e552da7Schristos if (rc != 0)
720e552da7Schristos goto error2;
730e552da7Schristos
740e552da7Schristos rc = uv_cond_init(&b->cond);
750e552da7Schristos if (rc != 0)
760e552da7Schristos goto error;
770e552da7Schristos
780e552da7Schristos barrier->b = b;
790e552da7Schristos return 0;
800e552da7Schristos
810e552da7Schristos error:
820e552da7Schristos uv_mutex_destroy(&b->mutex);
830e552da7Schristos error2:
840e552da7Schristos uv__free(b);
850e552da7Schristos return rc;
860e552da7Schristos }
870e552da7Schristos
880e552da7Schristos
uv_barrier_wait(uv_barrier_t * barrier)890e552da7Schristos int uv_barrier_wait(uv_barrier_t* barrier) {
900e552da7Schristos struct _uv_barrier* b;
910e552da7Schristos int last;
920e552da7Schristos
930e552da7Schristos if (barrier == NULL || barrier->b == NULL)
940e552da7Schristos return UV_EINVAL;
950e552da7Schristos
960e552da7Schristos b = barrier->b;
970e552da7Schristos uv_mutex_lock(&b->mutex);
980e552da7Schristos
990e552da7Schristos if (++b->in == b->threshold) {
1000e552da7Schristos b->in = 0;
1010e552da7Schristos b->out = b->threshold;
1020e552da7Schristos uv_cond_signal(&b->cond);
1030e552da7Schristos } else {
1040e552da7Schristos do
1050e552da7Schristos uv_cond_wait(&b->cond, &b->mutex);
1060e552da7Schristos while (b->in != 0);
1070e552da7Schristos }
1080e552da7Schristos
1090e552da7Schristos last = (--b->out == 0);
110*5f2f4271Schristos uv_cond_signal(&b->cond);
1110e552da7Schristos
1120e552da7Schristos uv_mutex_unlock(&b->mutex);
1130e552da7Schristos return last;
1140e552da7Schristos }
1150e552da7Schristos
1160e552da7Schristos
uv_barrier_destroy(uv_barrier_t * barrier)1170e552da7Schristos void uv_barrier_destroy(uv_barrier_t* barrier) {
1180e552da7Schristos struct _uv_barrier* b;
1190e552da7Schristos
1200e552da7Schristos b = barrier->b;
1210e552da7Schristos uv_mutex_lock(&b->mutex);
1220e552da7Schristos
1230e552da7Schristos assert(b->in == 0);
124*5f2f4271Schristos while (b->out != 0)
125*5f2f4271Schristos uv_cond_wait(&b->cond, &b->mutex);
1260e552da7Schristos
127*5f2f4271Schristos if (b->in != 0)
1280e552da7Schristos abort();
1290e552da7Schristos
1300e552da7Schristos uv_mutex_unlock(&b->mutex);
1310e552da7Schristos uv_mutex_destroy(&b->mutex);
1320e552da7Schristos uv_cond_destroy(&b->cond);
1330e552da7Schristos
1340e552da7Schristos uv__free(barrier->b);
1350e552da7Schristos barrier->b = NULL;
1360e552da7Schristos }
1370e552da7Schristos
1380e552da7Schristos #else
1390e552da7Schristos
uv_barrier_init(uv_barrier_t * barrier,unsigned int count)1400e552da7Schristos int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) {
1410e552da7Schristos return UV__ERR(pthread_barrier_init(barrier, NULL, count));
1420e552da7Schristos }
1430e552da7Schristos
1440e552da7Schristos
uv_barrier_wait(uv_barrier_t * barrier)1450e552da7Schristos int uv_barrier_wait(uv_barrier_t* barrier) {
1460e552da7Schristos int rc;
1470e552da7Schristos
1480e552da7Schristos rc = pthread_barrier_wait(barrier);
1490e552da7Schristos if (rc != 0)
1500e552da7Schristos if (rc != PTHREAD_BARRIER_SERIAL_THREAD)
1510e552da7Schristos abort();
1520e552da7Schristos
1530e552da7Schristos return rc == PTHREAD_BARRIER_SERIAL_THREAD;
1540e552da7Schristos }
1550e552da7Schristos
1560e552da7Schristos
uv_barrier_destroy(uv_barrier_t * barrier)1570e552da7Schristos void uv_barrier_destroy(uv_barrier_t* barrier) {
1580e552da7Schristos if (pthread_barrier_destroy(barrier))
1590e552da7Schristos abort();
1600e552da7Schristos }
1610e552da7Schristos
1620e552da7Schristos #endif
1630e552da7Schristos
1640e552da7Schristos
1650e552da7Schristos /* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is
1660e552da7Schristos * too small to safely receive signals on.
1670e552da7Schristos *
1680e552da7Schristos * Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has
1690e552da7Schristos * the largest MINSIGSTKSZ of the architectures that musl supports) so
1700e552da7Schristos * let's use that as a lower bound.
1710e552da7Schristos *
1720e552da7Schristos * We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ
1730e552da7Schristos * is between 28 and 133 KB when compiling against glibc, depending
1740e552da7Schristos * on the architecture.
1750e552da7Schristos */
uv__min_stack_size(void)176*5f2f4271Schristos static size_t uv__min_stack_size(void) {
177*5f2f4271Schristos static const size_t min = 8192;
1780e552da7Schristos
179*5f2f4271Schristos #ifdef PTHREAD_STACK_MIN /* Not defined on NetBSD. */
180*5f2f4271Schristos if (min < (size_t) PTHREAD_STACK_MIN)
181*5f2f4271Schristos return PTHREAD_STACK_MIN;
182*5f2f4271Schristos #endif /* PTHREAD_STACK_MIN */
183*5f2f4271Schristos
184*5f2f4271Schristos return min;
185*5f2f4271Schristos }
186*5f2f4271Schristos
187*5f2f4271Schristos
188*5f2f4271Schristos /* On Linux, threads created by musl have a much smaller stack than threads
189*5f2f4271Schristos * created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency.
190*5f2f4271Schristos */
uv__default_stack_size(void)191*5f2f4271Schristos static size_t uv__default_stack_size(void) {
1920e552da7Schristos #if !defined(__linux__)
1930e552da7Schristos return 0;
1940e552da7Schristos #elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__)
1950e552da7Schristos return 4 << 20; /* glibc default. */
1960e552da7Schristos #else
1970e552da7Schristos return 2 << 20; /* glibc default. */
1980e552da7Schristos #endif
1990e552da7Schristos }
2000e552da7Schristos
2010e552da7Schristos
202*5f2f4271Schristos /* On MacOS, threads other than the main thread are created with a reduced
203*5f2f4271Schristos * stack size by default. Adjust to RLIMIT_STACK aligned to the page size.
204*5f2f4271Schristos */
uv__thread_stack_size(void)205*5f2f4271Schristos size_t uv__thread_stack_size(void) {
206*5f2f4271Schristos #if defined(__APPLE__) || defined(__linux__)
207*5f2f4271Schristos struct rlimit lim;
208*5f2f4271Schristos
209*5f2f4271Schristos /* getrlimit() can fail on some aarch64 systems due to a glibc bug where
210*5f2f4271Schristos * the system call wrapper invokes the wrong system call. Don't treat
211*5f2f4271Schristos * that as fatal, just use the default stack size instead.
212*5f2f4271Schristos */
213*5f2f4271Schristos if (getrlimit(RLIMIT_STACK, &lim))
214*5f2f4271Schristos return uv__default_stack_size();
215*5f2f4271Schristos
216*5f2f4271Schristos if (lim.rlim_cur == RLIM_INFINITY)
217*5f2f4271Schristos return uv__default_stack_size();
218*5f2f4271Schristos
219*5f2f4271Schristos /* pthread_attr_setstacksize() expects page-aligned values. */
220*5f2f4271Schristos lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize();
221*5f2f4271Schristos
222*5f2f4271Schristos if (lim.rlim_cur >= (rlim_t) uv__min_stack_size())
223*5f2f4271Schristos return lim.rlim_cur;
224*5f2f4271Schristos #endif
225*5f2f4271Schristos
226*5f2f4271Schristos return uv__default_stack_size();
227*5f2f4271Schristos }
228*5f2f4271Schristos
229*5f2f4271Schristos
uv_thread_create(uv_thread_t * tid,void (* entry)(void * arg),void * arg)2300e552da7Schristos int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) {
2310e552da7Schristos uv_thread_options_t params;
2320e552da7Schristos params.flags = UV_THREAD_NO_FLAGS;
2330e552da7Schristos return uv_thread_create_ex(tid, ¶ms, entry, arg);
2340e552da7Schristos }
2350e552da7Schristos
uv_thread_create_ex(uv_thread_t * tid,const uv_thread_options_t * params,void (* entry)(void * arg),void * arg)2360e552da7Schristos int uv_thread_create_ex(uv_thread_t* tid,
2370e552da7Schristos const uv_thread_options_t* params,
2380e552da7Schristos void (*entry)(void *arg),
2390e552da7Schristos void *arg) {
2400e552da7Schristos int err;
2410e552da7Schristos pthread_attr_t* attr;
2420e552da7Schristos pthread_attr_t attr_storage;
2430e552da7Schristos size_t pagesize;
2440e552da7Schristos size_t stack_size;
245*5f2f4271Schristos size_t min_stack_size;
2460e552da7Schristos
2470e552da7Schristos /* Used to squelch a -Wcast-function-type warning. */
2480e552da7Schristos union {
2490e552da7Schristos void (*in)(void*);
2500e552da7Schristos void* (*out)(void*);
2510e552da7Schristos } f;
2520e552da7Schristos
2530e552da7Schristos stack_size =
2540e552da7Schristos params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0;
2550e552da7Schristos
2560e552da7Schristos attr = NULL;
2570e552da7Schristos if (stack_size == 0) {
258*5f2f4271Schristos stack_size = uv__thread_stack_size();
2590e552da7Schristos } else {
2600e552da7Schristos pagesize = (size_t)getpagesize();
2610e552da7Schristos /* Round up to the nearest page boundary. */
2620e552da7Schristos stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1);
263*5f2f4271Schristos min_stack_size = uv__min_stack_size();
264*5f2f4271Schristos if (stack_size < min_stack_size)
265*5f2f4271Schristos stack_size = min_stack_size;
2660e552da7Schristos }
2670e552da7Schristos
2680e552da7Schristos if (stack_size > 0) {
2690e552da7Schristos attr = &attr_storage;
2700e552da7Schristos
2710e552da7Schristos if (pthread_attr_init(attr))
2720e552da7Schristos abort();
2730e552da7Schristos
2740e552da7Schristos if (pthread_attr_setstacksize(attr, stack_size))
2750e552da7Schristos abort();
2760e552da7Schristos }
2770e552da7Schristos
2780e552da7Schristos f.in = entry;
2790e552da7Schristos err = pthread_create(tid, attr, f.out, arg);
2800e552da7Schristos
2810e552da7Schristos if (attr != NULL)
2820e552da7Schristos pthread_attr_destroy(attr);
2830e552da7Schristos
2840e552da7Schristos return UV__ERR(err);
2850e552da7Schristos }
2860e552da7Schristos
2870e552da7Schristos
uv_thread_self(void)2880e552da7Schristos uv_thread_t uv_thread_self(void) {
2890e552da7Schristos return pthread_self();
2900e552da7Schristos }
2910e552da7Schristos
uv_thread_join(uv_thread_t * tid)2920e552da7Schristos int uv_thread_join(uv_thread_t *tid) {
2930e552da7Schristos return UV__ERR(pthread_join(*tid, NULL));
2940e552da7Schristos }
2950e552da7Schristos
2960e552da7Schristos
uv_thread_equal(const uv_thread_t * t1,const uv_thread_t * t2)2970e552da7Schristos int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) {
2980e552da7Schristos return pthread_equal(*t1, *t2);
2990e552da7Schristos }
3000e552da7Schristos
3010e552da7Schristos
uv_mutex_init(uv_mutex_t * mutex)3020e552da7Schristos int uv_mutex_init(uv_mutex_t* mutex) {
3030e552da7Schristos #if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK)
3040e552da7Schristos return UV__ERR(pthread_mutex_init(mutex, NULL));
3050e552da7Schristos #else
3060e552da7Schristos pthread_mutexattr_t attr;
3070e552da7Schristos int err;
3080e552da7Schristos
3090e552da7Schristos if (pthread_mutexattr_init(&attr))
3100e552da7Schristos abort();
3110e552da7Schristos
3120e552da7Schristos if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK))
3130e552da7Schristos abort();
3140e552da7Schristos
3150e552da7Schristos err = pthread_mutex_init(mutex, &attr);
3160e552da7Schristos
3170e552da7Schristos if (pthread_mutexattr_destroy(&attr))
3180e552da7Schristos abort();
3190e552da7Schristos
3200e552da7Schristos return UV__ERR(err);
3210e552da7Schristos #endif
3220e552da7Schristos }
3230e552da7Schristos
3240e552da7Schristos
uv_mutex_init_recursive(uv_mutex_t * mutex)3250e552da7Schristos int uv_mutex_init_recursive(uv_mutex_t* mutex) {
3260e552da7Schristos pthread_mutexattr_t attr;
3270e552da7Schristos int err;
3280e552da7Schristos
3290e552da7Schristos if (pthread_mutexattr_init(&attr))
3300e552da7Schristos abort();
3310e552da7Schristos
3320e552da7Schristos if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
3330e552da7Schristos abort();
3340e552da7Schristos
3350e552da7Schristos err = pthread_mutex_init(mutex, &attr);
3360e552da7Schristos
3370e552da7Schristos if (pthread_mutexattr_destroy(&attr))
3380e552da7Schristos abort();
3390e552da7Schristos
3400e552da7Schristos return UV__ERR(err);
3410e552da7Schristos }
3420e552da7Schristos
3430e552da7Schristos
uv_mutex_destroy(uv_mutex_t * mutex)3440e552da7Schristos void uv_mutex_destroy(uv_mutex_t* mutex) {
3450e552da7Schristos if (pthread_mutex_destroy(mutex))
3460e552da7Schristos abort();
3470e552da7Schristos }
3480e552da7Schristos
3490e552da7Schristos
uv_mutex_lock(uv_mutex_t * mutex)3500e552da7Schristos void uv_mutex_lock(uv_mutex_t* mutex) {
3510e552da7Schristos if (pthread_mutex_lock(mutex))
3520e552da7Schristos abort();
3530e552da7Schristos }
3540e552da7Schristos
3550e552da7Schristos
uv_mutex_trylock(uv_mutex_t * mutex)3560e552da7Schristos int uv_mutex_trylock(uv_mutex_t* mutex) {
3570e552da7Schristos int err;
3580e552da7Schristos
3590e552da7Schristos err = pthread_mutex_trylock(mutex);
3600e552da7Schristos if (err) {
3610e552da7Schristos if (err != EBUSY && err != EAGAIN)
3620e552da7Schristos abort();
3630e552da7Schristos return UV_EBUSY;
3640e552da7Schristos }
3650e552da7Schristos
3660e552da7Schristos return 0;
3670e552da7Schristos }
3680e552da7Schristos
3690e552da7Schristos
uv_mutex_unlock(uv_mutex_t * mutex)3700e552da7Schristos void uv_mutex_unlock(uv_mutex_t* mutex) {
3710e552da7Schristos if (pthread_mutex_unlock(mutex))
3720e552da7Schristos abort();
3730e552da7Schristos }
3740e552da7Schristos
3750e552da7Schristos
uv_rwlock_init(uv_rwlock_t * rwlock)3760e552da7Schristos int uv_rwlock_init(uv_rwlock_t* rwlock) {
3770e552da7Schristos return UV__ERR(pthread_rwlock_init(rwlock, NULL));
3780e552da7Schristos }
3790e552da7Schristos
3800e552da7Schristos
uv_rwlock_destroy(uv_rwlock_t * rwlock)3810e552da7Schristos void uv_rwlock_destroy(uv_rwlock_t* rwlock) {
3820e552da7Schristos if (pthread_rwlock_destroy(rwlock))
3830e552da7Schristos abort();
3840e552da7Schristos }
3850e552da7Schristos
3860e552da7Schristos
uv_rwlock_rdlock(uv_rwlock_t * rwlock)3870e552da7Schristos void uv_rwlock_rdlock(uv_rwlock_t* rwlock) {
3880e552da7Schristos if (pthread_rwlock_rdlock(rwlock))
3890e552da7Schristos abort();
3900e552da7Schristos }
3910e552da7Schristos
3920e552da7Schristos
uv_rwlock_tryrdlock(uv_rwlock_t * rwlock)3930e552da7Schristos int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) {
3940e552da7Schristos int err;
3950e552da7Schristos
3960e552da7Schristos err = pthread_rwlock_tryrdlock(rwlock);
3970e552da7Schristos if (err) {
3980e552da7Schristos if (err != EBUSY && err != EAGAIN)
3990e552da7Schristos abort();
4000e552da7Schristos return UV_EBUSY;
4010e552da7Schristos }
4020e552da7Schristos
4030e552da7Schristos return 0;
4040e552da7Schristos }
4050e552da7Schristos
4060e552da7Schristos
uv_rwlock_rdunlock(uv_rwlock_t * rwlock)4070e552da7Schristos void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) {
4080e552da7Schristos if (pthread_rwlock_unlock(rwlock))
4090e552da7Schristos abort();
4100e552da7Schristos }
4110e552da7Schristos
4120e552da7Schristos
uv_rwlock_wrlock(uv_rwlock_t * rwlock)4130e552da7Schristos void uv_rwlock_wrlock(uv_rwlock_t* rwlock) {
4140e552da7Schristos if (pthread_rwlock_wrlock(rwlock))
4150e552da7Schristos abort();
4160e552da7Schristos }
4170e552da7Schristos
4180e552da7Schristos
uv_rwlock_trywrlock(uv_rwlock_t * rwlock)4190e552da7Schristos int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) {
4200e552da7Schristos int err;
4210e552da7Schristos
4220e552da7Schristos err = pthread_rwlock_trywrlock(rwlock);
4230e552da7Schristos if (err) {
4240e552da7Schristos if (err != EBUSY && err != EAGAIN)
4250e552da7Schristos abort();
4260e552da7Schristos return UV_EBUSY;
4270e552da7Schristos }
4280e552da7Schristos
4290e552da7Schristos return 0;
4300e552da7Schristos }
4310e552da7Schristos
4320e552da7Schristos
uv_rwlock_wrunlock(uv_rwlock_t * rwlock)4330e552da7Schristos void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) {
4340e552da7Schristos if (pthread_rwlock_unlock(rwlock))
4350e552da7Schristos abort();
4360e552da7Schristos }
4370e552da7Schristos
4380e552da7Schristos
uv_once(uv_once_t * guard,void (* callback)(void))4390e552da7Schristos void uv_once(uv_once_t* guard, void (*callback)(void)) {
4400e552da7Schristos if (pthread_once(guard, callback))
4410e552da7Schristos abort();
4420e552da7Schristos }
4430e552da7Schristos
4440e552da7Schristos #if defined(__APPLE__) && defined(__MACH__)
4450e552da7Schristos
uv_sem_init(uv_sem_t * sem,unsigned int value)4460e552da7Schristos int uv_sem_init(uv_sem_t* sem, unsigned int value) {
4470e552da7Schristos kern_return_t err;
4480e552da7Schristos
4490e552da7Schristos err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value);
4500e552da7Schristos if (err == KERN_SUCCESS)
4510e552da7Schristos return 0;
4520e552da7Schristos if (err == KERN_INVALID_ARGUMENT)
4530e552da7Schristos return UV_EINVAL;
4540e552da7Schristos if (err == KERN_RESOURCE_SHORTAGE)
4550e552da7Schristos return UV_ENOMEM;
4560e552da7Schristos
4570e552da7Schristos abort();
4580e552da7Schristos return UV_EINVAL; /* Satisfy the compiler. */
4590e552da7Schristos }
4600e552da7Schristos
4610e552da7Schristos
uv_sem_destroy(uv_sem_t * sem)4620e552da7Schristos void uv_sem_destroy(uv_sem_t* sem) {
4630e552da7Schristos if (semaphore_destroy(mach_task_self(), *sem))
4640e552da7Schristos abort();
4650e552da7Schristos }
4660e552da7Schristos
4670e552da7Schristos
uv_sem_post(uv_sem_t * sem)4680e552da7Schristos void uv_sem_post(uv_sem_t* sem) {
4690e552da7Schristos if (semaphore_signal(*sem))
4700e552da7Schristos abort();
4710e552da7Schristos }
4720e552da7Schristos
4730e552da7Schristos
uv_sem_wait(uv_sem_t * sem)4740e552da7Schristos void uv_sem_wait(uv_sem_t* sem) {
4750e552da7Schristos int r;
4760e552da7Schristos
4770e552da7Schristos do
4780e552da7Schristos r = semaphore_wait(*sem);
4790e552da7Schristos while (r == KERN_ABORTED);
4800e552da7Schristos
4810e552da7Schristos if (r != KERN_SUCCESS)
4820e552da7Schristos abort();
4830e552da7Schristos }
4840e552da7Schristos
4850e552da7Schristos
uv_sem_trywait(uv_sem_t * sem)4860e552da7Schristos int uv_sem_trywait(uv_sem_t* sem) {
4870e552da7Schristos mach_timespec_t interval;
4880e552da7Schristos kern_return_t err;
4890e552da7Schristos
4900e552da7Schristos interval.tv_sec = 0;
4910e552da7Schristos interval.tv_nsec = 0;
4920e552da7Schristos
4930e552da7Schristos err = semaphore_timedwait(*sem, interval);
4940e552da7Schristos if (err == KERN_SUCCESS)
4950e552da7Schristos return 0;
4960e552da7Schristos if (err == KERN_OPERATION_TIMED_OUT)
4970e552da7Schristos return UV_EAGAIN;
4980e552da7Schristos
4990e552da7Schristos abort();
5000e552da7Schristos return UV_EINVAL; /* Satisfy the compiler. */
5010e552da7Schristos }
5020e552da7Schristos
5030e552da7Schristos #else /* !(defined(__APPLE__) && defined(__MACH__)) */
5040e552da7Schristos
5050e552da7Schristos #if defined(__GLIBC__) && !defined(__UCLIBC__)
5060e552da7Schristos
5070e552da7Schristos /* Hack around https://sourceware.org/bugzilla/show_bug.cgi?id=12674
5080e552da7Schristos * by providing a custom implementation for glibc < 2.21 in terms of other
5090e552da7Schristos * concurrency primitives.
5100e552da7Schristos * Refs: https://github.com/nodejs/node/issues/19903 */
5110e552da7Schristos
5120e552da7Schristos /* To preserve ABI compatibility, we treat the uv_sem_t as storage for
5130e552da7Schristos * a pointer to the actual struct we're using underneath. */
5140e552da7Schristos
5150e552da7Schristos static uv_once_t glibc_version_check_once = UV_ONCE_INIT;
5160e552da7Schristos static int platform_needs_custom_semaphore = 0;
5170e552da7Schristos
glibc_version_check(void)5180e552da7Schristos static void glibc_version_check(void) {
5190e552da7Schristos const char* version = gnu_get_libc_version();
5200e552da7Schristos platform_needs_custom_semaphore =
5210e552da7Schristos version[0] == '2' && version[1] == '.' &&
5220e552da7Schristos atoi(version + 2) < 21;
5230e552da7Schristos }
5240e552da7Schristos
5250e552da7Schristos #elif defined(__MVS__)
5260e552da7Schristos
5270e552da7Schristos #define platform_needs_custom_semaphore 1
5280e552da7Schristos
5290e552da7Schristos #else /* !defined(__GLIBC__) && !defined(__MVS__) */
5300e552da7Schristos
5310e552da7Schristos #define platform_needs_custom_semaphore 0
5320e552da7Schristos
5330e552da7Schristos #endif
5340e552da7Schristos
5350e552da7Schristos typedef struct uv_semaphore_s {
5360e552da7Schristos uv_mutex_t mutex;
5370e552da7Schristos uv_cond_t cond;
5380e552da7Schristos unsigned int value;
5390e552da7Schristos } uv_semaphore_t;
5400e552da7Schristos
5410e552da7Schristos #if (defined(__GLIBC__) && !defined(__UCLIBC__)) || \
5420e552da7Schristos platform_needs_custom_semaphore
5430e552da7Schristos STATIC_ASSERT(sizeof(uv_sem_t) >= sizeof(uv_semaphore_t*));
5440e552da7Schristos #endif
5450e552da7Schristos
uv__custom_sem_init(uv_sem_t * sem_,unsigned int value)5460e552da7Schristos static int uv__custom_sem_init(uv_sem_t* sem_, unsigned int value) {
5470e552da7Schristos int err;
5480e552da7Schristos uv_semaphore_t* sem;
5490e552da7Schristos
5500e552da7Schristos sem = uv__malloc(sizeof(*sem));
5510e552da7Schristos if (sem == NULL)
5520e552da7Schristos return UV_ENOMEM;
5530e552da7Schristos
5540e552da7Schristos if ((err = uv_mutex_init(&sem->mutex)) != 0) {
5550e552da7Schristos uv__free(sem);
5560e552da7Schristos return err;
5570e552da7Schristos }
5580e552da7Schristos
5590e552da7Schristos if ((err = uv_cond_init(&sem->cond)) != 0) {
5600e552da7Schristos uv_mutex_destroy(&sem->mutex);
5610e552da7Schristos uv__free(sem);
5620e552da7Schristos return err;
5630e552da7Schristos }
5640e552da7Schristos
5650e552da7Schristos sem->value = value;
5660e552da7Schristos *(uv_semaphore_t**)sem_ = sem;
5670e552da7Schristos return 0;
5680e552da7Schristos }
5690e552da7Schristos
5700e552da7Schristos
uv__custom_sem_destroy(uv_sem_t * sem_)5710e552da7Schristos static void uv__custom_sem_destroy(uv_sem_t* sem_) {
5720e552da7Schristos uv_semaphore_t* sem;
5730e552da7Schristos
5740e552da7Schristos sem = *(uv_semaphore_t**)sem_;
5750e552da7Schristos uv_cond_destroy(&sem->cond);
5760e552da7Schristos uv_mutex_destroy(&sem->mutex);
5770e552da7Schristos uv__free(sem);
5780e552da7Schristos }
5790e552da7Schristos
5800e552da7Schristos
uv__custom_sem_post(uv_sem_t * sem_)5810e552da7Schristos static void uv__custom_sem_post(uv_sem_t* sem_) {
5820e552da7Schristos uv_semaphore_t* sem;
5830e552da7Schristos
5840e552da7Schristos sem = *(uv_semaphore_t**)sem_;
5850e552da7Schristos uv_mutex_lock(&sem->mutex);
5860e552da7Schristos sem->value++;
5870e552da7Schristos if (sem->value == 1)
5880e552da7Schristos uv_cond_signal(&sem->cond);
5890e552da7Schristos uv_mutex_unlock(&sem->mutex);
5900e552da7Schristos }
5910e552da7Schristos
5920e552da7Schristos
uv__custom_sem_wait(uv_sem_t * sem_)5930e552da7Schristos static void uv__custom_sem_wait(uv_sem_t* sem_) {
5940e552da7Schristos uv_semaphore_t* sem;
5950e552da7Schristos
5960e552da7Schristos sem = *(uv_semaphore_t**)sem_;
5970e552da7Schristos uv_mutex_lock(&sem->mutex);
5980e552da7Schristos while (sem->value == 0)
5990e552da7Schristos uv_cond_wait(&sem->cond, &sem->mutex);
6000e552da7Schristos sem->value--;
6010e552da7Schristos uv_mutex_unlock(&sem->mutex);
6020e552da7Schristos }
6030e552da7Schristos
6040e552da7Schristos
uv__custom_sem_trywait(uv_sem_t * sem_)6050e552da7Schristos static int uv__custom_sem_trywait(uv_sem_t* sem_) {
6060e552da7Schristos uv_semaphore_t* sem;
6070e552da7Schristos
6080e552da7Schristos sem = *(uv_semaphore_t**)sem_;
6090e552da7Schristos if (uv_mutex_trylock(&sem->mutex) != 0)
6100e552da7Schristos return UV_EAGAIN;
6110e552da7Schristos
6120e552da7Schristos if (sem->value == 0) {
6130e552da7Schristos uv_mutex_unlock(&sem->mutex);
6140e552da7Schristos return UV_EAGAIN;
6150e552da7Schristos }
6160e552da7Schristos
6170e552da7Schristos sem->value--;
6180e552da7Schristos uv_mutex_unlock(&sem->mutex);
6190e552da7Schristos
6200e552da7Schristos return 0;
6210e552da7Schristos }
6220e552da7Schristos
uv__sem_init(uv_sem_t * sem,unsigned int value)6230e552da7Schristos static int uv__sem_init(uv_sem_t* sem, unsigned int value) {
6240e552da7Schristos if (sem_init(sem, 0, value))
6250e552da7Schristos return UV__ERR(errno);
6260e552da7Schristos return 0;
6270e552da7Schristos }
6280e552da7Schristos
6290e552da7Schristos
uv__sem_destroy(uv_sem_t * sem)6300e552da7Schristos static void uv__sem_destroy(uv_sem_t* sem) {
6310e552da7Schristos if (sem_destroy(sem))
6320e552da7Schristos abort();
6330e552da7Schristos }
6340e552da7Schristos
6350e552da7Schristos
uv__sem_post(uv_sem_t * sem)6360e552da7Schristos static void uv__sem_post(uv_sem_t* sem) {
6370e552da7Schristos if (sem_post(sem))
6380e552da7Schristos abort();
6390e552da7Schristos }
6400e552da7Schristos
6410e552da7Schristos
uv__sem_wait(uv_sem_t * sem)6420e552da7Schristos static void uv__sem_wait(uv_sem_t* sem) {
6430e552da7Schristos int r;
6440e552da7Schristos
6450e552da7Schristos do
6460e552da7Schristos r = sem_wait(sem);
6470e552da7Schristos while (r == -1 && errno == EINTR);
6480e552da7Schristos
6490e552da7Schristos if (r)
6500e552da7Schristos abort();
6510e552da7Schristos }
6520e552da7Schristos
6530e552da7Schristos
uv__sem_trywait(uv_sem_t * sem)6540e552da7Schristos static int uv__sem_trywait(uv_sem_t* sem) {
6550e552da7Schristos int r;
6560e552da7Schristos
6570e552da7Schristos do
6580e552da7Schristos r = sem_trywait(sem);
6590e552da7Schristos while (r == -1 && errno == EINTR);
6600e552da7Schristos
6610e552da7Schristos if (r) {
6620e552da7Schristos if (errno == EAGAIN)
6630e552da7Schristos return UV_EAGAIN;
6640e552da7Schristos abort();
6650e552da7Schristos }
6660e552da7Schristos
6670e552da7Schristos return 0;
6680e552da7Schristos }
6690e552da7Schristos
uv_sem_init(uv_sem_t * sem,unsigned int value)6700e552da7Schristos int uv_sem_init(uv_sem_t* sem, unsigned int value) {
6710e552da7Schristos #if defined(__GLIBC__) && !defined(__UCLIBC__)
6720e552da7Schristos uv_once(&glibc_version_check_once, glibc_version_check);
6730e552da7Schristos #endif
6740e552da7Schristos
6750e552da7Schristos if (platform_needs_custom_semaphore)
6760e552da7Schristos return uv__custom_sem_init(sem, value);
6770e552da7Schristos else
6780e552da7Schristos return uv__sem_init(sem, value);
6790e552da7Schristos }
6800e552da7Schristos
6810e552da7Schristos
uv_sem_destroy(uv_sem_t * sem)6820e552da7Schristos void uv_sem_destroy(uv_sem_t* sem) {
6830e552da7Schristos if (platform_needs_custom_semaphore)
6840e552da7Schristos uv__custom_sem_destroy(sem);
6850e552da7Schristos else
6860e552da7Schristos uv__sem_destroy(sem);
6870e552da7Schristos }
6880e552da7Schristos
6890e552da7Schristos
uv_sem_post(uv_sem_t * sem)6900e552da7Schristos void uv_sem_post(uv_sem_t* sem) {
6910e552da7Schristos if (platform_needs_custom_semaphore)
6920e552da7Schristos uv__custom_sem_post(sem);
6930e552da7Schristos else
6940e552da7Schristos uv__sem_post(sem);
6950e552da7Schristos }
6960e552da7Schristos
6970e552da7Schristos
uv_sem_wait(uv_sem_t * sem)6980e552da7Schristos void uv_sem_wait(uv_sem_t* sem) {
6990e552da7Schristos if (platform_needs_custom_semaphore)
7000e552da7Schristos uv__custom_sem_wait(sem);
7010e552da7Schristos else
7020e552da7Schristos uv__sem_wait(sem);
7030e552da7Schristos }
7040e552da7Schristos
7050e552da7Schristos
uv_sem_trywait(uv_sem_t * sem)7060e552da7Schristos int uv_sem_trywait(uv_sem_t* sem) {
7070e552da7Schristos if (platform_needs_custom_semaphore)
7080e552da7Schristos return uv__custom_sem_trywait(sem);
7090e552da7Schristos else
7100e552da7Schristos return uv__sem_trywait(sem);
7110e552da7Schristos }
7120e552da7Schristos
7130e552da7Schristos #endif /* defined(__APPLE__) && defined(__MACH__) */
7140e552da7Schristos
7150e552da7Schristos
7160e552da7Schristos #if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__)
7170e552da7Schristos
uv_cond_init(uv_cond_t * cond)7180e552da7Schristos int uv_cond_init(uv_cond_t* cond) {
7190e552da7Schristos return UV__ERR(pthread_cond_init(cond, NULL));
7200e552da7Schristos }
7210e552da7Schristos
7220e552da7Schristos #else /* !(defined(__APPLE__) && defined(__MACH__)) */
7230e552da7Schristos
uv_cond_init(uv_cond_t * cond)7240e552da7Schristos int uv_cond_init(uv_cond_t* cond) {
7250e552da7Schristos pthread_condattr_t attr;
7260e552da7Schristos int err;
7270e552da7Schristos
7280e552da7Schristos err = pthread_condattr_init(&attr);
7290e552da7Schristos if (err)
7300e552da7Schristos return UV__ERR(err);
7310e552da7Schristos
7320e552da7Schristos err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
7330e552da7Schristos if (err)
7340e552da7Schristos goto error2;
7350e552da7Schristos
7360e552da7Schristos err = pthread_cond_init(cond, &attr);
7370e552da7Schristos if (err)
7380e552da7Schristos goto error2;
7390e552da7Schristos
7400e552da7Schristos err = pthread_condattr_destroy(&attr);
7410e552da7Schristos if (err)
7420e552da7Schristos goto error;
7430e552da7Schristos
7440e552da7Schristos return 0;
7450e552da7Schristos
7460e552da7Schristos error:
7470e552da7Schristos pthread_cond_destroy(cond);
7480e552da7Schristos error2:
7490e552da7Schristos pthread_condattr_destroy(&attr);
7500e552da7Schristos return UV__ERR(err);
7510e552da7Schristos }
7520e552da7Schristos
7530e552da7Schristos #endif /* defined(__APPLE__) && defined(__MACH__) */
7540e552da7Schristos
uv_cond_destroy(uv_cond_t * cond)7550e552da7Schristos void uv_cond_destroy(uv_cond_t* cond) {
7560e552da7Schristos #if defined(__APPLE__) && defined(__MACH__)
7570e552da7Schristos /* It has been reported that destroying condition variables that have been
7580e552da7Schristos * signalled but not waited on can sometimes result in application crashes.
7590e552da7Schristos * See https://codereview.chromium.org/1323293005.
7600e552da7Schristos */
7610e552da7Schristos pthread_mutex_t mutex;
7620e552da7Schristos struct timespec ts;
7630e552da7Schristos int err;
7640e552da7Schristos
7650e552da7Schristos if (pthread_mutex_init(&mutex, NULL))
7660e552da7Schristos abort();
7670e552da7Schristos
7680e552da7Schristos if (pthread_mutex_lock(&mutex))
7690e552da7Schristos abort();
7700e552da7Schristos
7710e552da7Schristos ts.tv_sec = 0;
7720e552da7Schristos ts.tv_nsec = 1;
7730e552da7Schristos
7740e552da7Schristos err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts);
7750e552da7Schristos if (err != 0 && err != ETIMEDOUT)
7760e552da7Schristos abort();
7770e552da7Schristos
7780e552da7Schristos if (pthread_mutex_unlock(&mutex))
7790e552da7Schristos abort();
7800e552da7Schristos
7810e552da7Schristos if (pthread_mutex_destroy(&mutex))
7820e552da7Schristos abort();
7830e552da7Schristos #endif /* defined(__APPLE__) && defined(__MACH__) */
7840e552da7Schristos
7850e552da7Schristos if (pthread_cond_destroy(cond))
7860e552da7Schristos abort();
7870e552da7Schristos }
7880e552da7Schristos
uv_cond_signal(uv_cond_t * cond)7890e552da7Schristos void uv_cond_signal(uv_cond_t* cond) {
7900e552da7Schristos if (pthread_cond_signal(cond))
7910e552da7Schristos abort();
7920e552da7Schristos }
7930e552da7Schristos
uv_cond_broadcast(uv_cond_t * cond)7940e552da7Schristos void uv_cond_broadcast(uv_cond_t* cond) {
7950e552da7Schristos if (pthread_cond_broadcast(cond))
7960e552da7Schristos abort();
7970e552da7Schristos }
7980e552da7Schristos
uv_cond_wait(uv_cond_t * cond,uv_mutex_t * mutex)7990e552da7Schristos void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) {
8000e552da7Schristos if (pthread_cond_wait(cond, mutex))
8010e552da7Schristos abort();
8020e552da7Schristos }
8030e552da7Schristos
8040e552da7Schristos
uv_cond_timedwait(uv_cond_t * cond,uv_mutex_t * mutex,uint64_t timeout)8050e552da7Schristos int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) {
8060e552da7Schristos int r;
8070e552da7Schristos struct timespec ts;
8080e552da7Schristos #if defined(__MVS__)
8090e552da7Schristos struct timeval tv;
8100e552da7Schristos #endif
8110e552da7Schristos
8120e552da7Schristos #if defined(__APPLE__) && defined(__MACH__)
8130e552da7Schristos ts.tv_sec = timeout / NANOSEC;
8140e552da7Schristos ts.tv_nsec = timeout % NANOSEC;
8150e552da7Schristos r = pthread_cond_timedwait_relative_np(cond, mutex, &ts);
8160e552da7Schristos #else
8170e552da7Schristos #if defined(__MVS__)
8180e552da7Schristos if (gettimeofday(&tv, NULL))
8190e552da7Schristos abort();
8200e552da7Schristos timeout += tv.tv_sec * NANOSEC + tv.tv_usec * 1e3;
8210e552da7Schristos #else
8220e552da7Schristos timeout += uv__hrtime(UV_CLOCK_PRECISE);
8230e552da7Schristos #endif
8240e552da7Schristos ts.tv_sec = timeout / NANOSEC;
8250e552da7Schristos ts.tv_nsec = timeout % NANOSEC;
8260e552da7Schristos r = pthread_cond_timedwait(cond, mutex, &ts);
8270e552da7Schristos #endif
8280e552da7Schristos
8290e552da7Schristos
8300e552da7Schristos if (r == 0)
8310e552da7Schristos return 0;
8320e552da7Schristos
8330e552da7Schristos if (r == ETIMEDOUT)
8340e552da7Schristos return UV_ETIMEDOUT;
8350e552da7Schristos
8360e552da7Schristos abort();
8370e552da7Schristos #ifndef __SUNPRO_C
8380e552da7Schristos return UV_EINVAL; /* Satisfy the compiler. */
8390e552da7Schristos #endif
8400e552da7Schristos }
8410e552da7Schristos
8420e552da7Schristos
uv_key_create(uv_key_t * key)8430e552da7Schristos int uv_key_create(uv_key_t* key) {
8440e552da7Schristos return UV__ERR(pthread_key_create(key, NULL));
8450e552da7Schristos }
8460e552da7Schristos
8470e552da7Schristos
uv_key_delete(uv_key_t * key)8480e552da7Schristos void uv_key_delete(uv_key_t* key) {
8490e552da7Schristos if (pthread_key_delete(*key))
8500e552da7Schristos abort();
8510e552da7Schristos }
8520e552da7Schristos
8530e552da7Schristos
uv_key_get(uv_key_t * key)8540e552da7Schristos void* uv_key_get(uv_key_t* key) {
8550e552da7Schristos return pthread_getspecific(*key);
8560e552da7Schristos }
8570e552da7Schristos
8580e552da7Schristos
uv_key_set(uv_key_t * key,void * value)8590e552da7Schristos void uv_key_set(uv_key_t* key, void* value) {
8600e552da7Schristos if (pthread_setspecific(*key, value))
8610e552da7Schristos abort();
8620e552da7Schristos }
863