// The Construct // // Copyright (C) The Construct Developers, Authors & Contributors // Copyright (C) 2016-2020 Jason Volk // // Permission to use, copy, modify, and/or distribute this software for any // purpose with or without fee is hereby granted, provided that the above // copyright notice and this permission notice is present in all copies. The // full license for this software is available in the LICENSE file. /////////////////////////////////////////////////////////////////////////////// // // This unit exists to mitigate unwanted use of pthreads by third-party // libraries. It is NOT intended to supplant real threads with ircd::ctx at // this time, as we still want real parallel execution ability available to // the project and to other users of the address space. // #include #include //#define IRCD_PTHREAD_DEADLK_CHK namespace ircd::ctx::posix { extern log::log log; std::vector ctxs; } using ircd::always_assert; decltype(ircd::ctx::posix::log) ircd::ctx::posix::log { "ctx.posix" }; // // Linker wraps/hooks; see ircd/Makefile.am LDFLAGS. These allow us to play // nice with legitimate uses of pthreads by the rest of the address space by // appropriately dispatching to either our implementation or the real one. // // // hook pthread_create // extern "C" int __real_pthread_create(pthread_t *const thread, const pthread_attr_t *const attr, void *(*const start_routine)(void *), void *const arg); extern "C" int __wrap_pthread_create(pthread_t *const thread, const pthread_attr_t *const attr, void *(*const start_routine)(void *), void *const arg) { return ircd::ctx::current? ircd_pthread_create(thread, attr, start_routine, arg): __real_pthread_create(thread, attr, start_routine, arg); } // // hook pthread_join // extern "C" int __real_pthread_join(pthread_t __th, void **__thread_return); extern "C" int __wrap_pthread_join(pthread_t __th, void **__thread_return) { return ircd::ctx::current? ircd_pthread_join(__th, __thread_return): __real_pthread_join(__th, __thread_return); } // // hook pthread_self // extern "C" pthread_t __real_pthread_self(void); extern "C" pthread_t __wrap_pthread_self(void) { return ircd::ctx::current? ircd_pthread_self(): __real_pthread_self(); } /////////////////////////////////////////////////////////////////////////////// // // pthread supplement // int ircd_pthread_create(pthread_t *const thread, const pthread_attr_t *const attr, void *(*const start_routine)(void *), void *const arg) noexcept { assert(thread); assert(start_routine); ircd::ctx::posix::ctxs.emplace_back(ircd::context { "pthread", 1024 * 1024 * 1UL, ircd::context::POST, std::bind(start_routine, arg), }); *thread = id(ircd::ctx::posix::ctxs.back()); ircd::log::debug { ircd::ctx::posix::log, "pthread_create id:%lu attr:%p func:%p arg:%p", *thread, attr, start_routine, arg }; return 0; } int ircd_pthread_join(pthread_t __th, void **__thread_return) { ircd::log::debug { ircd::ctx::posix::log, "pthread_join id:%lu thread_return:%p", __th, __thread_return, }; auto it(begin(ircd::ctx::posix::ctxs)); while(it != end(ircd::ctx::posix::ctxs)) { if(id(*it) == __th) { it->join(); it = ircd::ctx::posix::ctxs.erase(it); break; } else ++it; } if(__thread_return) *__thread_return = PTHREAD_CANCELED; return 0; } int ircd_pthread_tryjoin_np(pthread_t __th, void **__thread_return) { always_assert(false); return EINVAL; } int ircd_pthread_timedjoin_np(pthread_t __th, void **__thread_return, const struct timespec *__abstime) { always_assert(false); return EINVAL; } void ircd_pthread_exit(void *const retval) { always_assert(false); __builtin_unreachable(); } int ircd_pthread_detach(pthread_t __th) noexcept { always_assert(false); return EINVAL; } pthread_t ircd_pthread_self(void) noexcept { assert(ircd::ctx::current); return id(ircd::ctx::cur()); } int ircd_pthread_getcpuclockid(pthread_t __thread_id, __clockid_t *__clock_id) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_atfork(void (*__prepare)(void), void (*__parent)(void), void (*__child)(void)) noexcept { always_assert(false); return EINVAL; } // // Initialization // int ircd_pthread_once(pthread_once_t *__once_control, void (*__init_routine)(void)) { static_assert(sizeof(std::atomic) == sizeof(pthread_once_t)); auto *const _once_control { reinterpret_cast *>(__once_control) }; const int once_control { std::atomic_exchange(_once_control, 1) }; assert(once_control == 1 || once_control == 0); if(likely(once_control == 0)) __init_routine(); return 0; } // // Cancellation // int ircd_pthread_setcancelstate(int __state, int *__oldstate) { always_assert(false); return EINVAL; } int ircd_pthread_setcanceltype(int __type, int *__oldtype) { always_assert(false); return EINVAL; } int ircd_pthread_cancel(pthread_t __th) { always_assert(false); return EINVAL; } void ircd_pthread_testcancel(void) { always_assert(false); } // // Scheduling // int ircd_pthread_setschedparam(pthread_t __target_thread, int __policy, const struct sched_param *__param) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_getschedparam(pthread_t __target_thread, int *__restrict __policy, struct sched_param *__restrict __param) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_setschedprio(pthread_t __target_thread, int __prio) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_getname_np(pthread_t __target_thread, char *__buf, size_t __buflen) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_setname_np(pthread_t __target_thread, const char *__name) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_getconcurrency(void) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_setconcurrency(int __level) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_setaffinity_np(pthread_t __th, size_t __cpusetsize, const cpu_set_t *__cpuset) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_getaffinity_np(pthread_t __th, size_t __cpusetsize, cpu_set_t *__cpuset) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_yield(void) noexcept { assert(ircd::ctx::current); ircd::ctx::yield(); return 0; } // // Attributes // int ircd_pthread_attr_init(pthread_attr_t *__attr) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_destroy(pthread_attr_t *__attr) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_getdetachstate(const pthread_attr_t *__attr, int *__detachstate) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_setdetachstate(pthread_attr_t *__attr, int __detachstate) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_getguardsize(const pthread_attr_t *__attr, size_t *__guardsize) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_setguardsize(pthread_attr_t *__attr, size_t __guardsize) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_getschedparam(const pthread_attr_t *__restrict __attr, struct sched_param *__restrict __param) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_setschedparam(pthread_attr_t *__restrict __attr, const struct sched_param *__restrict __param) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_getschedpolicy(const pthread_attr_t *__restrict __attr, int *__restrict __policy) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_setschedpolicy(pthread_attr_t *__attr, int __policy) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_getinheritsched(const pthread_attr_t *__restrict __attr, int *__restrict __inherit) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_setinheritsched(pthread_attr_t *__attr, int __inherit) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_getscope(const pthread_attr_t *__restrict __attr, int *__restrict __scope) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_setscope(pthread_attr_t *__attr, int __scope) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_getstackaddr(const pthread_attr_t *__restrict __attr, void **__restrict __stackaddr) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_setstackaddr(pthread_attr_t *__attr, void *__stackaddr) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_getstacksize(const pthread_attr_t *__restrict __attr, size_t *__restrict __stacksize) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_setstacksize(pthread_attr_t *__attr, size_t __stacksize) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_getstack(const pthread_attr_t *__restrict __attr, void **__restrict __stackaddr, size_t *__restrict __stacksize) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_setstack(pthread_attr_t *__attr, void *__stackaddr, size_t __stacksize) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_setaffinity_np(pthread_attr_t *__attr, size_t __cpusetsize, const cpu_set_t *__cpuset) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_attr_getaffinity_np(const pthread_attr_t *__attr, size_t __cpusetsize, cpu_set_t *__cpuset) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_getattr_default_np(pthread_attr_t *__attr) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_setattr_default_np(const pthread_attr_t *__attr) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_getattr_np(pthread_t __th, pthread_attr_t *__attr) noexcept { always_assert(false); return EINVAL; } /////////////////////////////////////////////////////////////////////////////// // // Thread-Local // int ircd_pthread_key_create(pthread_key_t *__key, void (*__destr_function)(void *)) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_key_delete(pthread_key_t __key) noexcept { always_assert(false); return EINVAL; } void * ircd_pthread_getspecific(pthread_key_t __key) noexcept { always_assert(false); return nullptr; } int ircd_pthread_setspecific(pthread_key_t __key, const void *__pointer) noexcept { always_assert(false); return EINVAL; } /////////////////////////////////////////////////////////////////////////////// // // Spinlock // int ircd_pthread_spin_init(pthread_spinlock_t *__lock, int __pshared) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_spin_destroy(pthread_spinlock_t *__lock) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_spin_lock(pthread_spinlock_t *__lock) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_spin_trylock(pthread_spinlock_t *__lock) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_spin_unlock(pthread_spinlock_t *__lock) noexcept { always_assert(false); return EINVAL; } /////////////////////////////////////////////////////////////////////////////// // // Mutex // int ircd_pthread_mutex_init(pthread_mutex_t *__mutex, const pthread_mutexattr_t *__attr) noexcept { static_assert(sizeof(ircd::ctx::mutex) <= sizeof(pthread_mutex_t)); assert(__mutex); //assert(__attr); auto *const mutex { reinterpret_cast(__mutex) }; new (mutex) ircd::ctx::mutex; return 0; } int ircd_pthread_mutex_destroy(pthread_mutex_t *__mutex) noexcept { assert(__mutex); auto *const mutex { reinterpret_cast(__mutex) }; if(unlikely(mutex->locked())) return EBUSY; mutex->~mutex(); return 0; } int ircd_pthread_mutex_trylock(pthread_mutex_t *__mutex) noexcept { assert(__mutex); auto *const mutex { reinterpret_cast(__mutex) }; if(!mutex->try_lock()) return EBUSY; return 0; } int ircd_pthread_mutex_lock(pthread_mutex_t *__mutex) noexcept { assert(__mutex); auto *const mutex { reinterpret_cast(__mutex) }; #ifdef IRCD_PTHREAD_DEADLK_CHK if(unlikely(mutex->m == ircd::ctx::current)) return EDEADLK; #endif mutex->lock(); return 0; } int ircd_pthread_mutex_timedlock(pthread_mutex_t *__restrict __mutex, const struct timespec *__restrict __abstime) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutex_clocklock(pthread_mutex_t *__restrict __mutex, clockid_t __clockid, const struct timespec *__restrict __abstime) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutex_unlock(pthread_mutex_t *__mutex) noexcept { assert(__mutex); auto *const mutex { reinterpret_cast(__mutex) }; if(unlikely(mutex->m != ircd::ctx::current)) return EPERM; mutex->unlock(); return 0; } int ircd_pthread_mutex_getprioceiling(const pthread_mutex_t *__restrict __mutex, int *__restrict __prioceiling) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutex_setprioceiling(pthread_mutex_t *__restrict __mutex, int __prioceiling, int *__restrict __old_ceiling) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutex_consistent(pthread_mutex_t *__mutex) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutex_consistent_np(pthread_mutex_t *__mutex) noexcept { always_assert(false); return EINVAL; } // // Mutex Attributes // int ircd_pthread_mutexattr_init(pthread_mutexattr_t *__attr) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_destroy(pthread_mutexattr_t *__attr) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_getpshared(const pthread_mutexattr_t *__restrict __attr, int *__restrict __pshared) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_setpshared(pthread_mutexattr_t *__attr, int __pshared) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_gettype(const pthread_mutexattr_t *__restrict __attr, int *__restrict __kind) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_settype(pthread_mutexattr_t *__attr, int __kind) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_getprotocol(const pthread_mutexattr_t *__restrict __attr, int *__restrict __protocol) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_setprotocol(pthread_mutexattr_t *__attr, int __protocol) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *__restrict __attr, int *__restrict __prioceiling) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_setprioceiling(pthread_mutexattr_t *__attr, int __prioceiling) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_getrobust(const pthread_mutexattr_t *__attr, int *__robustness) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_getrobust_np(const pthread_mutexattr_t *__attr, int *__robustness) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_setrobust(pthread_mutexattr_t *__attr, int __robustness) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_mutexattr_setrobust_np(pthread_mutexattr_t *__attr, int __robustness) noexcept { always_assert(false); return EINVAL; } /////////////////////////////////////////////////////////////////////////////// // // Shared Mutex // int ircd_pthread_rwlock_init(pthread_rwlock_t *__restrict __rwlock, const pthread_rwlockattr_t *__restrict __attr) noexcept { static_assert(sizeof(ircd::ctx::shared_mutex) <= sizeof(pthread_rwlock_t)); assert(__rwlock); //assert(__attr); auto *const shared_mutex { reinterpret_cast(__rwlock) }; new (shared_mutex) ircd::ctx::shared_mutex; return 0; } int ircd_pthread_rwlock_destroy(pthread_rwlock_t *__rwlock) noexcept { assert(__rwlock); auto *const shared_mutex { reinterpret_cast(__rwlock) }; const bool busy { !shared_mutex->can_lock_upgrade() || shared_mutex->shares() || shared_mutex->waiting() }; if(unlikely(busy)) return EBUSY; shared_mutex->~shared_mutex(); return 0; } int ircd_pthread_rwlock_rdlock(pthread_rwlock_t *__rwlock) noexcept { assert(__rwlock); auto *const shared_mutex { reinterpret_cast(__rwlock) }; shared_mutex->lock_shared(); return 0; } int ircd_pthread_rwlock_tryrdlock(pthread_rwlock_t *__rwlock) noexcept { assert(__rwlock); auto *const shared_mutex { reinterpret_cast(__rwlock) }; if(!shared_mutex->try_lock_shared()) return EBUSY; return 0; } int ircd_pthread_rwlock_timedrdlock(pthread_rwlock_t *__restrict __rwlock, const struct timespec *__restrict __abstime) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_rwlock_clockrdlock(pthread_rwlock_t *__restrict __rwlock, clockid_t __clockid, const struct timespec *__restrict __abstime) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_rwlock_wrlock(pthread_rwlock_t *__rwlock) noexcept { assert(__rwlock); auto *const shared_mutex { reinterpret_cast(__rwlock) }; #ifdef IRCD_PTHREAD_DEADLK_CHK if(unlikely(shared_mutex->u == ircd::ctx::current)) return EDEADLK; #endif shared_mutex->lock(); return 0; } int ircd_pthread_rwlock_trywrlock(pthread_rwlock_t *__rwlock) noexcept { assert(__rwlock); auto *const shared_mutex { reinterpret_cast(__rwlock) }; if(!shared_mutex->try_lock()) return EBUSY; return 0; } int ircd_pthread_rwlock_timedwrlock(pthread_rwlock_t *__restrict __rwlock, const struct timespec *__restrict __abstime) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_rwlock_clockwrlock(pthread_rwlock_t *__restrict __rwlock, clockid_t __clockid, const struct timespec *__restrict __abstime) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_rwlock_unlock(pthread_rwlock_t *__rwlock) noexcept { assert(__rwlock); auto *const shared_mutex { reinterpret_cast(__rwlock) }; // pthread interface has no rdunlock() and wrunlock() so we have to branch if(shared_mutex->unique()) { if(unlikely(shared_mutex->u != ircd::ctx::current)) return EPERM; shared_mutex->unlock(); return 0; } if(unlikely(shared_mutex->unique() || !shared_mutex->shares())) return EPERM; shared_mutex->unlock_shared(); return 0; } // // Shared Mutex Attributes // int ircd_pthread_rwlockattr_init(pthread_rwlockattr_t *__attr) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_rwlockattr_destroy(pthread_rwlockattr_t *__attr) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *__restrict __attr, int *__restrict __pshared) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_rwlockattr_setpshared(pthread_rwlockattr_t *__attr, int __pshared) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_rwlockattr_getkind_np(const pthread_rwlockattr_t *__restrict __attr, int *__restrict __pref) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_rwlockattr_setkind_np(pthread_rwlockattr_t *__attr, int __pref) noexcept { always_assert(false); return EINVAL; } /////////////////////////////////////////////////////////////////////////////// // // Condition Variable // int ircd_pthread_cond_init(pthread_cond_t *__restrict __cond, const pthread_condattr_t *__restrict __cond_attr) noexcept { static_assert(sizeof(ircd::ctx::condition_variable) <= sizeof(pthread_cond_t)); assert(__cond); //assert(__cond_attr); auto *const condition_variable { reinterpret_cast(__cond) }; new (condition_variable) ircd::ctx::condition_variable; return 0; } int ircd_pthread_cond_destroy(pthread_cond_t *__cond) noexcept { assert(__cond); auto *const condition_variable { reinterpret_cast(__cond) }; const bool busy { !condition_variable->empty() }; if(unlikely(busy)) return EBUSY; condition_variable->~condition_variable(); return 0; } int ircd_pthread_cond_signal(pthread_cond_t *__cond) noexcept { auto *const condition_variable { reinterpret_cast(__cond) }; condition_variable->notify(); return 0; } int ircd_pthread_cond_broadcast(pthread_cond_t *__cond) noexcept { auto *const condition_variable { reinterpret_cast(__cond) }; condition_variable->notify_all(); return 0; } int ircd_pthread_cond_wait(pthread_cond_t *const __restrict __cond, pthread_mutex_t *const __restrict __mutex) { assert(__cond); assert(__mutex); auto *const condition_variable { reinterpret_cast(__cond) }; auto *const mutex { reinterpret_cast(__mutex) }; condition_variable->wait(*mutex); return 0; } int ircd_pthread_cond_timedwait(pthread_cond_t *const __restrict __cond, pthread_mutex_t *const __restrict __mutex, const struct timespec *__restrict __abstime) { using namespace std::chrono; assert(__cond); assert(__mutex); assert(__abstime); auto *const condition_variable { reinterpret_cast(__cond) }; auto *const mutex { reinterpret_cast(__mutex) }; const nanoseconds epoch { seconds(__abstime->tv_sec) + nanoseconds(__abstime->tv_nsec) }; const time_point time_point { epoch }; const std::cv_status cv_status { condition_variable->wait_until(*mutex, time_point) }; if(cv_status == std::cv_status::timeout) return ETIMEDOUT; return 0; } int ircd_pthread_cond_clockwait(pthread_cond_t *__restrict __cond, pthread_mutex_t *__restrict __mutex, __clockid_t __clock_id, const struct timespec *__restrict __abstime) { always_assert(false); return EINVAL; } // // Condition Variable Attributes // int ircd_pthread_condattr_init(pthread_condattr_t *__attr) noexcept { assert(__attr); memset(__attr, 0x0, sizeof(pthread_condattr_t)); return 0; } int ircd_pthread_condattr_destroy(pthread_condattr_t *__attr) noexcept { return 0; } int ircd_pthread_condattr_getpshared(const pthread_condattr_t *__restrict __attr, int *__restrict __pshared) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_condattr_setpshared(pthread_condattr_t *__attr, int __pshared) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_condattr_getclock(const pthread_condattr_t *__restrict __attr, __clockid_t *__restrict __clock_id) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_condattr_setclock(pthread_condattr_t *__attr, __clockid_t __clock_id) noexcept { always_assert(false); return EINVAL; } /////////////////////////////////////////////////////////////////////////////// // // Barrier // int ircd_pthread_barrier_init(pthread_barrier_t *__restrict __barrier, const pthread_barrierattr_t *__restrict __attr, unsigned int __count) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_barrier_destroy(pthread_barrier_t *__barrier) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_barrier_wait(pthread_barrier_t *__barrier) noexcept { always_assert(false); return EINVAL; } // // Barrier Attributes // int ircd_pthread_barrierattr_init(pthread_barrierattr_t *__attr) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_barrierattr_destroy(pthread_barrierattr_t *__attr) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_barrierattr_getpshared(const pthread_barrierattr_t *__restrict __attr, int *__restrict __pshared) noexcept { always_assert(false); return EINVAL; } int ircd_pthread_barrierattr_setpshared(pthread_barrierattr_t *__attr, int __pshared) noexcept { always_assert(false); return EINVAL; }