1 | /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. |
2 | * |
3 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
4 | * of this software and associated documentation files (the "Software"), to |
5 | * deal in the Software without restriction, including without limitation the |
6 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
7 | * sell copies of the Software, and to permit persons to whom the Software is |
8 | * furnished to do so, subject to the following conditions: |
9 | * |
10 | * The above copyright notice and this permission notice shall be included in |
11 | * all copies or substantial portions of the Software. |
12 | * |
13 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
14 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
15 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
16 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
17 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
18 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
19 | * IN THE SOFTWARE. |
20 | */ |
21 | |
22 | #include "uv.h" |
23 | #include "internal.h" |
24 | |
25 | #include <pthread.h> |
26 | #include <assert.h> |
27 | #include <errno.h> |
28 | |
29 | #include <sys/time.h> |
30 | #include <sys/resource.h> /* getrlimit() */ |
31 | #include <unistd.h> /* getpagesize() */ |
32 | |
33 | #include <limits.h> |
34 | |
35 | #ifdef __MVS__ |
36 | #include <sys/ipc.h> |
37 | #include <sys/sem.h> |
38 | #endif |
39 | |
40 | #if defined(__GLIBC__) && !defined(__UCLIBC__) |
41 | #include <gnu/libc-version.h> /* gnu_get_libc_version() */ |
42 | #endif |
43 | |
44 | #undef NANOSEC |
45 | #define NANOSEC ((uint64_t) 1e9) |
46 | |
47 | #if defined(PTHREAD_BARRIER_SERIAL_THREAD) |
48 | STATIC_ASSERT(sizeof(uv_barrier_t) == sizeof(pthread_barrier_t)); |
49 | #endif |
50 | |
51 | /* Note: guard clauses should match uv_barrier_t's in include/uv/unix.h. */ |
52 | #if defined(_AIX) || \ |
53 | defined(__OpenBSD__) || \ |
54 | !defined(PTHREAD_BARRIER_SERIAL_THREAD) |
55 | int uv_barrier_init(uv_barrier_t* barrier, unsigned int count) { |
56 | struct _uv_barrier* b; |
57 | int rc; |
58 | |
59 | if (barrier == NULL || count == 0) |
60 | return UV_EINVAL; |
61 | |
62 | b = uv__malloc(sizeof(*b)); |
63 | if (b == NULL) |
64 | return UV_ENOMEM; |
65 | |
66 | b->in = 0; |
67 | b->out = 0; |
68 | b->threshold = count; |
69 | |
70 | rc = uv_mutex_init(&b->mutex); |
71 | if (rc != 0) |
72 | goto error2; |
73 | |
74 | rc = uv_cond_init(&b->cond); |
75 | if (rc != 0) |
76 | goto error; |
77 | |
78 | barrier->b = b; |
79 | return 0; |
80 | |
81 | error: |
82 | uv_mutex_destroy(&b->mutex); |
83 | error2: |
84 | uv__free(b); |
85 | return rc; |
86 | } |
87 | |
88 | |
89 | int uv_barrier_wait(uv_barrier_t* barrier) { |
90 | struct _uv_barrier* b; |
91 | int last; |
92 | |
93 | if (barrier == NULL || barrier->b == NULL) |
94 | return UV_EINVAL; |
95 | |
96 | b = barrier->b; |
97 | uv_mutex_lock(&b->mutex); |
98 | |
99 | if (++b->in == b->threshold) { |
100 | b->in = 0; |
101 | b->out = b->threshold; |
102 | uv_cond_signal(&b->cond); |
103 | } else { |
104 | do |
105 | uv_cond_wait(&b->cond, &b->mutex); |
106 | while (b->in != 0); |
107 | } |
108 | |
109 | last = (--b->out == 0); |
110 | if (!last) |
111 | uv_cond_signal(&b->cond); /* Not needed for last thread. */ |
112 | |
113 | uv_mutex_unlock(&b->mutex); |
114 | return last; |
115 | } |
116 | |
117 | |
118 | void uv_barrier_destroy(uv_barrier_t* barrier) { |
119 | struct _uv_barrier* b; |
120 | |
121 | b = barrier->b; |
122 | uv_mutex_lock(&b->mutex); |
123 | |
124 | assert(b->in == 0); |
125 | assert(b->out == 0); |
126 | |
127 | if (b->in != 0 || b->out != 0) |
128 | abort(); |
129 | |
130 | uv_mutex_unlock(&b->mutex); |
131 | uv_mutex_destroy(&b->mutex); |
132 | uv_cond_destroy(&b->cond); |
133 | |
134 | uv__free(barrier->b); |
135 | barrier->b = NULL; |
136 | } |
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 | |
162 | #endif |
163 | |
164 | |
165 | /* On MacOS, threads other than the main thread are created with a reduced |
166 | * stack size by default. Adjust to RLIMIT_STACK aligned to the page size. |
167 | * |
168 | * On Linux, threads created by musl have a much smaller stack than threads |
169 | * created by glibc (80 vs. 2048 or 4096 kB.) Follow glibc for consistency. |
170 | */ |
171 | static size_t thread_stack_size(void) { |
172 | #if defined(__APPLE__) || defined(__linux__) |
173 | struct rlimit lim; |
174 | |
175 | /* getrlimit() can fail on some aarch64 systems due to a glibc bug where |
176 | * the system call wrapper invokes the wrong system call. Don't treat |
177 | * that as fatal, just use the default stack size instead. |
178 | */ |
179 | if (0 == getrlimit(RLIMIT_STACK, &lim) && lim.rlim_cur != RLIM_INFINITY) { |
180 | /* pthread_attr_setstacksize() expects page-aligned values. */ |
181 | lim.rlim_cur -= lim.rlim_cur % (rlim_t) getpagesize(); |
182 | |
183 | /* Musl's PTHREAD_STACK_MIN is 2 KB on all architectures, which is |
184 | * too small to safely receive signals on. |
185 | * |
186 | * Musl's PTHREAD_STACK_MIN + MINSIGSTKSZ == 8192 on arm64 (which has |
187 | * the largest MINSIGSTKSZ of the architectures that musl supports) so |
188 | * let's use that as a lower bound. |
189 | * |
190 | * We use a hardcoded value because PTHREAD_STACK_MIN + MINSIGSTKSZ |
191 | * is between 28 and 133 KB when compiling against glibc, depending |
192 | * on the architecture. |
193 | */ |
194 | if (lim.rlim_cur >= 8192) |
195 | if (lim.rlim_cur >= PTHREAD_STACK_MIN) |
196 | return lim.rlim_cur; |
197 | } |
198 | #endif |
199 | |
200 | #if !defined(__linux__) |
201 | return 0; |
202 | #elif defined(__PPC__) || defined(__ppc__) || defined(__powerpc__) |
203 | return 4 << 20; /* glibc default. */ |
204 | #else |
205 | return 2 << 20; /* glibc default. */ |
206 | #endif |
207 | } |
208 | |
209 | |
210 | int uv_thread_create(uv_thread_t *tid, void (*entry)(void *arg), void *arg) { |
211 | uv_thread_options_t params; |
212 | params.flags = UV_THREAD_NO_FLAGS; |
213 | return uv_thread_create_ex(tid, ¶ms, entry, arg); |
214 | } |
215 | |
216 | int uv_thread_create_ex(uv_thread_t* tid, |
217 | const uv_thread_options_t* params, |
218 | void (*entry)(void *arg), |
219 | void *arg) { |
220 | int err; |
221 | pthread_attr_t* attr; |
222 | pthread_attr_t attr_storage; |
223 | size_t pagesize; |
224 | size_t stack_size; |
225 | |
226 | /* Used to squelch a -Wcast-function-type warning. */ |
227 | union { |
228 | void (*in)(void*); |
229 | void* (*out)(void*); |
230 | } f; |
231 | |
232 | stack_size = |
233 | params->flags & UV_THREAD_HAS_STACK_SIZE ? params->stack_size : 0; |
234 | |
235 | attr = NULL; |
236 | if (stack_size == 0) { |
237 | stack_size = thread_stack_size(); |
238 | } else { |
239 | pagesize = (size_t)getpagesize(); |
240 | /* Round up to the nearest page boundary. */ |
241 | stack_size = (stack_size + pagesize - 1) &~ (pagesize - 1); |
242 | #ifdef PTHREAD_STACK_MIN |
243 | if (stack_size < PTHREAD_STACK_MIN) |
244 | stack_size = PTHREAD_STACK_MIN; |
245 | #endif |
246 | } |
247 | |
248 | if (stack_size > 0) { |
249 | attr = &attr_storage; |
250 | |
251 | if (pthread_attr_init(attr)) |
252 | abort(); |
253 | |
254 | if (pthread_attr_setstacksize(attr, stack_size)) |
255 | abort(); |
256 | } |
257 | |
258 | f.in = entry; |
259 | err = pthread_create(tid, attr, f.out, arg); |
260 | |
261 | if (attr != NULL) |
262 | pthread_attr_destroy(attr); |
263 | |
264 | return UV__ERR(err); |
265 | } |
266 | |
267 | |
268 | uv_thread_t uv_thread_self(void) { |
269 | return pthread_self(); |
270 | } |
271 | |
272 | int uv_thread_join(uv_thread_t *tid) { |
273 | return UV__ERR(pthread_join(*tid, NULL)); |
274 | } |
275 | |
276 | |
277 | int uv_thread_equal(const uv_thread_t* t1, const uv_thread_t* t2) { |
278 | return pthread_equal(*t1, *t2); |
279 | } |
280 | |
281 | |
282 | int uv_mutex_init(uv_mutex_t* mutex) { |
283 | #if defined(NDEBUG) || !defined(PTHREAD_MUTEX_ERRORCHECK) |
284 | return UV__ERR(pthread_mutex_init(mutex, NULL)); |
285 | #else |
286 | pthread_mutexattr_t attr; |
287 | int err; |
288 | |
289 | if (pthread_mutexattr_init(&attr)) |
290 | abort(); |
291 | |
292 | if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK)) |
293 | abort(); |
294 | |
295 | err = pthread_mutex_init(mutex, &attr); |
296 | |
297 | if (pthread_mutexattr_destroy(&attr)) |
298 | abort(); |
299 | |
300 | return UV__ERR(err); |
301 | #endif |
302 | } |
303 | |
304 | |
305 | int uv_mutex_init_recursive(uv_mutex_t* mutex) { |
306 | pthread_mutexattr_t attr; |
307 | int err; |
308 | |
309 | if (pthread_mutexattr_init(&attr)) |
310 | abort(); |
311 | |
312 | if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) |
313 | abort(); |
314 | |
315 | err = pthread_mutex_init(mutex, &attr); |
316 | |
317 | if (pthread_mutexattr_destroy(&attr)) |
318 | abort(); |
319 | |
320 | return UV__ERR(err); |
321 | } |
322 | |
323 | |
324 | void uv_mutex_destroy(uv_mutex_t* mutex) { |
325 | if (pthread_mutex_destroy(mutex)) |
326 | abort(); |
327 | } |
328 | |
329 | |
330 | void uv_mutex_lock(uv_mutex_t* mutex) { |
331 | if (pthread_mutex_lock(mutex)) |
332 | abort(); |
333 | } |
334 | |
335 | |
336 | int uv_mutex_trylock(uv_mutex_t* mutex) { |
337 | int err; |
338 | |
339 | err = pthread_mutex_trylock(mutex); |
340 | if (err) { |
341 | if (err != EBUSY && err != EAGAIN) |
342 | abort(); |
343 | return UV_EBUSY; |
344 | } |
345 | |
346 | return 0; |
347 | } |
348 | |
349 | |
350 | void uv_mutex_unlock(uv_mutex_t* mutex) { |
351 | if (pthread_mutex_unlock(mutex)) |
352 | abort(); |
353 | } |
354 | |
355 | |
356 | int uv_rwlock_init(uv_rwlock_t* rwlock) { |
357 | return UV__ERR(pthread_rwlock_init(rwlock, NULL)); |
358 | } |
359 | |
360 | |
361 | void uv_rwlock_destroy(uv_rwlock_t* rwlock) { |
362 | if (pthread_rwlock_destroy(rwlock)) |
363 | abort(); |
364 | } |
365 | |
366 | |
367 | void uv_rwlock_rdlock(uv_rwlock_t* rwlock) { |
368 | if (pthread_rwlock_rdlock(rwlock)) |
369 | abort(); |
370 | } |
371 | |
372 | |
373 | int uv_rwlock_tryrdlock(uv_rwlock_t* rwlock) { |
374 | int err; |
375 | |
376 | err = pthread_rwlock_tryrdlock(rwlock); |
377 | if (err) { |
378 | if (err != EBUSY && err != EAGAIN) |
379 | abort(); |
380 | return UV_EBUSY; |
381 | } |
382 | |
383 | return 0; |
384 | } |
385 | |
386 | |
387 | void uv_rwlock_rdunlock(uv_rwlock_t* rwlock) { |
388 | if (pthread_rwlock_unlock(rwlock)) |
389 | abort(); |
390 | } |
391 | |
392 | |
393 | void uv_rwlock_wrlock(uv_rwlock_t* rwlock) { |
394 | if (pthread_rwlock_wrlock(rwlock)) |
395 | abort(); |
396 | } |
397 | |
398 | |
399 | int uv_rwlock_trywrlock(uv_rwlock_t* rwlock) { |
400 | int err; |
401 | |
402 | err = pthread_rwlock_trywrlock(rwlock); |
403 | if (err) { |
404 | if (err != EBUSY && err != EAGAIN) |
405 | abort(); |
406 | return UV_EBUSY; |
407 | } |
408 | |
409 | return 0; |
410 | } |
411 | |
412 | |
413 | void uv_rwlock_wrunlock(uv_rwlock_t* rwlock) { |
414 | if (pthread_rwlock_unlock(rwlock)) |
415 | abort(); |
416 | } |
417 | |
418 | |
419 | void uv_once(uv_once_t* guard, void (*callback)(void)) { |
420 | if (pthread_once(guard, callback)) |
421 | abort(); |
422 | } |
423 | |
424 | #if defined(__APPLE__) && defined(__MACH__) |
425 | |
426 | int uv_sem_init(uv_sem_t* sem, unsigned int value) { |
427 | kern_return_t err; |
428 | |
429 | err = semaphore_create(mach_task_self(), sem, SYNC_POLICY_FIFO, value); |
430 | if (err == KERN_SUCCESS) |
431 | return 0; |
432 | if (err == KERN_INVALID_ARGUMENT) |
433 | return UV_EINVAL; |
434 | if (err == KERN_RESOURCE_SHORTAGE) |
435 | return UV_ENOMEM; |
436 | |
437 | abort(); |
438 | return UV_EINVAL; /* Satisfy the compiler. */ |
439 | } |
440 | |
441 | |
442 | void uv_sem_destroy(uv_sem_t* sem) { |
443 | if (semaphore_destroy(mach_task_self(), *sem)) |
444 | abort(); |
445 | } |
446 | |
447 | |
448 | void uv_sem_post(uv_sem_t* sem) { |
449 | if (semaphore_signal(*sem)) |
450 | abort(); |
451 | } |
452 | |
453 | |
454 | void uv_sem_wait(uv_sem_t* sem) { |
455 | int r; |
456 | |
457 | do |
458 | r = semaphore_wait(*sem); |
459 | while (r == KERN_ABORTED); |
460 | |
461 | if (r != KERN_SUCCESS) |
462 | abort(); |
463 | } |
464 | |
465 | |
466 | int uv_sem_trywait(uv_sem_t* sem) { |
467 | mach_timespec_t interval; |
468 | kern_return_t err; |
469 | |
470 | interval.tv_sec = 0; |
471 | interval.tv_nsec = 0; |
472 | |
473 | err = semaphore_timedwait(*sem, interval); |
474 | if (err == KERN_SUCCESS) |
475 | return 0; |
476 | if (err == KERN_OPERATION_TIMED_OUT) |
477 | return UV_EAGAIN; |
478 | |
479 | abort(); |
480 | return UV_EINVAL; /* Satisfy the compiler. */ |
481 | } |
482 | |
483 | #else /* !(defined(__APPLE__) && defined(__MACH__)) */ |
484 | |
485 | #if defined(__GLIBC__) && !defined(__UCLIBC__) |
486 | |
487 | /* Hack around https://sourceware.org/bugzilla/show_bug.cgi?id=12674 |
488 | * by providing a custom implementation for glibc < 2.21 in terms of other |
489 | * concurrency primitives. |
490 | * Refs: https://github.com/nodejs/node/issues/19903 */ |
491 | |
492 | /* To preserve ABI compatibility, we treat the uv_sem_t as storage for |
493 | * a pointer to the actual struct we're using underneath. */ |
494 | |
495 | static uv_once_t glibc_version_check_once = UV_ONCE_INIT; |
496 | static int platform_needs_custom_semaphore = 0; |
497 | |
498 | static void glibc_version_check(void) { |
499 | const char* version = gnu_get_libc_version(); |
500 | platform_needs_custom_semaphore = |
501 | version[0] == '2' && version[1] == '.' && |
502 | atoi(version + 2) < 21; |
503 | } |
504 | |
505 | #elif defined(__MVS__) |
506 | |
507 | #define platform_needs_custom_semaphore 1 |
508 | |
509 | #else /* !defined(__GLIBC__) && !defined(__MVS__) */ |
510 | |
511 | #define platform_needs_custom_semaphore 0 |
512 | |
513 | #endif |
514 | |
515 | typedef struct uv_semaphore_s { |
516 | uv_mutex_t mutex; |
517 | uv_cond_t cond; |
518 | unsigned int value; |
519 | } uv_semaphore_t; |
520 | |
521 | #if (defined(__GLIBC__) && !defined(__UCLIBC__)) || \ |
522 | platform_needs_custom_semaphore |
523 | STATIC_ASSERT(sizeof(uv_sem_t) >= sizeof(uv_semaphore_t*)); |
524 | #endif |
525 | |
526 | static int uv__custom_sem_init(uv_sem_t* sem_, unsigned int value) { |
527 | int err; |
528 | uv_semaphore_t* sem; |
529 | |
530 | sem = uv__malloc(sizeof(*sem)); |
531 | if (sem == NULL) |
532 | return UV_ENOMEM; |
533 | |
534 | if ((err = uv_mutex_init(&sem->mutex)) != 0) { |
535 | uv__free(sem); |
536 | return err; |
537 | } |
538 | |
539 | if ((err = uv_cond_init(&sem->cond)) != 0) { |
540 | uv_mutex_destroy(&sem->mutex); |
541 | uv__free(sem); |
542 | return err; |
543 | } |
544 | |
545 | sem->value = value; |
546 | *(uv_semaphore_t**)sem_ = sem; |
547 | return 0; |
548 | } |
549 | |
550 | |
551 | static void uv__custom_sem_destroy(uv_sem_t* sem_) { |
552 | uv_semaphore_t* sem; |
553 | |
554 | sem = *(uv_semaphore_t**)sem_; |
555 | uv_cond_destroy(&sem->cond); |
556 | uv_mutex_destroy(&sem->mutex); |
557 | uv__free(sem); |
558 | } |
559 | |
560 | |
561 | static void uv__custom_sem_post(uv_sem_t* sem_) { |
562 | uv_semaphore_t* sem; |
563 | |
564 | sem = *(uv_semaphore_t**)sem_; |
565 | uv_mutex_lock(&sem->mutex); |
566 | sem->value++; |
567 | if (sem->value == 1) |
568 | uv_cond_signal(&sem->cond); |
569 | uv_mutex_unlock(&sem->mutex); |
570 | } |
571 | |
572 | |
573 | static void uv__custom_sem_wait(uv_sem_t* sem_) { |
574 | uv_semaphore_t* sem; |
575 | |
576 | sem = *(uv_semaphore_t**)sem_; |
577 | uv_mutex_lock(&sem->mutex); |
578 | while (sem->value == 0) |
579 | uv_cond_wait(&sem->cond, &sem->mutex); |
580 | sem->value--; |
581 | uv_mutex_unlock(&sem->mutex); |
582 | } |
583 | |
584 | |
585 | static int uv__custom_sem_trywait(uv_sem_t* sem_) { |
586 | uv_semaphore_t* sem; |
587 | |
588 | sem = *(uv_semaphore_t**)sem_; |
589 | if (uv_mutex_trylock(&sem->mutex) != 0) |
590 | return UV_EAGAIN; |
591 | |
592 | if (sem->value == 0) { |
593 | uv_mutex_unlock(&sem->mutex); |
594 | return UV_EAGAIN; |
595 | } |
596 | |
597 | sem->value--; |
598 | uv_mutex_unlock(&sem->mutex); |
599 | |
600 | return 0; |
601 | } |
602 | |
603 | static int uv__sem_init(uv_sem_t* sem, unsigned int value) { |
604 | if (sem_init(sem, 0, value)) |
605 | return UV__ERR(errno); |
606 | return 0; |
607 | } |
608 | |
609 | |
610 | static void uv__sem_destroy(uv_sem_t* sem) { |
611 | if (sem_destroy(sem)) |
612 | abort(); |
613 | } |
614 | |
615 | |
616 | static void uv__sem_post(uv_sem_t* sem) { |
617 | if (sem_post(sem)) |
618 | abort(); |
619 | } |
620 | |
621 | |
622 | static void uv__sem_wait(uv_sem_t* sem) { |
623 | int r; |
624 | |
625 | do |
626 | r = sem_wait(sem); |
627 | while (r == -1 && errno == EINTR); |
628 | |
629 | if (r) |
630 | abort(); |
631 | } |
632 | |
633 | |
634 | static int uv__sem_trywait(uv_sem_t* sem) { |
635 | int r; |
636 | |
637 | do |
638 | r = sem_trywait(sem); |
639 | while (r == -1 && errno == EINTR); |
640 | |
641 | if (r) { |
642 | if (errno == EAGAIN) |
643 | return UV_EAGAIN; |
644 | abort(); |
645 | } |
646 | |
647 | return 0; |
648 | } |
649 | |
650 | int uv_sem_init(uv_sem_t* sem, unsigned int value) { |
651 | #if defined(__GLIBC__) && !defined(__UCLIBC__) |
652 | uv_once(&glibc_version_check_once, glibc_version_check); |
653 | #endif |
654 | |
655 | if (platform_needs_custom_semaphore) |
656 | return uv__custom_sem_init(sem, value); |
657 | else |
658 | return uv__sem_init(sem, value); |
659 | } |
660 | |
661 | |
662 | void uv_sem_destroy(uv_sem_t* sem) { |
663 | if (platform_needs_custom_semaphore) |
664 | uv__custom_sem_destroy(sem); |
665 | else |
666 | uv__sem_destroy(sem); |
667 | } |
668 | |
669 | |
670 | void uv_sem_post(uv_sem_t* sem) { |
671 | if (platform_needs_custom_semaphore) |
672 | uv__custom_sem_post(sem); |
673 | else |
674 | uv__sem_post(sem); |
675 | } |
676 | |
677 | |
678 | void uv_sem_wait(uv_sem_t* sem) { |
679 | if (platform_needs_custom_semaphore) |
680 | uv__custom_sem_wait(sem); |
681 | else |
682 | uv__sem_wait(sem); |
683 | } |
684 | |
685 | |
686 | int uv_sem_trywait(uv_sem_t* sem) { |
687 | if (platform_needs_custom_semaphore) |
688 | return uv__custom_sem_trywait(sem); |
689 | else |
690 | return uv__sem_trywait(sem); |
691 | } |
692 | |
693 | #endif /* defined(__APPLE__) && defined(__MACH__) */ |
694 | |
695 | |
696 | #if defined(__APPLE__) && defined(__MACH__) || defined(__MVS__) |
697 | |
698 | int uv_cond_init(uv_cond_t* cond) { |
699 | return UV__ERR(pthread_cond_init(cond, NULL)); |
700 | } |
701 | |
702 | #else /* !(defined(__APPLE__) && defined(__MACH__)) */ |
703 | |
704 | int uv_cond_init(uv_cond_t* cond) { |
705 | pthread_condattr_t attr; |
706 | int err; |
707 | |
708 | err = pthread_condattr_init(&attr); |
709 | if (err) |
710 | return UV__ERR(err); |
711 | |
712 | err = pthread_condattr_setclock(&attr, CLOCK_MONOTONIC); |
713 | if (err) |
714 | goto error2; |
715 | |
716 | err = pthread_cond_init(cond, &attr); |
717 | if (err) |
718 | goto error2; |
719 | |
720 | err = pthread_condattr_destroy(&attr); |
721 | if (err) |
722 | goto error; |
723 | |
724 | return 0; |
725 | |
726 | error: |
727 | pthread_cond_destroy(cond); |
728 | error2: |
729 | pthread_condattr_destroy(&attr); |
730 | return UV__ERR(err); |
731 | } |
732 | |
733 | #endif /* defined(__APPLE__) && defined(__MACH__) */ |
734 | |
735 | void uv_cond_destroy(uv_cond_t* cond) { |
736 | #if defined(__APPLE__) && defined(__MACH__) |
737 | /* It has been reported that destroying condition variables that have been |
738 | * signalled but not waited on can sometimes result in application crashes. |
739 | * See https://codereview.chromium.org/1323293005. |
740 | */ |
741 | pthread_mutex_t mutex; |
742 | struct timespec ts; |
743 | int err; |
744 | |
745 | if (pthread_mutex_init(&mutex, NULL)) |
746 | abort(); |
747 | |
748 | if (pthread_mutex_lock(&mutex)) |
749 | abort(); |
750 | |
751 | ts.tv_sec = 0; |
752 | ts.tv_nsec = 1; |
753 | |
754 | err = pthread_cond_timedwait_relative_np(cond, &mutex, &ts); |
755 | if (err != 0 && err != ETIMEDOUT) |
756 | abort(); |
757 | |
758 | if (pthread_mutex_unlock(&mutex)) |
759 | abort(); |
760 | |
761 | if (pthread_mutex_destroy(&mutex)) |
762 | abort(); |
763 | #endif /* defined(__APPLE__) && defined(__MACH__) */ |
764 | |
765 | if (pthread_cond_destroy(cond)) |
766 | abort(); |
767 | } |
768 | |
769 | void uv_cond_signal(uv_cond_t* cond) { |
770 | if (pthread_cond_signal(cond)) |
771 | abort(); |
772 | } |
773 | |
774 | void uv_cond_broadcast(uv_cond_t* cond) { |
775 | if (pthread_cond_broadcast(cond)) |
776 | abort(); |
777 | } |
778 | |
779 | void uv_cond_wait(uv_cond_t* cond, uv_mutex_t* mutex) { |
780 | if (pthread_cond_wait(cond, mutex)) |
781 | abort(); |
782 | } |
783 | |
784 | |
785 | int uv_cond_timedwait(uv_cond_t* cond, uv_mutex_t* mutex, uint64_t timeout) { |
786 | int r; |
787 | struct timespec ts; |
788 | #if defined(__MVS__) |
789 | struct timeval tv; |
790 | #endif |
791 | |
792 | #if defined(__APPLE__) && defined(__MACH__) |
793 | ts.tv_sec = timeout / NANOSEC; |
794 | ts.tv_nsec = timeout % NANOSEC; |
795 | r = pthread_cond_timedwait_relative_np(cond, mutex, &ts); |
796 | #else |
797 | #if defined(__MVS__) |
798 | if (gettimeofday(&tv, NULL)) |
799 | abort(); |
800 | timeout += tv.tv_sec * NANOSEC + tv.tv_usec * 1e3; |
801 | #else |
802 | timeout += uv__hrtime(UV_CLOCK_PRECISE); |
803 | #endif |
804 | ts.tv_sec = timeout / NANOSEC; |
805 | ts.tv_nsec = timeout % NANOSEC; |
806 | r = pthread_cond_timedwait(cond, mutex, &ts); |
807 | #endif |
808 | |
809 | |
810 | if (r == 0) |
811 | return 0; |
812 | |
813 | if (r == ETIMEDOUT) |
814 | return UV_ETIMEDOUT; |
815 | |
816 | abort(); |
817 | #ifndef __SUNPRO_C |
818 | return UV_EINVAL; /* Satisfy the compiler. */ |
819 | #endif |
820 | } |
821 | |
822 | |
823 | int uv_key_create(uv_key_t* key) { |
824 | return UV__ERR(pthread_key_create(key, NULL)); |
825 | } |
826 | |
827 | |
828 | void uv_key_delete(uv_key_t* key) { |
829 | if (pthread_key_delete(*key)) |
830 | abort(); |
831 | } |
832 | |
833 | |
834 | void* uv_key_get(uv_key_t* key) { |
835 | return pthread_getspecific(*key); |
836 | } |
837 | |
838 | |
839 | void uv_key_set(uv_key_t* key, void* value) { |
840 | if (pthread_setspecific(*key, value)) |
841 | abort(); |
842 | } |
843 | |