x86: R_SCRATCH_4 may alias R_SAVED_2; make R_SI and R_DI allocatable
[ajla.git] / th_posix.c
blobbf4845507030d335d942b128cd61ffa582972e22
1 /*
2 * Copyright (C) 2024 Mikulas Patocka
4 * This file is part of Ajla.
6 * Ajla is free software: you can redistribute it and/or modify it under the
7 * terms of the GNU General Public License as published by the Free Software
8 * Foundation, either version 3 of the License, or (at your option) any later
9 * version.
11 * Ajla is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
13 * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along with
16 * Ajla. If not, see <https://www.gnu.org/licenses/>.
19 #include "ajla.h"
21 #include "obj_reg.h"
22 #include "str.h"
23 #include "os.h"
24 #include "os_util.h"
26 #include "thread.h"
28 #ifdef THREAD_POSIX
30 #if defined(HAVE_PTHREAD_CONDATTR_SETCLOCK) && defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_MONOTONIC)
31 #define USE_PTHREAD_CONDATTR
32 #endif
34 #ifndef USE_PTHREAD_CONDATTR
35 #include <sys/time.h>
36 #else
37 #include <time.h>
38 static clockid_t clock_id;
39 #endif
41 #if defined(HAVE_SYS_PARAM_H)
42 #include <sys/param.h>
43 #endif
44 #if defined(HAVE_SYS_PSTAT_H)
45 #include <sys/pstat.h>
46 #endif
47 #if defined(HAVE_SYS_SYSCTL_H) && defined(HAVE_SYSCTL) && defined(CTL_HW) && defined(HW_NCPU)
48 #include <sys/sysctl.h>
49 #endif
51 uchar_efficient_t thread_needs_barriers = true;
53 static inline unsigned thread_concurrency_getdynamic(void)
55 #if defined(HAVE_SYS_PSTAT_H) && defined(HAVE_PSTAT_GETDYNAMIC)
56 struct pst_dynamic pst;
57 int ir;
58 EINTR_LOOP(ir, pstat_getdynamic(&pst, sizeof(pst), 1, 0));
59 if (ir == 1) {
60 if (unlikely(pst.psd_proc_cnt <= 0)) {
61 warning("pstat_getdynamic returned invalid value %d", (int)pst.psd_proc_cnt);
62 return 0;
64 return (unsigned)pst.psd_proc_cnt;
66 #endif
67 return 0;
71 static inline unsigned thread_concurrency_sysctl(void)
73 #if defined(HAVE_SYSCTL) && defined(CTL_HW) && defined(HW_NCPU)
74 int n_cpus;
75 int mib[2];
76 size_t sz;
77 int ir;
78 n_cpus = 0;
79 mib[0] = CTL_HW;
80 mib[1] = HW_NCPU;
81 sz = sizeof(n_cpus);
82 EINTR_LOOP(ir, sysctl(mib, 2, &n_cpus, &sz, NULL, 0));
83 if (likely(!ir)) {
84 if (likely(n_cpus > 0))
85 return (unsigned)n_cpus;
86 warning("sysctl(CTL_HW,HW_NCPU) returned invalid value %d", n_cpus);
87 } else {
89 int er = errno;
90 warning("sysctl(CTL_HW,HW_NCPU) returned error: %d, %s", er, error_decode(error_from_errno(EC_SYSCALL, er)));
93 #endif
94 return 0;
97 #ifdef HAVE_UNISTD_H
98 #include <unistd.h>
99 #endif
101 static inline unsigned thread_concurrency_sysconf(void)
103 #if !(defined(UNUSUAL) && defined(__linux__))
104 int attr_unused ir;
105 const char attr_unused *str;
106 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
107 errno = 0;
108 str = "sysconf(_SC_NPROCESSORS_ONLN)";
109 EINTR_LOOP(ir, sysconf(_SC_NPROCESSORS_ONLN));
110 #elif defined(HAVE_SYSCONF) && defined(_SC_NPROC_ONLN)
111 errno = 0;
112 str = "sysconf(_SC_NPROC_ONLN)";
113 EINTR_LOOP(ir, sysconf(_SC_NPROC_ONLN));
114 #else
115 return 0;
116 #endif
117 if (likely(ir > 0))
118 return ir;
119 if (ir == -1) {
121 int er = errno;
122 warning("%s returned error: %d, %s", str, er, error_decode(error_from_errno(EC_SYSCALL, er)));
124 } else {
125 warning("%s returned invalid value %d", str, ir);
127 #endif
128 return 0;
131 static inline unsigned thread_concurrency_linux(void)
133 #if defined(__linux__)
134 ajla_error_t sink;
135 char *str;
136 const char *p;
137 size_t len;
138 unsigned n_cpus;
139 if (unlikely(!os_read_file("/proc/cpuinfo", &str, &len, &sink)))
140 return 0;
141 array_add(char, &str, &len, 0);
142 p = str;
143 n_cpus = 0;
144 while (1) {
145 if (!strncmp(p, "processor", 9)) {
146 n_cpus++;
148 p = strchr(p, '\n');
149 if (unlikely(!p))
150 break;
151 p++;
153 mem_free(str);
154 return n_cpus;
155 #endif
156 return 0;
159 unsigned thread_concurrency(void)
161 unsigned ret;
162 #ifdef thread_concurrency_win32_
163 thread_concurrency_win32_;
164 #endif
165 if ((ret = thread_concurrency_getdynamic()))
166 return ret;
167 if ((ret = thread_concurrency_sysctl()))
168 return ret;
169 if ((ret = thread_concurrency_sysconf()))
170 return ret;
171 if ((ret = thread_concurrency_linux()))
172 return ret;
173 return 1;
176 static pthread_mutexattr_t mutex_attr;
177 static pthread_rwlockattr_t rwmutex_attr;
178 #ifdef USE_PTHREAD_CONDATTR
179 static pthread_condattr_t cond_attr;
180 #define cond_attr_p (&cond_attr)
181 #else
182 #define cond_attr_p NULL
183 #endif
184 static pthread_attr_t thread_attr;
186 #define do_pthread_mutex_init(m) \
187 do { \
188 int r; \
189 r = pthread_mutex_init(m, &mutex_attr); \
190 if (unlikely(r)) \
191 fatal("pthread_mutex_init failed at %s: %d, %s", position_string(position_arg), r, error_decode(error_from_errno(EC_SYSCALL, r)));\
192 } while (0)
194 #define do_pthread_mutex_done(m) \
195 do { \
196 int r; \
197 r = pthread_mutex_destroy(m); \
198 if (unlikely(r)) \
199 internal(caller_file_line, "mutex_done: pthread_mutex_destroy failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
200 } while (0)
202 #define do_pthread_mutex_lock(m) \
203 do { \
204 int r; \
205 r = pthread_mutex_lock(m); \
206 if (unlikely(r)) \
207 internal(caller_file_line, "mutex_lock: pthread_mutex_lock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
208 } while (0)
210 #define do_pthread_mutex_trylock(m) \
211 do { \
212 int r; \
213 r = pthread_mutex_trylock(m); \
214 if (unlikely(r)) { \
215 if (unlikely(r != EBUSY) && unlikely(r != EDEADLK)) \
216 internal(caller_file_line, "mutex_trylock: pthread_mutex_trylock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
217 return false; \
219 return true; \
220 } while (0)
222 #define do_pthread_mutex_unlock(m) \
223 do { \
224 int r; \
225 r = pthread_mutex_unlock(m); \
226 if (unlikely(r)) \
227 internal(caller_file_line, "mutex_unlock: pthread_mutex_unlock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
228 } while (0)
230 #ifndef UNUSUAL_SPINLOCK
232 #define do_mutex_init do_pthread_mutex_init
233 #define do_mutex_done do_pthread_mutex_done
234 #define do_mutex_lock do_pthread_mutex_lock
235 #define do_mutex_trylock do_pthread_mutex_trylock
236 #define do_mutex_unlock do_pthread_mutex_unlock
238 #else
240 #define do_mutex_init(m) \
241 do { \
242 int r; \
243 r = pthread_spin_init(m, PTHREAD_PROCESS_PRIVATE); \
244 if (unlikely(r)) \
245 fatal("pthread_spin_init failed at %s: %d, %s", position_string(position_arg), r, error_decode(error_from_errno(EC_SYSCALL, r)));\
246 } while (0)
248 #define do_mutex_done(m) \
249 do { \
250 int r; \
251 r = pthread_spin_destroy(m); \
252 if (unlikely(r)) \
253 internal(caller_file_line, "mutex_done: pthread_spin_destroy failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
254 } while (0)
256 #define do_mutex_lock(m) \
257 do { \
258 int r; \
259 r = pthread_spin_lock(m); \
260 if (unlikely(r)) \
261 internal(caller_file_line, "mutex_lock: pthread_spin_lock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
262 } while (0)
264 #define do_mutex_trylock(m) \
265 do { \
266 int r; \
267 r = pthread_spin_trylock(m); \
268 if (unlikely(r)) { \
269 if (unlikely(r != EBUSY) && unlikely(r != EDEADLK)) \
270 internal(caller_file_line, "mutex_trylock: pthread_spin_trylock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
271 return false; \
273 return true; \
274 } while (0)
276 #define do_mutex_unlock(m) \
277 do { \
278 int r; \
279 r = pthread_spin_unlock(m); \
280 if (unlikely(r)) \
281 internal(caller_file_line, "mutex_unlock: pthread_spin_unlock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
282 } while (0)
284 #endif
286 #define do_rwmutex_init(m) \
287 do { \
288 int r; \
289 r = pthread_rwlock_init(m, &rwmutex_attr); \
290 if (unlikely(r)) \
291 fatal("pthread_rwlock_init failed at %s: %d, %s", position_string(position_arg), r, error_decode(error_from_errno(EC_SYSCALL, r)));\
292 } while (0)
294 #define do_rwmutex_done(m) \
295 do { \
296 int r; \
297 r = pthread_rwlock_destroy(m); \
298 if (unlikely(r)) \
299 internal(caller_file_line, "rwmutex_done: pthread_rwlock_destroy failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
300 } while (0)
302 #define do_rwmutex_lock_read(m) \
303 do { \
304 int r; \
305 r = pthread_rwlock_rdlock(m); \
306 if (unlikely(r)) \
307 internal(caller_file_line, "rwmutex_lock_read: pthread_rwlock_rdlock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
308 } while (0)
310 #define do_rwmutex_unlock_read(m) \
311 do { \
312 int r; \
313 r = pthread_rwlock_unlock(m); \
314 if (unlikely(r)) \
315 internal(caller_file_line, "rwmutex_unlock_read: pthread_rwlock_unlock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
316 } while (0)
318 #define do_rwmutex_lock_write(m) \
319 do { \
320 int r; \
321 r = pthread_rwlock_wrlock(m); \
322 if (unlikely(r)) \
323 internal(caller_file_line, "rwmutex_lock_write: pthread_rwlock_wrlock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
324 } while (0)
326 #define do_rwmutex_unlock_write(m) \
327 do { \
328 int r; \
329 r = pthread_rwlock_unlock(m); \
330 if (unlikely(r)) \
331 internal(caller_file_line, "rwmutex_unlock_write: pthread_rwlock_unlock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
332 } while (0)
334 #define do_cond_init(c) \
335 do { \
336 int r; \
337 do_pthread_mutex_init(&(c)->mutex); \
338 r = pthread_cond_init(&(c)->cond, cond_attr_p); \
339 if (unlikely(r)) \
340 fatal("pthread_cond_init failed at %s: %d, %s", position_string(position_arg), r, error_decode(error_from_errno(EC_SYSCALL, r)));\
341 } while (0)
343 #define do_cond_done(c) \
344 do { \
345 int r; \
346 do_pthread_mutex_done(&(c)->mutex); \
347 r = pthread_cond_destroy(&(c)->cond); \
348 if (unlikely(r)) \
349 internal(caller_file_line, "cond_done: pthread_cond_destroy failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
350 } while (0)
352 #define do_cond_lock(c) \
353 do { \
354 do_pthread_mutex_lock(&(c)->mutex); \
355 } while (0)
357 #define do_cond_unlock(c) \
358 do { \
359 do_pthread_mutex_unlock(&(c)->mutex); \
360 } while (0)
362 #define do_cond_unlock_signal(c) \
363 do { \
364 int r; \
365 do_pthread_mutex_unlock(&(c)->mutex); \
366 r = pthread_cond_signal(&(c)->cond); \
367 if (unlikely(r)) \
368 internal(caller_file_line, "cond_unlock_signal: pthread_cond_signal failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
369 } while (0)
371 #define do_cond_unlock_broadcast(c) \
372 do { \
373 int r; \
374 do_pthread_mutex_unlock(&(c)->mutex); \
375 r = pthread_cond_broadcast(&(c)->cond); \
376 if (unlikely(r)) \
377 internal(caller_file_line, "cond_unlock_broadcast: pthread_cond_broadcast failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
378 } while (0)
380 #define do_cond_wait(c) \
381 do { \
382 int r; \
383 again: \
384 r = pthread_cond_wait(&(c)->cond, &(c)->mutex); \
385 if (unlikely(r)) { \
386 if (r == EINTR) goto again; \
387 internal(caller_file_line, "cond_wait: pthread_cond_wait failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
389 } while (0)
391 #if !defined(USE_PTHREAD_CONDATTR)
393 static struct timespec cond_getts(uint32_t us)
395 int r;
396 struct timeval tv;
397 struct timespec ts;
399 EINTR_LOOP(r, gettimeofday(&tv, NULL));
400 if (unlikely(r == -1)) {
401 int e = errno;
402 fatal("gettimeofday failed: %d, %s", e, error_decode(error_from_errno(EC_SYSCALL, e)));
404 if (unlikely(us >= 1000000)) {
405 tv.tv_sec += us / 1000000;
406 us %= 1000000;
408 tv.tv_usec += us;
409 if (unlikely(tv.tv_usec >= 1000000)) {
410 tv.tv_usec -= 1000000;
411 tv.tv_sec++;
413 ts.tv_sec = tv.tv_sec;
414 ts.tv_nsec = (uint32_t)tv.tv_usec * 1000;
416 return ts;
419 #else
421 static struct timespec cond_getts(uint32_t us)
423 int r;
424 struct timespec ts;
426 EINTR_LOOP(r, clock_gettime(clock_id, &ts));
427 if (unlikely(r == -1)) {
428 int e = errno;
429 fatal("clock_gettime(%d) failed: %d, %s", (int)clock_id, e, error_decode(error_from_errno(EC_SYSCALL, e)));
431 if (unlikely(us >= 1000000)) {
432 ts.tv_sec += us / 1000000;
433 us %= 1000000;
435 ts.tv_nsec += us * 1000;
436 if (unlikely(ts.tv_nsec >= 1000000000)) {
437 ts.tv_nsec -= 1000000000;
438 ts.tv_sec++;
441 return ts;
444 #endif
446 #define do_cond_wait_us(c, us) \
447 do { \
448 int r; \
449 struct timespec ts; \
451 ts = cond_getts(us); \
452 again: \
453 r = pthread_cond_timedwait(&(c)->cond, &(c)->mutex, &ts); \
454 if (unlikely(r)) { \
455 if (likely(r == ETIMEDOUT)) return false; \
456 if (r == EINTR) goto again; \
457 internal(caller_file_line, "cond_wait_us: pthread_cond_timedwait failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
459 return true; \
460 } while (0)
463 #define do_thread_spawn(t, function, arg, priority, err) \
464 do { \
465 int r; \
466 r = pthread_create(t, &thread_attr, function, arg); \
467 if (unlikely(r)) { \
468 ajla_error_t e = error_from_errno(EC_SYSCALL, r); \
469 fatal_mayfail(e, err, "pthread_create failed at %s: %d, %s", position_string(position_arg), r, error_decode(e));\
470 return false; \
472 } while (0)
474 #define do_thread_join(t) \
475 do { \
476 int r; \
477 r = pthread_join(*t, NULL); \
478 if (unlikely(r)) \
479 internal(caller_file_line, "thread_join: pthread_join failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
480 } while (0)
483 #if !defined(HAVE___THREAD)
485 #define do_tls_init(tl) \
486 do { \
487 int r; \
488 r = pthread_key_create(tl, NULL); \
489 if (unlikely(r)) \
490 fatal("pthread_key_create failed at %s: %d, %s", position_string(position_arg), r, error_decode(error_from_errno(EC_SYSCALL, r)));\
491 } while (0)
493 #define do_tls_done(tl) \
494 do { \
495 int r; \
496 r = pthread_key_delete(*(tl)); \
497 if (unlikely(r)) \
498 internal(caller_file_line, "tls_done: pthread_key_delete failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
499 } while (0)
501 #define do_tls_get(tl, ret) \
502 do { \
503 *(ret) = ptr_to_num(pthread_getspecific(*(tl))); \
504 } while (0)
506 #define do_tls_set(tl, val) \
507 do { \
508 int r; \
509 r = pthread_setspecific(*(tl), (void *)(val)); \
510 if (unlikely(r)) \
511 internal(caller_file_line, "tls_set: pthread_setspecific failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));\
512 } while (0)
514 #endif
516 #include "th_com.inc"
519 #ifndef barrier_write_before_lock
521 #if defined(HAVE_PTHREAD_SPIN_INIT) && !defined(UNUSUAL_ARITHMETICS)
523 void barrier_write_before_lock(void)
525 pthread_spinlock_t lock;
526 int r;
527 #ifdef barrier_write_before_unlock_lock
528 barrier_write_before_unlock_lock();
529 #endif
530 r = pthread_spin_init(&lock, PTHREAD_PROCESS_PRIVATE);
531 if (unlikely(r))
532 fatal("pthread_spin_init failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
533 r = pthread_spin_lock(&lock);
534 if (unlikely(r))
535 internal(file_line, "pthread_spin_lock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
536 r = pthread_spin_unlock(&lock);
537 if (unlikely(r))
538 internal(file_line, "pthread_spin_unlock failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
539 r = pthread_spin_destroy(&lock);
540 if (unlikely(r))
541 internal(file_line, "pthread_spin_destroy failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
544 #else
546 #define barrier_lock_need_tls
547 struct barrier_lock {
548 mutex_t mutex;
549 tls_destructor_t destructor;
551 static tls_decl(struct barrier_lock *, barrier_lock);
553 static void barrier_lock_destructor(tls_destructor_t *destr)
555 struct barrier_lock *lock = get_struct(destr, struct barrier_lock, destructor);
556 mutex_done(&lock->mutex);
557 mem_free(lock);
560 void barrier_write_before_lock(void)
562 struct barrier_lock *lock = tls_get(struct barrier_lock *, barrier_lock);
563 if (unlikely(!lock)) {
564 lock = mem_alloc(struct barrier_lock *, sizeof(struct barrier_lock));
565 mutex_init(&lock->mutex);
566 tls_set(struct barrier_lock *, barrier_lock, lock);
567 tls_destructor(&lock->destructor, barrier_lock_destructor);
569 #ifdef barrier_write_before_unlock_lock
570 barrier_write_before_unlock_lock();
571 #endif
572 mutex_lock(&lock->mutex);
573 mutex_unlock(&lock->mutex);
576 #endif
578 #endif
581 #include "th_sig.inc"
584 #ifdef USE_PTHREAD_CONDATTR
585 static bool pthread_condattr_try_clock(clockid_t c, bool mayfail)
587 int r = pthread_condattr_setclock(cond_attr_p, c);
588 if (r) {
589 if (unlikely(!mayfail))
590 fatal("pthread_condattr_setclock(%d) failed: %d, %s", (int)c, r, error_decode(error_from_errno(EC_SYSCALL, r)));
591 return false;
592 } else {
593 pthread_cond_t cond;
594 r = pthread_cond_init(&cond, cond_attr_p);
595 if (unlikely(r)) {
596 (!mayfail ? fatal : warning)("pthread_cond_init (clock %d) failed: %d, %s", (int)c, r, error_decode(error_from_errno(EC_SYSCALL, r)));
597 return false;
599 r = pthread_cond_destroy(&cond);
600 if (unlikely(r))
601 internal(file_line, "pthread_condattr_try_clock: pthread_cond_destroy (clock %d) failed: %d, %s", (int)c, r, error_decode(error_from_errno(EC_SYSCALL, r)));
602 clock_id = c;
603 return true;
606 #endif
608 void thread_init(void)
610 int r;
611 size_t stack;
613 #if defined(__linux__)
614 ajla_error_t sink;
615 char *str;
616 size_t len;
617 if (likely(os_read_file("/sys/devices/system/cpu/possible", &str, &len, &sink))) {
618 array_add(char, &str, &len, 0);
619 if (!strcmp(str, "0\n"))
620 thread_needs_barriers = false;
621 mem_free(str);
623 #endif
625 r = pthread_mutexattr_init(&mutex_attr);
626 if (unlikely(r))
627 fatal("pthread_mutexattr_init failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
628 #ifdef DEBUG_OBJECT_POSSIBLE
629 if (mutex_debug) {
630 #if defined(HAVE_PTHREAD_MUTEX_ERRORCHECK)
631 r = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK);
632 #elif defined(HAVE_PTHREAD_MUTEX_ERRORCHECK_NP)
633 r = pthread_mutexattr_settype(&mutex_attr, PTHREAD_MUTEX_ERRORCHECK_NP);
634 #else
635 r = 0;
636 #endif
637 if (unlikely(r))
638 fatal("pthread_mutexattr_settype failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
640 #endif
642 r = pthread_rwlockattr_init(&rwmutex_attr);
643 if (unlikely(r))
644 fatal("pthread_rwlockattr_init failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
646 #ifdef USE_PTHREAD_CONDATTR
647 r = pthread_condattr_init(&cond_attr);
648 if (unlikely(r))
649 fatal("pthread_condattr_init failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
650 #ifdef HAVE_CLOCK_MONOTONIC_RAW
651 if (likely(!pthread_condattr_try_clock(CLOCK_MONOTONIC_RAW, true)))
652 #endif
654 if (unlikely(!pthread_condattr_try_clock(CLOCK_MONOTONIC, true))) {
655 pthread_condattr_try_clock(CLOCK_REALTIME, false);
658 #endif
660 r = pthread_attr_init(&thread_attr);
661 if (unlikely(r))
662 fatal("pthread_attr_init failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
664 r = pthread_attr_getstacksize(&thread_attr, &stack);
665 if (unlikely(r))
666 fatal("pthread_attr_getstacksize failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
667 if (stack < MINIMUM_STACK_SIZE) {
668 r = pthread_attr_setstacksize(&thread_attr, MINIMUM_STACK_SIZE);
669 if (unlikely(r))
670 fatal("pthread_attr_setstacksize failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
673 thread_signal_init();
674 thread_common_init();
675 #ifdef barrier_lock_need_tls
676 tls_init(struct barrier_lock *, barrier_lock);
677 #endif
680 void thread_done(void)
682 int r;
683 thread_common_done();
684 thread_signal_done();
685 #ifdef barrier_lock_need_tls
686 tls_done(struct barrier_lock *, barrier_lock);
687 #endif
688 r = pthread_attr_destroy(&thread_attr);
689 if (unlikely(r))
690 fatal("pthread_attr_destroy failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
691 r = pthread_mutexattr_destroy(&mutex_attr);
692 if (unlikely(r))
693 fatal("pthread_mutexattr_destroy failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
694 r = pthread_rwlockattr_destroy(&rwmutex_attr);
695 if (unlikely(r))
696 fatal("pthread_rwlockattr_destroy failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
697 #ifdef USE_PTHREAD_CONDATTR
698 r = pthread_condattr_destroy(&cond_attr);
699 if (unlikely(r))
700 fatal("pthread_condattr_destroy failed: %d, %s", r, error_decode(error_from_errno(EC_SYSCALL, r)));
701 #endif
704 #endif