xref: /netbsd-src/external/mit/libuv/dist/src/unix/thread.c (revision 5f2f42719cd62ff11fd913b40b7ce19f07c4fd25)
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, &params, 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