* z_Linux_util.cpp -- platform specific routines.
*/
#include "kmp.h"
#include "kmp_affinity.h"
#include "kmp_i18n.h"
#include "kmp_io.h"
#include "kmp_itt.h"
#include "kmp_lock.h"
#include "kmp_stats.h"
#include "kmp_str.h"
#include "kmp_wait_release.h"
#include "kmp_wrapper_getpid.h"
#if !KMP_OS_DRAGONFLY && !KMP_OS_FREEBSD && !KMP_OS_NETBSD && !KMP_OS_OPENBSD
#include <alloca.h>
#endif
#include <math.h>
#if KMP_OS_LINUX
#include <semaphore.h>
#endif
#include <sys/resource.h>
#if KMP_OS_AIX
#include <sys/ldr.h>
#include <libperfstat.h>
#else
#include <sys/syscall.h>
#endif
#include <sys/time.h>
#include <sys/times.h>
#include <unistd.h>
#if KMP_OS_LINUX
#include <sys/sysinfo.h>
#if KMP_USE_FUTEX
#ifndef FUTEX_WAIT
#define FUTEX_WAIT 0
#endif
#ifndef FUTEX_WAKE
#define FUTEX_WAKE 1
#endif
#endif
#elif KMP_OS_DARWIN
#include <mach/mach.h>
#include <sys/sysctl.h>
#elif KMP_OS_DRAGONFLY || KMP_OS_FREEBSD
#include <sys/types.h>
#include <sys/sysctl.h>
#include <sys/user.h>
#include <pthread_np.h>
#if KMP_OS_DRAGONFLY
#include <kvm.h>
#endif
#elif KMP_OS_NETBSD || KMP_OS_OPENBSD
#include <sys/types.h>
#include <sys/sysctl.h>
#if KMP_OS_NETBSD
#include <sched.h>
#endif
#elif KMP_OS_SOLARIS
#include <libproc.h>
#include <procfs.h>
#include <thread.h>
#include <sys/loadavg.h>
#endif
#include <ctype.h>
#include <dirent.h>
#include <fcntl.h>
struct kmp_sys_timer {
struct timespec start;
};
#ifndef TIMEVAL_TO_TIMESPEC
#define TIMEVAL_TO_TIMESPEC(tv, ts) \
do { \
(ts)->tv_sec = (tv)->tv_sec; \
(ts)->tv_nsec = (tv)->tv_usec * 1000; \
} while (0)
#endif
#define TS2NS(timespec) \
(((timespec).tv_sec * (long int)1e9) + (timespec).tv_nsec)
static struct kmp_sys_timer __kmp_sys_timer_data;
#if KMP_HANDLE_SIGNALS
typedef void (*sig_func_t)(int);
STATIC_EFI2_WORKAROUND struct sigaction __kmp_sighldrs[NSIG];
static sigset_t __kmp_sigset;
#endif
static int __kmp_init_runtime = FALSE;
static int __kmp_fork_count = 0;
static pthread_condattr_t __kmp_suspend_cond_attr;
static pthread_mutexattr_t __kmp_suspend_mutex_attr;
static kmp_cond_align_t __kmp_wait_cv;
static kmp_mutex_align_t __kmp_wait_mx;
kmp_uint64 __kmp_ticks_per_msec = 1000000;
kmp_uint64 __kmp_ticks_per_usec = 1000;
#ifdef DEBUG_SUSPEND
static void __kmp_print_cond(char *buffer, kmp_cond_align_t *cond) {
KMP_SNPRINTF(buffer, 128, "(cond (lock (%ld, %d)), (descr (%p)))",
cond->c_cond.__c_lock.__status, cond->c_cond.__c_lock.__spinlock,
cond->c_cond.__c_waiting);
}
#endif
#if ((KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_NETBSD || KMP_OS_DRAGONFLY || \
KMP_OS_AIX) && \
KMP_AFFINITY_SUPPORTED)
void __kmp_affinity_bind_thread(int which) {
KMP_ASSERT2(KMP_AFFINITY_CAPABLE(),
"Illegal set affinity operation when not capable");
kmp_affin_mask_t *mask;
KMP_CPU_ALLOC_ON_STACK(mask);
KMP_CPU_ZERO(mask);
KMP_CPU_SET(which, mask);
__kmp_set_system_affinity(mask, TRUE);
KMP_CPU_FREE_FROM_STACK(mask);
}
#if KMP_OS_AIX
void __kmp_affinity_determine_capable(const char *env_var) {
size_t mask_size = __kmp_xproc / CHAR_BIT;
if (__kmp_xproc % CHAR_BIT)
++mask_size;
if (mask_size % sizeof(__kmp_affin_mask_size))
mask_size += sizeof(__kmp_affin_mask_size) -
mask_size % sizeof(__kmp_affin_mask_size);
KMP_AFFINITY_ENABLE(mask_size);
KA_TRACE(10,
("__kmp_affinity_determine_capable: "
"AIX OS affinity interface bindprocessor functional (mask size = "
"%" KMP_SIZE_T_SPEC ").\n",
__kmp_affin_mask_size));
}
#else
* Linux* OS by checking __NR_sched_{get,set}affinity system calls, and set
* __kmp_affin_mask_size to the appropriate value (0 means not capable). */
void __kmp_affinity_determine_capable(const char *env_var) {
#if KMP_OS_LINUX
#define KMP_CPU_SET_SIZE_LIMIT (1024 * 1024)
#define KMP_CPU_SET_TRY_SIZE CACHE_LINE
#elif KMP_OS_FREEBSD || KMP_OS_DRAGONFLY
#define KMP_CPU_SET_SIZE_LIMIT (sizeof(cpuset_t))
#elif KMP_OS_NETBSD
#define KMP_CPU_SET_SIZE_LIMIT (256)
#endif
int verbose = __kmp_affinity.flags.verbose;
int warnings = __kmp_affinity.flags.warnings;
enum affinity_type type = __kmp_affinity.type;
#if KMP_OS_LINUX
long gCode;
unsigned char *buf;
buf = (unsigned char *)KMP_INTERNAL_MALLOC(KMP_CPU_SET_SIZE_LIMIT);
gCode = syscall(__NR_sched_getaffinity, 0, KMP_CPU_SET_TRY_SIZE, buf);
KA_TRACE(30, ("__kmp_affinity_determine_capable: "
"initial getaffinity call returned %ld errno = %d\n",
gCode, errno));
if (gCode < 0 && errno != EINVAL) {
if (verbose ||
(warnings && (type != affinity_none) && (type != affinity_default) &&
(type != affinity_disabled))) {
int error = errno;
kmp_msg_t err_code = KMP_ERR(error);
__kmp_msg(kmp_ms_warning, KMP_MSG(GetAffSysCallNotSupported, env_var),
err_code, __kmp_msg_null);
if (__kmp_generate_warnings == kmp_warnings_off) {
__kmp_str_free(&err_code.str);
}
}
KMP_AFFINITY_DISABLE();
KMP_INTERNAL_FREE(buf);
return;
} else if (gCode > 0) {
KMP_AFFINITY_ENABLE(gCode);
KA_TRACE(10, ("__kmp_affinity_determine_capable: "
"affinity supported (mask size %d)\n",
(int)__kmp_affin_mask_size));
KMP_INTERNAL_FREE(buf);
return;
}
KA_TRACE(30, ("__kmp_affinity_determine_capable: "
"searching for proper set size\n"));
int size;
for (size = 1; size <= KMP_CPU_SET_SIZE_LIMIT; size *= 2) {
gCode = syscall(__NR_sched_getaffinity, 0, size, buf);
KA_TRACE(30, ("__kmp_affinity_determine_capable: "
"getaffinity for mask size %ld returned %ld errno = %d\n",
size, gCode, errno));
if (gCode < 0) {
if (errno == ENOSYS) {
KA_TRACE(30, ("__kmp_affinity_determine_capable: "
"inconsistent OS call behavior: errno == ENOSYS for mask "
"size %d\n",
size));
if (verbose ||
(warnings && (type != affinity_none) &&
(type != affinity_default) && (type != affinity_disabled))) {
int error = errno;
kmp_msg_t err_code = KMP_ERR(error);
__kmp_msg(kmp_ms_warning, KMP_MSG(GetAffSysCallNotSupported, env_var),
err_code, __kmp_msg_null);
if (__kmp_generate_warnings == kmp_warnings_off) {
__kmp_str_free(&err_code.str);
}
}
KMP_AFFINITY_DISABLE();
KMP_INTERNAL_FREE(buf);
return;
}
continue;
}
KMP_AFFINITY_ENABLE(gCode);
KA_TRACE(10, ("__kmp_affinity_determine_capable: "
"affinity supported (mask size %d)\n",
(int)__kmp_affin_mask_size));
KMP_INTERNAL_FREE(buf);
return;
}
#elif KMP_OS_FREEBSD || KMP_OS_NETBSD || KMP_OS_DRAGONFLY
long gCode;
unsigned char *buf;
buf = (unsigned char *)KMP_INTERNAL_MALLOC(KMP_CPU_SET_SIZE_LIMIT);
gCode = pthread_getaffinity_np(pthread_self(), KMP_CPU_SET_SIZE_LIMIT,
reinterpret_cast<cpuset_t *>(buf));
KA_TRACE(30, ("__kmp_affinity_determine_capable: "
"initial getaffinity call returned %d errno = %d\n",
gCode, errno));
if (gCode == 0) {
KMP_AFFINITY_ENABLE(KMP_CPU_SET_SIZE_LIMIT);
KA_TRACE(10, ("__kmp_affinity_determine_capable: "
"affinity supported (mask size %d)\n",
(int)__kmp_affin_mask_size));
KMP_INTERNAL_FREE(buf);
return;
}
#endif
KMP_INTERNAL_FREE(buf);
KMP_AFFINITY_DISABLE();
KA_TRACE(10, ("__kmp_affinity_determine_capable: "
"cannot determine mask size - affinity not supported\n"));
if (verbose || (warnings && (type != affinity_none) &&
(type != affinity_default) && (type != affinity_disabled))) {
KMP_WARNING(AffCantGetMaskSize, env_var);
}
}
#endif
#endif
KMP_OS_DRAGONFLY || KMP_OS_AIX) && KMP_AFFINITY_SUPPORTED
#if KMP_USE_FUTEX
int __kmp_futex_determine_capable() {
int loc = 0;
long rc = syscall(__NR_futex, &loc, FUTEX_WAKE, 1, NULL, NULL, 0);
int retval = (rc == 0) || (errno != ENOSYS);
KA_TRACE(10,
("__kmp_futex_determine_capable: rc = %d errno = %d\n", rc, errno));
KA_TRACE(10, ("__kmp_futex_determine_capable: futex syscall%s supported\n",
retval ? "" : " not"));
return retval;
}
#endif
#if (KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_ARCH_WASM) && (!KMP_ASM_INTRINS)
use compare_and_store for these routines */
kmp_int8 __kmp_test_then_or8(volatile kmp_int8 *p, kmp_int8 d) {
kmp_int8 old_value, new_value;
old_value = TCR_1(*p);
new_value = old_value | d;
while (!KMP_COMPARE_AND_STORE_REL8(p, old_value, new_value)) {
KMP_CPU_PAUSE();
old_value = TCR_1(*p);
new_value = old_value | d;
}
return old_value;
}
kmp_int8 __kmp_test_then_and8(volatile kmp_int8 *p, kmp_int8 d) {
kmp_int8 old_value, new_value;
old_value = TCR_1(*p);
new_value = old_value & d;
while (!KMP_COMPARE_AND_STORE_REL8(p, old_value, new_value)) {
KMP_CPU_PAUSE();
old_value = TCR_1(*p);
new_value = old_value & d;
}
return old_value;
}
kmp_uint32 __kmp_test_then_or32(volatile kmp_uint32 *p, kmp_uint32 d) {
kmp_uint32 old_value, new_value;
old_value = TCR_4(*p);
new_value = old_value | d;
while (!KMP_COMPARE_AND_STORE_REL32(p, old_value, new_value)) {
KMP_CPU_PAUSE();
old_value = TCR_4(*p);
new_value = old_value | d;
}
return old_value;
}
kmp_uint32 __kmp_test_then_and32(volatile kmp_uint32 *p, kmp_uint32 d) {
kmp_uint32 old_value, new_value;
old_value = TCR_4(*p);
new_value = old_value & d;
while (!KMP_COMPARE_AND_STORE_REL32(p, old_value, new_value)) {
KMP_CPU_PAUSE();
old_value = TCR_4(*p);
new_value = old_value & d;
}
return old_value;
}
#if KMP_ARCH_X86 || KMP_ARCH_WASM
kmp_int8 __kmp_test_then_add8(volatile kmp_int8 *p, kmp_int8 d) {
kmp_int8 old_value, new_value;
old_value = TCR_1(*p);
new_value = old_value + d;
while (!KMP_COMPARE_AND_STORE_REL8(p, old_value, new_value)) {
KMP_CPU_PAUSE();
old_value = TCR_1(*p);
new_value = old_value + d;
}
return old_value;
}
kmp_int64 __kmp_test_then_add64(volatile kmp_int64 *p, kmp_int64 d) {
kmp_int64 old_value, new_value;
old_value = TCR_8(*p);
new_value = old_value + d;
while (!KMP_COMPARE_AND_STORE_REL64(p, old_value, new_value)) {
KMP_CPU_PAUSE();
old_value = TCR_8(*p);
new_value = old_value + d;
}
return old_value;
}
#endif
kmp_uint64 __kmp_test_then_or64(volatile kmp_uint64 *p, kmp_uint64 d) {
kmp_uint64 old_value, new_value;
old_value = TCR_8(*p);
new_value = old_value | d;
while (!KMP_COMPARE_AND_STORE_REL64(p, old_value, new_value)) {
KMP_CPU_PAUSE();
old_value = TCR_8(*p);
new_value = old_value | d;
}
return old_value;
}
kmp_uint64 __kmp_test_then_and64(volatile kmp_uint64 *p, kmp_uint64 d) {
kmp_uint64 old_value, new_value;
old_value = TCR_8(*p);
new_value = old_value & d;
while (!KMP_COMPARE_AND_STORE_REL64(p, old_value, new_value)) {
KMP_CPU_PAUSE();
old_value = TCR_8(*p);
new_value = old_value & d;
}
return old_value;
}
#endif
void __kmp_terminate_thread(int gtid) {
int status;
kmp_info_t *th = __kmp_threads[gtid];
if (!th)
return;
#ifdef KMP_CANCEL_THREADS
KA_TRACE(10, ("__kmp_terminate_thread: kill (%d)\n", gtid));
status = pthread_cancel(th->th.th_info.ds.ds_thread);
if (status != 0 && status != ESRCH) {
__kmp_fatal(KMP_MSG(CantTerminateWorkerThread), KMP_ERR(status),
__kmp_msg_null);
}
#endif
KMP_YIELD(TRUE);
}
If values are unreasonable, assume call failed and use incremental stack
refinement method instead. Returns TRUE if the stack parameters could be
determined exactly, FALSE if incremental refinement is necessary. */
static kmp_int32 __kmp_set_stack_info(int gtid, kmp_info_t *th) {
int stack_data;
#if KMP_OS_LINUX || KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD || \
KMP_OS_HURD || KMP_OS_SOLARIS || KMP_OS_AIX
int status;
size_t size = 0;
void *addr = 0;
initial thread stack range can be reduced by sibling thread creation so
pthread_attr_getstack may cause thread gtid aliasing */
if (!KMP_UBER_GTID(gtid)) {
#if KMP_OS_SOLARIS
stack_t s;
if ((status = thr_stksegment(&s)) < 0) {
KMP_CHECK_SYSFAIL("thr_stksegment", status);
}
addr = s.ss_sp;
size = s.ss_size;
KA_TRACE(60, ("__kmp_set_stack_info: T#%d thr_stksegment returned size:"
" %lu, low addr: %p\n",
gtid, size, addr));
#else
pthread_attr_t attr;
status = pthread_attr_init(&attr);
KMP_CHECK_SYSFAIL("pthread_attr_init", status);
#if KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD
status = pthread_attr_get_np(pthread_self(), &attr);
KMP_CHECK_SYSFAIL("pthread_attr_get_np", status);
#else
status = pthread_getattr_np(pthread_self(), &attr);
KMP_CHECK_SYSFAIL("pthread_getattr_np", status);
#endif
status = pthread_attr_getstack(&attr, &addr, &size);
KMP_CHECK_SYSFAIL("pthread_attr_getstack", status);
KA_TRACE(60,
("__kmp_set_stack_info: T#%d pthread_attr_getstack returned size:"
" %lu, low addr: %p\n",
gtid, size, addr));
status = pthread_attr_destroy(&attr);
KMP_CHECK_SYSFAIL("pthread_attr_destroy", status);
#endif
}
if (size != 0 && addr != 0) {
TCW_PTR(th->th.th_info.ds.ds_stackbase, (((char *)addr) + size));
TCW_PTR(th->th.th_info.ds.ds_stacksize, size);
TCW_4(th->th.th_info.ds.ds_stackgrow, FALSE);
return TRUE;
}
#endif
|| KMP_OS_HURD || KMP_OS_SOLARIS */
TCW_PTR(th->th.th_info.ds.ds_stacksize, 0);
TCW_PTR(th->th.th_info.ds.ds_stackbase, &stack_data);
TCW_4(th->th.th_info.ds.ds_stackgrow, TRUE);
return FALSE;
}
static void *__kmp_launch_worker(void *thr) {
int status, old_type, old_state;
#ifdef KMP_BLOCK_SIGNALS
sigset_t new_set, old_set;
#endif
void *exit_val;
#if KMP_OS_LINUX || KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD || \
KMP_OS_OPENBSD || KMP_OS_HURD || KMP_OS_SOLARIS || KMP_OS_AIX
void *volatile padding = 0;
#endif
int gtid;
gtid = ((kmp_info_t *)thr)->th.th_info.ds.ds_gtid;
__kmp_gtid_set_specific(gtid);
#ifdef KMP_TDATA_GTID
__kmp_gtid = gtid;
#endif
#if KMP_STATS_ENABLED
__kmp_stats_thread_ptr = ((kmp_info_t *)thr)->th.th_stats;
__kmp_stats_thread_ptr->startLife();
KMP_SET_THREAD_STATE(IDLE);
KMP_INIT_PARTITIONED_TIMERS(OMP_idle);
#endif
#if USE_ITT_BUILD
__kmp_itt_thread_name(gtid);
#endif
#if KMP_AFFINITY_SUPPORTED
__kmp_affinity_bind_init_mask(gtid);
#endif
#ifdef KMP_CANCEL_THREADS
status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type);
KMP_CHECK_SYSFAIL("pthread_setcanceltype", status);
status = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_state);
KMP_CHECK_SYSFAIL("pthread_setcancelstate", status);
#endif
#if KMP_ARCH_X86 || KMP_ARCH_X86_64
__kmp_clear_x87_fpu_status_word();
__kmp_load_x87_fpu_control_word(&__kmp_init_x87_fpu_control_word);
__kmp_load_mxcsr(&__kmp_init_mxcsr);
#endif
#ifdef KMP_BLOCK_SIGNALS
status = sigfillset(&new_set);
KMP_CHECK_SYSFAIL_ERRNO("sigfillset", status);
status = pthread_sigmask(SIG_BLOCK, &new_set, &old_set);
KMP_CHECK_SYSFAIL("pthread_sigmask", status);
#endif
#if KMP_OS_LINUX || KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD || \
KMP_OS_OPENBSD || KMP_OS_HURD || KMP_OS_SOLARIS || KMP_OS_AIX
if (__kmp_stkoffset > 0 && gtid > 0) {
padding = KMP_ALLOCA(gtid * __kmp_stkoffset);
(void)padding;
}
#endif
KMP_MB();
__kmp_set_stack_info(gtid, (kmp_info_t *)thr);
__kmp_check_stack_overlap((kmp_info_t *)thr);
exit_val = __kmp_launch_thread((kmp_info_t *)thr);
#ifdef KMP_BLOCK_SIGNALS
status = pthread_sigmask(SIG_SETMASK, &old_set, NULL);
KMP_CHECK_SYSFAIL("pthread_sigmask", status);
#endif
return exit_val;
}
#if KMP_USE_MONITOR
static void *__kmp_launch_monitor(void *thr) {
int status, old_type, old_state;
#ifdef KMP_BLOCK_SIGNALS
sigset_t new_set;
#endif
struct timespec interval;
KMP_MB();
KA_TRACE(10, ("__kmp_launch_monitor: #1 launched\n"));
__kmp_gtid_set_specific(KMP_GTID_MONITOR);
#ifdef KMP_TDATA_GTID
__kmp_gtid = KMP_GTID_MONITOR;
#endif
KMP_MB();
#if USE_ITT_BUILD
__kmp_itt_thread_ignore();
#endif
__kmp_set_stack_info(((kmp_info_t *)thr)->th.th_info.ds.ds_gtid,
(kmp_info_t *)thr);
__kmp_check_stack_overlap((kmp_info_t *)thr);
#ifdef KMP_CANCEL_THREADS
status = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &old_type);
KMP_CHECK_SYSFAIL("pthread_setcanceltype", status);
status = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &old_state);
KMP_CHECK_SYSFAIL("pthread_setcancelstate", status);
#endif
#if KMP_REAL_TIME_FIX
{
int sched = sched_getscheduler(0);
if (sched == SCHED_FIFO || sched == SCHED_RR) {
struct sched_param param;
int max_priority = sched_get_priority_max(sched);
int rc;
KMP_WARNING(RealTimeSchedNotSupported);
sched_getparam(0, ¶m);
if (param.sched_priority < max_priority) {
param.sched_priority += 1;
rc = sched_setscheduler(0, sched, ¶m);
if (rc != 0) {
int error = errno;
kmp_msg_t err_code = KMP_ERR(error);
__kmp_msg(kmp_ms_warning, KMP_MSG(CantChangeMonitorPriority),
err_code, KMP_MSG(MonitorWillStarve), __kmp_msg_null);
if (__kmp_generate_warnings == kmp_warnings_off) {
__kmp_str_free(&err_code.str);
}
}
} else {
__kmp_msg(kmp_ms_warning, KMP_MSG(RunningAtMaxPriority),
KMP_MSG(MonitorWillStarve), KMP_HNT(RunningAtMaxPriority),
__kmp_msg_null);
}
}
TCW_4(__kmp_global.g.g_time.dt.t_value, 0);
}
#endif
KMP_MB();
if (__kmp_monitor_wakeups == 1) {
interval.tv_sec = 1;
interval.tv_nsec = 0;
} else {
interval.tv_sec = 0;
interval.tv_nsec = (KMP_NSEC_PER_SEC / __kmp_monitor_wakeups);
}
KA_TRACE(10, ("__kmp_launch_monitor: #2 monitor\n"));
while (!TCR_4(__kmp_global.g.g_done)) {
struct timespec now;
struct timeval tval;
KA_TRACE(15, ("__kmp_launch_monitor: update\n"));
status = gettimeofday(&tval, NULL);
KMP_CHECK_SYSFAIL_ERRNO("gettimeofday", status);
TIMEVAL_TO_TIMESPEC(&tval, &now);
now.tv_sec += interval.tv_sec;
now.tv_nsec += interval.tv_nsec;
if (now.tv_nsec >= KMP_NSEC_PER_SEC) {
now.tv_sec += 1;
now.tv_nsec -= KMP_NSEC_PER_SEC;
}
status = pthread_mutex_lock(&__kmp_wait_mx.m_mutex);
KMP_CHECK_SYSFAIL("pthread_mutex_lock", status);
if (!TCR_4(__kmp_global.g.g_done)) {
status = pthread_cond_timedwait(&__kmp_wait_cv.c_cond,
&__kmp_wait_mx.m_mutex, &now);
if (status != 0) {
if (status != ETIMEDOUT && status != EINTR) {
KMP_SYSFAIL("pthread_cond_timedwait", status);
}
}
}
status = pthread_mutex_unlock(&__kmp_wait_mx.m_mutex);
KMP_CHECK_SYSFAIL("pthread_mutex_unlock", status);
TCW_4(__kmp_global.g.g_time.dt.t_value,
TCR_4(__kmp_global.g.g_time.dt.t_value) + 1);
KMP_MB();
}
KA_TRACE(10, ("__kmp_launch_monitor: #3 cleanup\n"));
#ifdef KMP_BLOCK_SIGNALS
status = sigfillset(&new_set);
KMP_CHECK_SYSFAIL_ERRNO("sigfillset", status);
status = pthread_sigmask(SIG_UNBLOCK, &new_set, NULL);
KMP_CHECK_SYSFAIL("pthread_sigmask", status);
#endif
KA_TRACE(10, ("__kmp_launch_monitor: #4 finished\n"));
if (__kmp_global.g.g_abort != 0) {
int gtid;
KA_TRACE(10, ("__kmp_launch_monitor: #5 terminate sig=%d\n",
__kmp_global.g.g_abort));
* the uber master might not be 0 anymore.. */
for (gtid = 1; gtid < __kmp_threads_capacity; ++gtid)
__kmp_terminate_thread(gtid);
__kmp_cleanup();
KA_TRACE(10, ("__kmp_launch_monitor: #6 raise sig=%d\n",
__kmp_global.g.g_abort));
if (__kmp_global.g.g_abort > 0)
raise(__kmp_global.g.g_abort);
}
KA_TRACE(10, ("__kmp_launch_monitor: #7 exit\n"));
return thr;
}
#endif
void __kmp_create_worker(int gtid, kmp_info_t *th, size_t stack_size) {
pthread_t handle;
pthread_attr_t thread_attr;
int status;
th->th.th_info.ds.ds_gtid = gtid;
#if KMP_STATS_ENABLED
__kmp_acquire_tas_lock(&__kmp_stats_lock, gtid);
if (!KMP_UBER_GTID(gtid)) {
th->th.th_stats = __kmp_stats_list->push_back(gtid);
} else {
th->th.th_stats = __kmp_stats_thread_ptr;
}
__kmp_release_tas_lock(&__kmp_stats_lock, gtid);
#endif
if (KMP_UBER_GTID(gtid)) {
KA_TRACE(10, ("__kmp_create_worker: uber thread (%d)\n", gtid));
th->th.th_info.ds.ds_thread = pthread_self();
__kmp_set_stack_info(gtid, th);
__kmp_check_stack_overlap(th);
return;
}
KA_TRACE(10, ("__kmp_create_worker: try to create thread (%d)\n", gtid));
KMP_MB();
#ifdef KMP_THREAD_ATTR
status = pthread_attr_init(&thread_attr);
if (status != 0) {
__kmp_fatal(KMP_MSG(CantInitThreadAttrs), KMP_ERR(status), __kmp_msg_null);
}
status = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
if (status != 0) {
__kmp_fatal(KMP_MSG(CantSetWorkerState), KMP_ERR(status), __kmp_msg_null);
}
The multiple of 2 is there because on some machines, requesting an unusual
stacksize causes the thread to have an offset before the dummy alloca()
takes place to create the offset. Since we want the user to have a
sufficient stacksize AND support a stack offset, we alloca() twice the
offset so that the upcoming alloca() does not eliminate any premade offset,
and also gives the user the stack space they requested for all threads */
stack_size += gtid * __kmp_stkoffset * 2;
KA_TRACE(10, ("__kmp_create_worker: T#%d, default stacksize = %lu bytes, "
"__kmp_stksize = %lu bytes, final stacksize = %lu bytes\n",
gtid, KMP_DEFAULT_STKSIZE, __kmp_stksize, stack_size));
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
status = pthread_attr_setstacksize(&thread_attr, stack_size);
#ifdef KMP_BACKUP_STKSIZE
if (status != 0) {
if (!__kmp_env_stksize) {
stack_size = KMP_BACKUP_STKSIZE + gtid * __kmp_stkoffset;
__kmp_stksize = KMP_BACKUP_STKSIZE;
KA_TRACE(10, ("__kmp_create_worker: T#%d, default stacksize = %lu bytes, "
"__kmp_stksize = %lu bytes, (backup) final stacksize = %lu "
"bytes\n",
gtid, KMP_DEFAULT_STKSIZE, __kmp_stksize, stack_size));
status = pthread_attr_setstacksize(&thread_attr, stack_size);
}
}
#endif
if (status != 0) {
__kmp_fatal(KMP_MSG(CantSetWorkerStackSize, stack_size), KMP_ERR(status),
KMP_HNT(ChangeWorkerStackSize), __kmp_msg_null);
}
#endif
#endif
status =
pthread_create(&handle, &thread_attr, __kmp_launch_worker, (void *)th);
if (status != 0 || !handle) {
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
if (status == EINVAL) {
__kmp_fatal(KMP_MSG(CantSetWorkerStackSize, stack_size), KMP_ERR(status),
KMP_HNT(IncreaseWorkerStackSize), __kmp_msg_null);
}
if (status == ENOMEM) {
__kmp_fatal(KMP_MSG(CantSetWorkerStackSize, stack_size), KMP_ERR(status),
KMP_HNT(DecreaseWorkerStackSize), __kmp_msg_null);
}
#endif
if (status == EAGAIN) {
__kmp_fatal(KMP_MSG(NoResourcesForWorkerThread), KMP_ERR(status),
KMP_HNT(Decrease_NUM_THREADS), __kmp_msg_null);
}
KMP_SYSFAIL("pthread_create", status);
}
th->th.th_info.ds.ds_thread = handle;
#ifdef KMP_THREAD_ATTR
status = pthread_attr_destroy(&thread_attr);
if (status) {
kmp_msg_t err_code = KMP_ERR(status);
__kmp_msg(kmp_ms_warning, KMP_MSG(CantDestroyThreadAttrs), err_code,
__kmp_msg_null);
if (__kmp_generate_warnings == kmp_warnings_off) {
__kmp_str_free(&err_code.str);
}
}
#endif
KMP_MB();
KA_TRACE(10, ("__kmp_create_worker: done creating thread (%d)\n", gtid));
}
#if KMP_USE_MONITOR
void __kmp_create_monitor(kmp_info_t *th) {
pthread_t handle;
pthread_attr_t thread_attr;
size_t size;
int status;
int auto_adj_size = FALSE;
if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME) {
KA_TRACE(10, ("__kmp_create_monitor: skipping monitor thread because of "
"MAX blocktime\n"));
th->th.th_info.ds.ds_tid = 0;
th->th.th_info.ds.ds_gtid = 0;
return;
}
KA_TRACE(10, ("__kmp_create_monitor: try to create monitor\n"));
KMP_MB();
th->th.th_info.ds.ds_tid = KMP_GTID_MONITOR;
th->th.th_info.ds.ds_gtid = KMP_GTID_MONITOR;
#if KMP_REAL_TIME_FIX
TCW_4(__kmp_global.g.g_time.dt.t_value,
-1);
#else
TCW_4(__kmp_global.g.g_time.dt.t_value, 0);
#endif
#ifdef KMP_THREAD_ATTR
if (__kmp_monitor_stksize == 0) {
__kmp_monitor_stksize = KMP_DEFAULT_MONITOR_STKSIZE;
auto_adj_size = TRUE;
}
status = pthread_attr_init(&thread_attr);
if (status != 0) {
__kmp_fatal(KMP_MSG(CantInitThreadAttrs), KMP_ERR(status), __kmp_msg_null);
}
status = pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE);
if (status != 0) {
__kmp_fatal(KMP_MSG(CantSetMonitorState), KMP_ERR(status), __kmp_msg_null);
}
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
status = pthread_attr_getstacksize(&thread_attr, &size);
KMP_CHECK_SYSFAIL("pthread_attr_getstacksize", status);
#else
size = __kmp_sys_min_stksize;
#endif
#endif
if (__kmp_monitor_stksize == 0) {
__kmp_monitor_stksize = KMP_DEFAULT_MONITOR_STKSIZE;
}
if (__kmp_monitor_stksize < __kmp_sys_min_stksize) {
__kmp_monitor_stksize = __kmp_sys_min_stksize;
}
KA_TRACE(10, ("__kmp_create_monitor: default stacksize = %lu bytes,"
"requested stacksize = %lu bytes\n",
size, __kmp_monitor_stksize));
retry:
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
KA_TRACE(10, ("__kmp_create_monitor: setting stacksize = %lu bytes,",
__kmp_monitor_stksize));
status = pthread_attr_setstacksize(&thread_attr, __kmp_monitor_stksize);
if (status != 0) {
if (auto_adj_size) {
__kmp_monitor_stksize *= 2;
goto retry;
}
kmp_msg_t err_code = KMP_ERR(status);
__kmp_msg(kmp_ms_warning,
KMP_MSG(CantSetMonitorStackSize, (long int)__kmp_monitor_stksize),
err_code, KMP_HNT(ChangeMonitorStackSize), __kmp_msg_null);
if (__kmp_generate_warnings == kmp_warnings_off) {
__kmp_str_free(&err_code.str);
}
}
#endif
status =
pthread_create(&handle, &thread_attr, __kmp_launch_monitor, (void *)th);
if (status != 0) {
#ifdef _POSIX_THREAD_ATTR_STACKSIZE
if (status == EINVAL) {
if (auto_adj_size && (__kmp_monitor_stksize < (size_t)0x40000000)) {
__kmp_monitor_stksize *= 2;
goto retry;
}
__kmp_fatal(KMP_MSG(CantSetMonitorStackSize, __kmp_monitor_stksize),
KMP_ERR(status), KMP_HNT(IncreaseMonitorStackSize),
__kmp_msg_null);
}
if (status == ENOMEM) {
__kmp_fatal(KMP_MSG(CantSetMonitorStackSize, __kmp_monitor_stksize),
KMP_ERR(status), KMP_HNT(DecreaseMonitorStackSize),
__kmp_msg_null);
}
#endif
if (status == EAGAIN) {
__kmp_fatal(KMP_MSG(NoResourcesForMonitorThread), KMP_ERR(status),
KMP_HNT(DecreaseNumberOfThreadsInUse), __kmp_msg_null);
}
KMP_SYSFAIL("pthread_create", status);
}
th->th.th_info.ds.ds_thread = handle;
#if KMP_REAL_TIME_FIX
KMP_DEBUG_ASSERT(sizeof(kmp_uint32) ==
sizeof(__kmp_global.g.g_time.dt.t_value));
__kmp_wait_4((kmp_uint32 volatile *)&__kmp_global.g.g_time.dt.t_value, -1,
&__kmp_neq_4, NULL);
#endif
#ifdef KMP_THREAD_ATTR
status = pthread_attr_destroy(&thread_attr);
if (status != 0) {
kmp_msg_t err_code = KMP_ERR(status);
__kmp_msg(kmp_ms_warning, KMP_MSG(CantDestroyThreadAttrs), err_code,
__kmp_msg_null);
if (__kmp_generate_warnings == kmp_warnings_off) {
__kmp_str_free(&err_code.str);
}
}
#endif
KMP_MB();
KA_TRACE(10, ("__kmp_create_monitor: monitor created %#.8lx\n",
th->th.th_info.ds.ds_thread));
}
#endif
void __kmp_exit_thread(int exit_status) {
#if KMP_OS_WASI
#else
pthread_exit((void *)(intptr_t)exit_status);
#endif
}
#if KMP_USE_MONITOR
void __kmp_resume_monitor();
extern "C" void __kmp_reap_monitor(kmp_info_t *th) {
int status;
void *exit_val;
KA_TRACE(10, ("__kmp_reap_monitor: try to reap monitor thread with handle"
" %#.8lx\n",
th->th.th_info.ds.ds_thread));
KMP_DEBUG_ASSERT(th->th.th_info.ds.ds_tid == th->th.th_info.ds.ds_gtid);
if (th->th.th_info.ds.ds_gtid != KMP_GTID_MONITOR) {
KA_TRACE(10, ("__kmp_reap_monitor: monitor did not start, returning\n"));
return;
}
KMP_MB();
is to avoid performance problem when the monitor sleeps during
blocktime-size interval */
status = pthread_kill(th->th.th_info.ds.ds_thread, 0);
if (status != ESRCH) {
__kmp_resume_monitor();
}
KA_TRACE(10, ("__kmp_reap_monitor: try to join with monitor\n"));
status = pthread_join(th->th.th_info.ds.ds_thread, &exit_val);
if (exit_val != th) {
__kmp_fatal(KMP_MSG(ReapMonitorError), KMP_ERR(status), __kmp_msg_null);
}
th->th.th_info.ds.ds_tid = KMP_GTID_DNE;
th->th.th_info.ds.ds_gtid = KMP_GTID_DNE;
KA_TRACE(10, ("__kmp_reap_monitor: done reaping monitor thread with handle"
" %#.8lx\n",
th->th.th_info.ds.ds_thread));
KMP_MB();
}
#else
extern "C" void __kmp_reap_monitor(kmp_info_t *th) { (void)th; }
#endif
void __kmp_reap_worker(kmp_info_t *th) {
int status;
void *exit_val;
KMP_MB();
KA_TRACE(
10, ("__kmp_reap_worker: try to reap T#%d\n", th->th.th_info.ds.ds_gtid));
status = pthread_join(th->th.th_info.ds.ds_thread, &exit_val);
#ifdef KMP_DEBUG
if (status != 0) {
__kmp_fatal(KMP_MSG(ReapWorkerError), KMP_ERR(status), __kmp_msg_null);
}
if (exit_val != th) {
KA_TRACE(10, ("__kmp_reap_worker: worker T#%d did not reap properly, "
"exit_val = %p\n",
th->th.th_info.ds.ds_gtid, exit_val));
}
#else
(void)status;
#endif
KA_TRACE(10, ("__kmp_reap_worker: done reaping T#%d\n",
th->th.th_info.ds.ds_gtid));
KMP_MB();
}
#if KMP_HANDLE_SIGNALS
static void __kmp_null_handler(int signo) {
}
static void __kmp_team_handler(int signo) {
if (__kmp_global.g.g_abort == 0) {
#ifdef KMP_DEBUG
__kmp_debug_printf("__kmp_team_handler: caught signal = %d\n", signo);
#endif
switch (signo) {
case SIGHUP:
case SIGINT:
case SIGQUIT:
case SIGILL:
case SIGABRT:
case SIGFPE:
case SIGBUS:
case SIGSEGV:
#ifdef SIGSYS
case SIGSYS:
#endif
case SIGTERM:
if (__kmp_debug_buf) {
__kmp_dump_debug_buffer();
}
__kmp_unregister_library();
KMP_MB();
TCW_4(__kmp_global.g.g_abort, signo);
KMP_MB();
TCW_4(__kmp_global.g.g_done, TRUE);
KMP_MB();
break;
default:
#ifdef KMP_DEBUG
__kmp_debug_printf("__kmp_team_handler: unknown signal type");
#endif
break;
}
}
}
static void __kmp_sigaction(int signum, const struct sigaction *act,
struct sigaction *oldact) {
int rc = sigaction(signum, act, oldact);
KMP_CHECK_SYSFAIL_ERRNO("sigaction", rc);
}
static void __kmp_install_one_handler(int sig, sig_func_t handler_func,
int parallel_init) {
KMP_MB();
KB_TRACE(60,
("__kmp_install_one_handler( %d, ..., %d )\n", sig, parallel_init));
if (parallel_init) {
struct sigaction new_action;
struct sigaction old_action;
new_action.sa_handler = handler_func;
new_action.sa_flags = 0;
sigfillset(&new_action.sa_mask);
__kmp_sigaction(sig, &new_action, &old_action);
if (old_action.sa_handler == __kmp_sighldrs[sig].sa_handler) {
sigaddset(&__kmp_sigset, sig);
} else {
__kmp_sigaction(sig, &old_action, NULL);
}
} else {
__kmp_sigaction(sig, NULL, &__kmp_sighldrs[sig]);
}
KMP_MB();
}
static void __kmp_remove_one_handler(int sig) {
KB_TRACE(60, ("__kmp_remove_one_handler( %d )\n", sig));
if (sigismember(&__kmp_sigset, sig)) {
struct sigaction old;
KMP_MB();
__kmp_sigaction(sig, &__kmp_sighldrs[sig], &old);
if ((old.sa_handler != __kmp_team_handler) &&
(old.sa_handler != __kmp_null_handler)) {
KB_TRACE(10, ("__kmp_remove_one_handler: oops, not our handler, "
"restoring: sig=%d\n",
sig));
__kmp_sigaction(sig, &old, NULL);
}
sigdelset(&__kmp_sigset, sig);
KMP_MB();
}
}
void __kmp_install_signals(int parallel_init) {
KB_TRACE(10, ("__kmp_install_signals( %d )\n", parallel_init));
if (__kmp_handle_signals || !parallel_init) {
sigemptyset(&__kmp_sigset);
__kmp_install_one_handler(SIGHUP, __kmp_team_handler, parallel_init);
__kmp_install_one_handler(SIGINT, __kmp_team_handler, parallel_init);
__kmp_install_one_handler(SIGQUIT, __kmp_team_handler, parallel_init);
__kmp_install_one_handler(SIGILL, __kmp_team_handler, parallel_init);
__kmp_install_one_handler(SIGABRT, __kmp_team_handler, parallel_init);
__kmp_install_one_handler(SIGFPE, __kmp_team_handler, parallel_init);
__kmp_install_one_handler(SIGBUS, __kmp_team_handler, parallel_init);
__kmp_install_one_handler(SIGSEGV, __kmp_team_handler, parallel_init);
#ifdef SIGSYS
__kmp_install_one_handler(SIGSYS, __kmp_team_handler, parallel_init);
#endif
__kmp_install_one_handler(SIGTERM, __kmp_team_handler, parallel_init);
#ifdef SIGPIPE
__kmp_install_one_handler(SIGPIPE, __kmp_team_handler, parallel_init);
#endif
}
}
void __kmp_remove_signals(void) {
int sig;
KB_TRACE(10, ("__kmp_remove_signals()\n"));
for (sig = 1; sig < NSIG; ++sig) {
__kmp_remove_one_handler(sig);
}
}
#endif
void __kmp_enable(int new_state) {
#ifdef KMP_CANCEL_THREADS
int status, old_state;
status = pthread_setcancelstate(new_state, &old_state);
KMP_CHECK_SYSFAIL("pthread_setcancelstate", status);
KMP_DEBUG_ASSERT(old_state == PTHREAD_CANCEL_DISABLE);
#endif
}
void __kmp_disable(int *old_state) {
#ifdef KMP_CANCEL_THREADS
int status;
status = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, old_state);
KMP_CHECK_SYSFAIL("pthread_setcancelstate", status);
#endif
}
static void __kmp_atfork_prepare(void) {
__kmp_acquire_bootstrap_lock(&__kmp_initz_lock);
__kmp_acquire_bootstrap_lock(&__kmp_forkjoin_lock);
}
static void __kmp_atfork_parent(void) {
__kmp_release_bootstrap_lock(&__kmp_forkjoin_lock);
__kmp_release_bootstrap_lock(&__kmp_initz_lock);
}
clean data structures in initial states. Don't worry about freeing memory
allocated by parent, just abandon it to be safe. */
static void __kmp_atfork_child(void) {
__kmp_release_bootstrap_lock(&__kmp_forkjoin_lock);
__kmp_release_bootstrap_lock(&__kmp_initz_lock);
++__kmp_fork_count;
#if KMP_AFFINITY_SUPPORTED
#if KMP_OS_LINUX || KMP_OS_FREEBSD || KMP_OS_NETBSD || KMP_OS_DRAGONFLY || \
KMP_OS_AIX
kmp_set_thread_affinity_mask_initial();
#endif
if (__kmp_nested_proc_bind.bind_types != NULL) {
__kmp_nested_proc_bind.bind_types[0] = proc_bind_false;
}
for (kmp_affinity_t *affinity : __kmp_affinities)
*affinity = KMP_AFFINITY_INIT(affinity->env_var);
__kmp_affin_fullMask = nullptr;
__kmp_affin_origMask = nullptr;
__kmp_topology = nullptr;
#endif
#if KMP_USE_MONITOR
__kmp_init_monitor = 0;
#endif
__kmp_init_parallel = FALSE;
__kmp_init_middle = FALSE;
__kmp_init_serial = FALSE;
TCW_4(__kmp_init_gtid, FALSE);
__kmp_init_common = FALSE;
TCW_4(__kmp_init_user_locks, FALSE);
#if !KMP_USE_DYNAMIC_LOCK
__kmp_user_lock_table.used = 1;
__kmp_user_lock_table.allocated = 0;
__kmp_user_lock_table.table = NULL;
__kmp_lock_blocks = NULL;
#endif
__kmp_all_nth = 0;
TCW_4(__kmp_nth, 0);
__kmp_thread_pool = NULL;
__kmp_thread_pool_insert_pt = NULL;
__kmp_team_pool = NULL;
here so threadprivate doesn't use stale data */
KA_TRACE(10, ("__kmp_atfork_child: checking cache address list %p\n",
__kmp_threadpriv_cache_list));
while (__kmp_threadpriv_cache_list != NULL) {
if (*__kmp_threadpriv_cache_list->addr != NULL) {
KC_TRACE(50, ("__kmp_atfork_child: zeroing cache at address %p\n",
&(*__kmp_threadpriv_cache_list->addr)));
*__kmp_threadpriv_cache_list->addr = NULL;
}
__kmp_threadpriv_cache_list = __kmp_threadpriv_cache_list->next;
}
__kmp_init_runtime = FALSE;
__kmp_init_bootstrap_lock(&__kmp_initz_lock);
__kmp_init_bootstrap_lock(&__kmp_stdio_lock);
__kmp_init_bootstrap_lock(&__kmp_console_lock);
__kmp_init_bootstrap_lock(&__kmp_task_team_lock);
#if USE_ITT_BUILD
__kmp_itt_reset();
#endif
{
__kmp_need_register_serial = FALSE;
__kmp_serial_initialize();
}
handler. Mathworks: dlsym() is unsafe. We call dlsym and dlopen
in dynamic_link when check the presence of shared tbbmalloc library.
Suggestion is to make the library initialization lazier, similar
to what done for __kmpc_begin(). */
}
void __kmp_register_atfork(void) {
if (__kmp_need_register_atfork) {
#if !KMP_OS_WASI
int status = pthread_atfork(__kmp_atfork_prepare, __kmp_atfork_parent,
__kmp_atfork_child);
KMP_CHECK_SYSFAIL("pthread_atfork", status);
#endif
__kmp_need_register_atfork = FALSE;
}
}
void __kmp_suspend_initialize(void) {
int status;
status = pthread_mutexattr_init(&__kmp_suspend_mutex_attr);
KMP_CHECK_SYSFAIL("pthread_mutexattr_init", status);
status = pthread_condattr_init(&__kmp_suspend_cond_attr);
KMP_CHECK_SYSFAIL("pthread_condattr_init", status);
}
void __kmp_suspend_initialize_thread(kmp_info_t *th) {
int old_value = KMP_ATOMIC_LD_RLX(&th->th.th_suspend_init_count);
int new_value = __kmp_fork_count + 1;
if (old_value == new_value)
return;
if (old_value == -1 || !__kmp_atomic_compare_store(
&th->th.th_suspend_init_count, old_value, -1)) {
while (KMP_ATOMIC_LD_ACQ(&th->th.th_suspend_init_count) != new_value) {
KMP_CPU_PAUSE();
}
} else {
int status;
status = pthread_cond_init(&th->th.th_suspend_cv.c_cond,
&__kmp_suspend_cond_attr);
KMP_CHECK_SYSFAIL("pthread_cond_init", status);
status = pthread_mutex_init(&th->th.th_suspend_mx.m_mutex,
&__kmp_suspend_mutex_attr);
KMP_CHECK_SYSFAIL("pthread_mutex_init", status);
KMP_ATOMIC_ST_REL(&th->th.th_suspend_init_count, new_value);
}
}
void __kmp_suspend_uninitialize_thread(kmp_info_t *th) {
if (KMP_ATOMIC_LD_ACQ(&th->th.th_suspend_init_count) > __kmp_fork_count) {
thread in this instance of the process */
int status;
status = pthread_cond_destroy(&th->th.th_suspend_cv.c_cond);
if (status != 0 && status != EBUSY) {
KMP_SYSFAIL("pthread_cond_destroy", status);
}
status = pthread_mutex_destroy(&th->th.th_suspend_mx.m_mutex);
if (status != 0 && status != EBUSY) {
KMP_SYSFAIL("pthread_mutex_destroy", status);
}
--th->th.th_suspend_init_count;
KMP_DEBUG_ASSERT(KMP_ATOMIC_LD_RLX(&th->th.th_suspend_init_count) ==
__kmp_fork_count);
}
}
int __kmp_try_suspend_mx(kmp_info_t *th) {
return (pthread_mutex_trylock(&th->th.th_suspend_mx.m_mutex) == 0);
}
void __kmp_lock_suspend_mx(kmp_info_t *th) {
int status = pthread_mutex_lock(&th->th.th_suspend_mx.m_mutex);
KMP_CHECK_SYSFAIL("pthread_mutex_lock", status);
}
void __kmp_unlock_suspend_mx(kmp_info_t *th) {
int status = pthread_mutex_unlock(&th->th.th_suspend_mx.m_mutex);
KMP_CHECK_SYSFAIL("pthread_mutex_unlock", status);
}
sleep bit for the indicated flag variable to true. */
template <class C>
static inline void __kmp_suspend_template(int th_gtid, C *flag) {
KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(USER_suspend);
kmp_info_t *th = __kmp_threads[th_gtid];
int status;
typename C::flag_t old_spin;
KF_TRACE(30, ("__kmp_suspend_template: T#%d enter for flag = %p\n", th_gtid,
flag->get()));
__kmp_suspend_initialize_thread(th);
__kmp_lock_suspend_mx(th);
KF_TRACE(10, ("__kmp_suspend_template: T#%d setting sleep bit for spin(%p)\n",
th_gtid, flag->get()));
__kmp_suspend_initialize_thread gets called first? */
old_spin = flag->set_sleeping();
TCW_PTR(th->th.th_sleep_loc, (void *)flag);
th->th.th_sleep_loc_type = flag->get_type();
if (__kmp_dflt_blocktime == KMP_MAX_BLOCKTIME &&
__kmp_pause_status != kmp_soft_paused) {
flag->unset_sleeping();
TCW_PTR(th->th.th_sleep_loc, NULL);
th->th.th_sleep_loc_type = flag_unset;
__kmp_unlock_suspend_mx(th);
return;
}
KF_TRACE(5, ("__kmp_suspend_template: T#%d set sleep bit for spin(%p)==%x,"
" was %x\n",
th_gtid, flag->get(), flag->load(), old_spin));
if (flag->done_check_val(old_spin) || flag->done_check()) {
flag->unset_sleeping();
TCW_PTR(th->th.th_sleep_loc, NULL);
th->th.th_sleep_loc_type = flag_unset;
KF_TRACE(5, ("__kmp_suspend_template: T#%d false alarm, reset sleep bit "
"for spin(%p)\n",
th_gtid, flag->get()));
} else {
"with low probability" return when the condition variable has
not been signaled or broadcast */
int deactivated = FALSE;
while (flag->is_sleeping()) {
#ifdef DEBUG_SUSPEND
char buffer[128];
__kmp_suspend_count++;
__kmp_print_cond(buffer, &th->th.th_suspend_cv);
__kmp_printf("__kmp_suspend_template: suspending T#%d: %s\n", th_gtid,
buffer);
#endif
if (!deactivated) {
th->th.th_active = FALSE;
if (th->th.th_active_in_pool) {
th->th.th_active_in_pool = FALSE;
KMP_ATOMIC_DEC(&__kmp_thread_pool_active_nth);
KMP_DEBUG_ASSERT(TCR_4(__kmp_thread_pool_active_nth) >= 0);
}
deactivated = TRUE;
}
KMP_DEBUG_ASSERT(th->th.th_sleep_loc);
KMP_DEBUG_ASSERT(flag->get_type() == th->th.th_sleep_loc_type);
#if USE_SUSPEND_TIMEOUT
struct timespec now;
struct timeval tval;
int msecs;
status = gettimeofday(&tval, NULL);
KMP_CHECK_SYSFAIL_ERRNO("gettimeofday", status);
TIMEVAL_TO_TIMESPEC(&tval, &now);
msecs = (4 * __kmp_dflt_blocktime) + 200;
now.tv_sec += msecs / 1000;
now.tv_nsec += (msecs % 1000) * 1000;
KF_TRACE(15, ("__kmp_suspend_template: T#%d about to perform "
"pthread_cond_timedwait\n",
th_gtid));
status = pthread_cond_timedwait(&th->th.th_suspend_cv.c_cond,
&th->th.th_suspend_mx.m_mutex, &now);
#else
KF_TRACE(15, ("__kmp_suspend_template: T#%d about to perform"
" pthread_cond_wait\n",
th_gtid));
status = pthread_cond_wait(&th->th.th_suspend_cv.c_cond,
&th->th.th_suspend_mx.m_mutex);
#endif
if ((status != 0) && (status != EINTR) && (status != ETIMEDOUT)) {
KMP_SYSFAIL("pthread_cond_wait", status);
}
KMP_DEBUG_ASSERT(flag->get_type() == flag->get_ptr_type());
if (!flag->is_sleeping() &&
((status == EINTR) || (status == ETIMEDOUT))) {
flag->unset_sleeping();
TCW_PTR(th->th.th_sleep_loc, NULL);
th->th.th_sleep_loc_type = flag_unset;
}
#ifdef KMP_DEBUG
if (status == ETIMEDOUT) {
if (flag->is_sleeping()) {
KF_TRACE(100,
("__kmp_suspend_template: T#%d timeout wakeup\n", th_gtid));
} else {
KF_TRACE(2, ("__kmp_suspend_template: T#%d timeout wakeup, sleep bit "
"not set!\n",
th_gtid));
TCW_PTR(th->th.th_sleep_loc, NULL);
th->th.th_sleep_loc_type = flag_unset;
}
} else if (flag->is_sleeping()) {
KF_TRACE(100,
("__kmp_suspend_template: T#%d spurious wakeup\n", th_gtid));
}
#endif
}
if (deactivated) {
th->th.th_active = TRUE;
if (TCR_4(th->th.th_in_pool)) {
KMP_ATOMIC_INC(&__kmp_thread_pool_active_nth);
th->th.th_active_in_pool = TRUE;
}
}
}
TCW_PTR(th->th.th_sleep_loc, NULL);
th->th.th_sleep_loc_type = flag_unset;
KMP_DEBUG_ASSERT(!flag->is_sleeping());
KMP_DEBUG_ASSERT(!th->th.th_sleep_loc);
#ifdef DEBUG_SUSPEND
{
char buffer[128];
__kmp_print_cond(buffer, &th->th.th_suspend_cv);
__kmp_printf("__kmp_suspend_template: T#%d has awakened: %s\n", th_gtid,
buffer);
}
#endif
__kmp_unlock_suspend_mx(th);
KF_TRACE(30, ("__kmp_suspend_template: T#%d exit\n", th_gtid));
}
template <bool C, bool S>
void __kmp_suspend_32(int th_gtid, kmp_flag_32<C, S> *flag) {
__kmp_suspend_template(th_gtid, flag);
}
template <bool C, bool S>
void __kmp_suspend_64(int th_gtid, kmp_flag_64<C, S> *flag) {
__kmp_suspend_template(th_gtid, flag);
}
template <bool C, bool S>
void __kmp_atomic_suspend_64(int th_gtid, kmp_atomic_flag_64<C, S> *flag) {
__kmp_suspend_template(th_gtid, flag);
}
void __kmp_suspend_oncore(int th_gtid, kmp_flag_oncore *flag) {
__kmp_suspend_template(th_gtid, flag);
}
template void __kmp_suspend_32<false, false>(int, kmp_flag_32<false, false> *);
template void __kmp_suspend_64<false, true>(int, kmp_flag_64<false, true> *);
template void __kmp_suspend_64<true, false>(int, kmp_flag_64<true, false> *);
template void
__kmp_atomic_suspend_64<false, true>(int, kmp_atomic_flag_64<false, true> *);
template void
__kmp_atomic_suspend_64<true, false>(int, kmp_atomic_flag_64<true, false> *);
after setting the sleep bit indicated by the flag argument to FALSE.
The target thread must already have called __kmp_suspend_template() */
template <class C>
static inline void __kmp_resume_template(int target_gtid, C *flag) {
KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(USER_resume);
kmp_info_t *th = __kmp_threads[target_gtid];
int status;
#ifdef KMP_DEBUG
int gtid = TCR_4(__kmp_init_gtid) ? __kmp_get_gtid() : -1;
#endif
KF_TRACE(30, ("__kmp_resume_template: T#%d wants to wakeup T#%d enter\n",
gtid, target_gtid));
KMP_DEBUG_ASSERT(gtid != target_gtid);
__kmp_suspend_initialize_thread(th);
__kmp_lock_suspend_mx(th);
if (!flag || flag != th->th.th_sleep_loc) {
flag = (C *)CCAST(void *, th->th.th_sleep_loc);
}
if (!flag) {
KF_TRACE(5, ("__kmp_resume_template: T#%d exiting, thread T#%d already "
"awake: flag(%p)\n",
gtid, target_gtid, (void *)NULL));
__kmp_unlock_suspend_mx(th);
return;
} else if (flag->get_type() != th->th.th_sleep_loc_type) {
KF_TRACE(
5,
("__kmp_resume_template: T#%d retrying, thread T#%d Mismatch flag(%p), "
"spin(%p) type=%d ptr_type=%d\n",
gtid, target_gtid, flag, flag->get(), flag->get_type(),
th->th.th_sleep_loc_type));
__kmp_unlock_suspend_mx(th);
__kmp_null_resume_wrapper(th);
return;
} else {
if (!flag->is_sleeping()) {
KF_TRACE(5, ("__kmp_resume_template: T#%d exiting, thread T#%d already "
"awake: flag(%p): %u\n",
gtid, target_gtid, flag->get(), (unsigned int)flag->load()));
__kmp_unlock_suspend_mx(th);
return;
}
}
KMP_DEBUG_ASSERT(flag);
flag->unset_sleeping();
TCW_PTR(th->th.th_sleep_loc, NULL);
th->th.th_sleep_loc_type = flag_unset;
KF_TRACE(5, ("__kmp_resume_template: T#%d about to wakeup T#%d, reset "
"sleep bit for flag's loc(%p): %u\n",
gtid, target_gtid, flag->get(), (unsigned int)flag->load()));
#ifdef DEBUG_SUSPEND
{
char buffer[128];
__kmp_print_cond(buffer, &th->th.th_suspend_cv);
__kmp_printf("__kmp_resume_template: T#%d resuming T#%d: %s\n", gtid,
target_gtid, buffer);
}
#endif
status = pthread_cond_signal(&th->th.th_suspend_cv.c_cond);
KMP_CHECK_SYSFAIL("pthread_cond_signal", status);
__kmp_unlock_suspend_mx(th);
KF_TRACE(30, ("__kmp_resume_template: T#%d exiting after signaling wake up"
" for T#%d\n",
gtid, target_gtid));
}
template <bool C, bool S>
void __kmp_resume_32(int target_gtid, kmp_flag_32<C, S> *flag) {
__kmp_resume_template(target_gtid, flag);
}
template <bool C, bool S>
void __kmp_resume_64(int target_gtid, kmp_flag_64<C, S> *flag) {
__kmp_resume_template(target_gtid, flag);
}
template <bool C, bool S>
void __kmp_atomic_resume_64(int target_gtid, kmp_atomic_flag_64<C, S> *flag) {
__kmp_resume_template(target_gtid, flag);
}
void __kmp_resume_oncore(int target_gtid, kmp_flag_oncore *flag) {
__kmp_resume_template(target_gtid, flag);
}
template void __kmp_resume_32<false, true>(int, kmp_flag_32<false, true> *);
template void __kmp_resume_32<false, false>(int, kmp_flag_32<false, false> *);
template void __kmp_resume_64<false, true>(int, kmp_flag_64<false, true> *);
template void
__kmp_atomic_resume_64<false, true>(int, kmp_atomic_flag_64<false, true> *);
#if KMP_USE_MONITOR
void __kmp_resume_monitor() {
KMP_TIME_DEVELOPER_PARTITIONED_BLOCK(USER_resume);
int status;
#ifdef KMP_DEBUG
int gtid = TCR_4(__kmp_init_gtid) ? __kmp_get_gtid() : -1;
KF_TRACE(30, ("__kmp_resume_monitor: T#%d wants to wakeup T#%d enter\n", gtid,
KMP_GTID_MONITOR));
KMP_DEBUG_ASSERT(gtid != KMP_GTID_MONITOR);
#endif
status = pthread_mutex_lock(&__kmp_wait_mx.m_mutex);
KMP_CHECK_SYSFAIL("pthread_mutex_lock", status);
#ifdef DEBUG_SUSPEND
{
char buffer[128];
__kmp_print_cond(buffer, &__kmp_wait_cv.c_cond);
__kmp_printf("__kmp_resume_monitor: T#%d resuming T#%d: %s\n", gtid,
KMP_GTID_MONITOR, buffer);
}
#endif
status = pthread_cond_signal(&__kmp_wait_cv.c_cond);
KMP_CHECK_SYSFAIL("pthread_cond_signal", status);
status = pthread_mutex_unlock(&__kmp_wait_mx.m_mutex);
KMP_CHECK_SYSFAIL("pthread_mutex_unlock", status);
KF_TRACE(30, ("__kmp_resume_monitor: T#%d exiting after signaling wake up"
" for T#%d\n",
gtid, KMP_GTID_MONITOR));
}
#endif
void __kmp_yield() { sched_yield(); }
void __kmp_gtid_set_specific(int gtid) {
if (__kmp_init_gtid) {
int status;
status = pthread_setspecific(__kmp_gtid_threadprivate_key,
(void *)(intptr_t)(gtid + 1));
KMP_CHECK_SYSFAIL("pthread_setspecific", status);
} else {
KA_TRACE(50, ("__kmp_gtid_set_specific: runtime shutdown, returning\n"));
}
}
int __kmp_gtid_get_specific() {
int gtid;
if (!__kmp_init_gtid) {
KA_TRACE(50, ("__kmp_gtid_get_specific: runtime shutdown, returning "
"KMP_GTID_SHUTDOWN\n"));
return KMP_GTID_SHUTDOWN;
}
gtid = (int)(size_t)pthread_getspecific(__kmp_gtid_threadprivate_key);
if (gtid == 0) {
gtid = KMP_GTID_DNE;
} else {
gtid--;
}
KA_TRACE(50, ("__kmp_gtid_get_specific: key:%d gtid:%d\n",
__kmp_gtid_threadprivate_key, gtid));
return gtid;
}
double __kmp_read_cpu_time(void) {
struct tms buffer;
times(&buffer);
return (double)(buffer.tms_utime + buffer.tms_cutime) /
(double)CLOCKS_PER_SEC;
}
int __kmp_read_system_info(struct kmp_sys_info *info) {
int status;
struct rusage r_usage;
memset(info, 0, sizeof(*info));
status = getrusage(RUSAGE_SELF, &r_usage);
KMP_CHECK_SYSFAIL_ERRNO("getrusage", status);
#if !KMP_OS_WASI
info->maxrss = r_usage.ru_maxrss;
info->minflt = r_usage.ru_minflt;
info->majflt = r_usage.ru_majflt;
info->nswap = r_usage.ru_nswap;
info->inblock = r_usage.ru_inblock;
info->oublock = r_usage.ru_oublock;
info->nvcsw = r_usage.ru_nvcsw;
info->nivcsw = r_usage.ru_nivcsw;
#endif
return (status != 0);
}
void __kmp_read_system_time(double *delta) {
double t_ns;
struct timeval tval;
struct timespec stop;
int status;
status = gettimeofday(&tval, NULL);
KMP_CHECK_SYSFAIL_ERRNO("gettimeofday", status);
TIMEVAL_TO_TIMESPEC(&tval, &stop);
t_ns = (double)(TS2NS(stop) - TS2NS(__kmp_sys_timer_data.start));
*delta = (t_ns * 1e-9);
}
void __kmp_clear_system_time(void) {
struct timeval tval;
int status;
status = gettimeofday(&tval, NULL);
KMP_CHECK_SYSFAIL_ERRNO("gettimeofday", status);
TIMEVAL_TO_TIMESPEC(&tval, &__kmp_sys_timer_data.start);
}
static int __kmp_get_xproc(void) {
int r = 0;
#if KMP_OS_LINUX
__kmp_type_convert(sysconf(_SC_NPROCESSORS_CONF), &(r));
#elif KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD || KMP_OS_OPENBSD || \
KMP_OS_HURD || KMP_OS_SOLARIS || KMP_OS_WASI || KMP_OS_AIX
__kmp_type_convert(sysconf(_SC_NPROCESSORS_ONLN), &(r));
#elif KMP_OS_DARWIN
size_t len = sizeof(r);
sysctlbyname("hw.logicalcpu", &r, &len, NULL, 0);
#else
#error "Unknown or unsupported OS."
#endif
return r > 0 ? r : 2;
}
int __kmp_read_from_file(char const *path, char const *format, ...) {
int result;
va_list args;
va_start(args, format);
FILE *f = fopen(path, "rb");
if (f == NULL) {
va_end(args);
return 0;
}
result = vfscanf(f, format, args);
fclose(f);
va_end(args);
return result;
}
void __kmp_runtime_initialize(void) {
int status;
pthread_mutexattr_t mutex_attr;
pthread_condattr_t cond_attr;
if (__kmp_init_runtime) {
return;
}
#if (KMP_ARCH_X86 || KMP_ARCH_X86_64)
if (!__kmp_cpuinfo.initialized) {
__kmp_query_cpuid(&__kmp_cpuinfo);
}
#endif
__kmp_xproc = __kmp_get_xproc();
#if !KMP_32_BIT_ARCH
struct rlimit rlim;
status = getrlimit(RLIMIT_STACK, &rlim);
if (status == 0) {
__kmp_stksize = rlim.rlim_cur;
__kmp_check_stksize(&__kmp_stksize);
}
#endif
if (sysconf(_SC_THREADS)) {
__kmp_type_convert(sysconf(_SC_THREAD_THREADS_MAX), &(__kmp_sys_max_nth));
#ifdef __ve__
if (__kmp_sys_max_nth == -1) {
__kmp_sys_max_nth = KMP_MAX_NTH;
}
#else
if (__kmp_sys_max_nth == -1) {
__kmp_sys_max_nth = INT_MAX;
} else if (__kmp_sys_max_nth <= 1) {
__kmp_sys_max_nth = KMP_MAX_NTH;
}
#endif
__kmp_sys_min_stksize = sysconf(_SC_THREAD_STACK_MIN);
if (__kmp_sys_min_stksize <= 1) {
__kmp_sys_min_stksize = KMP_MIN_STKSIZE;
}
}
__kmp_tls_gtid_min = KMP_TLS_GTID_MIN;
status = pthread_key_create(&__kmp_gtid_threadprivate_key,
__kmp_internal_end_dest);
KMP_CHECK_SYSFAIL("pthread_key_create", status);
status = pthread_mutexattr_init(&mutex_attr);
KMP_CHECK_SYSFAIL("pthread_mutexattr_init", status);
status = pthread_mutex_init(&__kmp_wait_mx.m_mutex, &mutex_attr);
KMP_CHECK_SYSFAIL("pthread_mutex_init", status);
status = pthread_mutexattr_destroy(&mutex_attr);
KMP_CHECK_SYSFAIL("pthread_mutexattr_destroy", status);
status = pthread_condattr_init(&cond_attr);
KMP_CHECK_SYSFAIL("pthread_condattr_init", status);
status = pthread_cond_init(&__kmp_wait_cv.c_cond, &cond_attr);
KMP_CHECK_SYSFAIL("pthread_cond_init", status);
status = pthread_condattr_destroy(&cond_attr);
KMP_CHECK_SYSFAIL("pthread_condattr_destroy", status);
#if USE_ITT_BUILD
__kmp_itt_initialize();
#endif
__kmp_init_runtime = TRUE;
}
void __kmp_runtime_destroy(void) {
int status;
if (!__kmp_init_runtime) {
return;
}
#if USE_ITT_BUILD
__kmp_itt_destroy();
#endif
status = pthread_key_delete(__kmp_gtid_threadprivate_key);
KMP_CHECK_SYSFAIL("pthread_key_delete", status);
status = pthread_mutex_destroy(&__kmp_wait_mx.m_mutex);
if (status != 0 && status != EBUSY) {
KMP_SYSFAIL("pthread_mutex_destroy", status);
}
status = pthread_cond_destroy(&__kmp_wait_cv.c_cond);
if (status != 0 && status != EBUSY) {
KMP_SYSFAIL("pthread_cond_destroy", status);
}
#if KMP_AFFINITY_SUPPORTED
__kmp_affinity_uninitialize();
#endif
__kmp_init_runtime = FALSE;
}
void __kmp_thread_sleep(int millis) { sleep((millis + 500) / 1000); }
void __kmp_elapsed(double *t) {
int status;
#ifdef FIX_SGI_CLOCK
struct timespec ts;
status = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
KMP_CHECK_SYSFAIL_ERRNO("clock_gettime", status);
*t =
(double)ts.tv_nsec * (1.0 / (double)KMP_NSEC_PER_SEC) + (double)ts.tv_sec;
#else
struct timeval tv;
status = gettimeofday(&tv, NULL);
KMP_CHECK_SYSFAIL_ERRNO("gettimeofday", status);
*t =
(double)tv.tv_usec * (1.0 / (double)KMP_USEC_PER_SEC) + (double)tv.tv_sec;
#endif
}
void __kmp_elapsed_tick(double *t) { *t = 1 / (double)CLOCKS_PER_SEC; }
kmp_uint64 __kmp_now_nsec() {
struct timeval t;
gettimeofday(&t, NULL);
kmp_uint64 nsec = (kmp_uint64)KMP_NSEC_PER_SEC * (kmp_uint64)t.tv_sec +
(kmp_uint64)1000 * (kmp_uint64)t.tv_usec;
return nsec;
}
#if KMP_ARCH_X86 || KMP_ARCH_X86_64
void __kmp_initialize_system_tick() {
kmp_uint64 now, nsec2, diff;
kmp_uint64 delay = 1000000;
kmp_uint64 nsec = __kmp_now_nsec();
kmp_uint64 goal = __kmp_hardware_timestamp() + delay;
while ((now = __kmp_hardware_timestamp()) < goal)
;
nsec2 = __kmp_now_nsec();
diff = nsec2 - nsec;
if (diff > 0) {
double tpus = 1000.0 * (double)(delay + (now - goal)) / (double)diff;
if (tpus > 0.0) {
__kmp_ticks_per_msec = (kmp_uint64)(tpus * 1000.0);
__kmp_ticks_per_usec = (kmp_uint64)tpus;
}
}
}
#endif
space. */
int __kmp_is_address_mapped(void *addr) {
int found = 0;
int rc;
#if KMP_OS_LINUX || KMP_OS_HURD
address ranges mapped into the address space. */
char *name = __kmp_str_format("/proc/%d/maps", getpid());
FILE *file = NULL;
file = fopen(name, "r");
KMP_ASSERT(file != NULL);
for (;;) {
void *beginning = NULL;
void *ending = NULL;
char perms[5];
rc = fscanf(file, "%p-%p %4s %*[^\n]\n", &beginning, &ending, perms);
if (rc == EOF) {
break;
}
KMP_ASSERT(rc == 3 &&
KMP_STRLEN(perms) == 4);
if ((addr >= beginning) && (addr < ending)) {
perms[2] = 0;
if (strcmp(perms, "rw") == 0) {
found = 1;
}
break;
}
}
fclose(file);
KMP_INTERNAL_FREE(name);
#elif KMP_OS_FREEBSD
char *buf;
size_t lstsz;
int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
rc = sysctl(mib, 4, NULL, &lstsz, NULL, 0);
if (rc < 0)
return 0;
lstsz = lstsz * 4 / 3;
buf = reinterpret_cast<char *>(KMP_INTERNAL_MALLOC(lstsz));
rc = sysctl(mib, 4, buf, &lstsz, NULL, 0);
if (rc < 0) {
KMP_INTERNAL_FREE(buf);
return 0;
}
char *lw = buf;
char *up = buf + lstsz;
while (lw < up) {
struct kinfo_vmentry *cur = reinterpret_cast<struct kinfo_vmentry *>(lw);
size_t cursz = cur->kve_structsize;
if (cursz == 0)
break;
void *start = reinterpret_cast<void *>(cur->kve_start);
void *end = reinterpret_cast<void *>(cur->kve_end);
if ((addr >= start) && (addr < end)) {
if ((cur->kve_protection & KVME_PROT_READ) != 0 &&
(cur->kve_protection & KVME_PROT_WRITE) != 0) {
found = 1;
break;
}
}
lw += cursz;
}
KMP_INTERNAL_FREE(buf);
#elif KMP_OS_DRAGONFLY
char err[_POSIX2_LINE_MAX];
kinfo_proc *proc;
vmspace sp;
vm_map *cur;
vm_map_entry entry, *c;
struct proc p;
kvm_t *fd;
uintptr_t uaddr;
int num;
fd = kvm_openfiles(nullptr, nullptr, nullptr, O_RDONLY, err);
if (!fd) {
return 0;
}
proc = kvm_getprocs(fd, KERN_PROC_PID, getpid(), &num);
if (kvm_read(fd, static_cast<uintptr_t>(proc->kp_paddr), &p, sizeof(p)) !=
sizeof(p) ||
kvm_read(fd, reinterpret_cast<uintptr_t>(p.p_vmspace), &sp, sizeof(sp)) !=
sizeof(sp)) {
kvm_close(fd);
return 0;
}
(void)rc;
cur = &sp.vm_map;
uaddr = reinterpret_cast<uintptr_t>(addr);
for (c = kvm_vm_map_entry_first(fd, cur, &entry); c;
c = kvm_vm_map_entry_next(fd, c, &entry)) {
if ((uaddr >= entry.ba.start) && (uaddr <= entry.ba.end)) {
if ((entry.protection & VM_PROT_READ) != 0 &&
(entry.protection & VM_PROT_WRITE) != 0) {
found = 1;
break;
}
}
}
kvm_close(fd);
#elif KMP_OS_SOLARIS
prmap_t *cur, *map;
void *buf;
uintptr_t uaddr;
ssize_t rd;
int err;
int file;
pid_t pid = getpid();
struct ps_prochandle *fd = Pgrab(pid, PGRAB_RDONLY, &err);
;
if (!fd) {
return 0;
}
char *name = __kmp_str_format("/proc/%d/map", pid);
size_t sz = (1 << 20);
file = open(name, O_RDONLY);
if (file == -1) {
KMP_INTERNAL_FREE(name);
return 0;
}
buf = KMP_INTERNAL_MALLOC(sz);
while (sz > 0 && (rd = pread(file, buf, sz, 0)) == sz) {
void *newbuf;
sz <<= 1;
newbuf = KMP_INTERNAL_REALLOC(buf, sz);
buf = newbuf;
}
map = reinterpret_cast<prmap_t *>(buf);
uaddr = reinterpret_cast<uintptr_t>(addr);
for (cur = map; rd > 0; cur++, rd = -sizeof(*map)) {
if ((uaddr >= cur->pr_vaddr) && (uaddr < cur->pr_vaddr)) {
if ((cur->pr_mflags & MA_READ) != 0 && (cur->pr_mflags & MA_WRITE) != 0) {
found = 1;
break;
}
}
}
KMP_INTERNAL_FREE(map);
close(file);
KMP_INTERNAL_FREE(name);
#elif KMP_OS_DARWIN
using vm interface. */
int buffer;
vm_size_t count;
rc = vm_read_overwrite(
mach_task_self(),
(vm_address_t)(addr),
1,
(vm_address_t)(&buffer),
&count
);
if (rc == 0) {
found = 1;
}
#elif KMP_OS_NETBSD
int mib[5];
mib[0] = CTL_VM;
mib[1] = VM_PROC;
mib[2] = VM_PROC_MAP;
mib[3] = getpid();
mib[4] = sizeof(struct kinfo_vmentry);
size_t size;
rc = sysctl(mib, __arraycount(mib), NULL, &size, NULL, 0);
KMP_ASSERT(!rc);
KMP_ASSERT(size);
size = size * 4 / 3;
struct kinfo_vmentry *kiv = (struct kinfo_vmentry *)KMP_INTERNAL_MALLOC(size);
KMP_ASSERT(kiv);
rc = sysctl(mib, __arraycount(mib), kiv, &size, NULL, 0);
KMP_ASSERT(!rc);
KMP_ASSERT(size);
for (size_t i = 0; i < size; i++) {
if (kiv[i].kve_start >= (uint64_t)addr &&
kiv[i].kve_end <= (uint64_t)addr) {
found = 1;
break;
}
}
KMP_INTERNAL_FREE(kiv);
#elif KMP_OS_OPENBSD
int mib[3];
mib[0] = CTL_KERN;
mib[1] = KERN_PROC_VMMAP;
mib[2] = getpid();
size_t size;
uint64_t end;
rc = sysctl(mib, 3, NULL, &size, NULL, 0);
KMP_ASSERT(!rc);
KMP_ASSERT(size);
end = size;
struct kinfo_vmentry kiv = {.kve_start = 0};
while ((rc = sysctl(mib, 3, &kiv, &size, NULL, 0)) == 0) {
KMP_ASSERT(size);
if (kiv.kve_end == end)
break;
if (kiv.kve_start >= (uint64_t)addr && kiv.kve_end <= (uint64_t)addr) {
found = 1;
break;
}
kiv.kve_start += 1;
}
#elif KMP_OS_WASI
found = (int)addr < (__builtin_wasm_memory_size(0) * PAGESIZE);
#elif KMP_OS_AIX
uint32_t loadQueryBufSize = 4096u;
char *loadQueryBuf;
for (;;) {
loadQueryBuf = (char *)KMP_INTERNAL_MALLOC(loadQueryBufSize);
if (loadQueryBuf == NULL) {
return 0;
}
rc = loadquery(L_GETXINFO | L_IGNOREUNLOAD, loadQueryBuf, loadQueryBufSize);
if (rc < 0) {
KMP_INTERNAL_FREE(loadQueryBuf);
if (errno != ENOMEM) {
return 0;
}
loadQueryBufSize <<= 1;
continue;
}
break;
}
struct ld_xinfo *curLdInfo = (struct ld_xinfo *)loadQueryBuf;
for (;;) {
uintptr_t curDataStart = (uintptr_t)curLdInfo->ldinfo_dataorg;
uintptr_t curDataEnd = curDataStart + curLdInfo->ldinfo_datasize;
if (curDataStart <= (uintptr_t)addr && (uintptr_t)addr < curDataEnd) {
found = 1;
break;
}
if (curLdInfo->ldinfo_next == 0u) {
break;
}
curLdInfo = (struct ld_xinfo *)((char *)curLdInfo + curLdInfo->ldinfo_next);
}
KMP_INTERNAL_FREE(loadQueryBuf);
#else
#error "Unknown or unsupported OS"
#endif
return found;
}
#ifdef USE_LOAD_BALANCE
#if KMP_OS_DARWIN || KMP_OS_DRAGONFLY || KMP_OS_FREEBSD || KMP_OS_NETBSD || \
KMP_OS_OPENBSD || KMP_OS_SOLARIS
int __kmp_get_load_balance(int max) {
double averages[3];
int ret_avg = 0;
int res = getloadavg(averages, 3);
if (__kmp_load_balance_interval < 180 && (res >= 1)) {
ret_avg = (int)averages[0];
} else if ((__kmp_load_balance_interval >= 180 &&
__kmp_load_balance_interval < 600) &&
(res >= 2)) {
ret_avg = (int)averages[1];
} else if ((__kmp_load_balance_interval >= 600) && (res == 3)) {
ret_avg = (int)averages[2];
} else {
return -1;
}
return ret_avg;
}
#elif KMP_OS_AIX
int __kmp_get_load_balance(int max) {
static int glb_running_threads = 0;
static double glb_call_time = 0;
int running_threads = 0;
double call_time = 0.0;
__kmp_elapsed(&call_time);
if (glb_call_time &&
(call_time - glb_call_time < __kmp_load_balance_interval))
return glb_running_threads;
glb_call_time = call_time;
if (max <= 0) {
max = INT_MAX;
}
int logical_cpus = perfstat_cpu(NULL, NULL, sizeof(perfstat_cpu_t), 0);
if (logical_cpus <= 0) {
glb_call_time = -1;
return -1;
}
perfstat_cpu_t *cpu_stat = (perfstat_cpu_t *)KMP_INTERNAL_MALLOC(
logical_cpus * sizeof(perfstat_cpu_t));
if (cpu_stat == NULL) {
glb_call_time = -1;
return -1;
}
perfstat_id_t first_cpu_name;
strcpy(first_cpu_name.name, FIRST_CPU);
int rc = perfstat_cpu(&first_cpu_name, cpu_stat, sizeof(perfstat_cpu_t),
logical_cpus);
KMP_DEBUG_ASSERT(rc == logical_cpus);
if (rc <= 0) {
KMP_INTERNAL_FREE(cpu_stat);
glb_call_time = -1;
return -1;
}
for (int i = 0; i < logical_cpus; ++i) {
running_threads += cpu_stat[i].runque;
if (running_threads >= max)
break;
}
KMP_DEBUG_ASSERT(running_threads > 0);
if (running_threads <= 0)
running_threads = 1;
KMP_INTERNAL_FREE(cpu_stat);
glb_running_threads = running_threads;
return running_threads;
}
#else
int __kmp_get_load_balance(int max) {
static int permanent_error = 0;
static int glb_running_threads = 0;
static double glb_call_time = 0;
int running_threads = 0;
DIR *proc_dir = NULL;
struct dirent *proc_entry = NULL;
kmp_str_buf_t task_path;
DIR *task_dir = NULL;
struct dirent *task_entry = NULL;
int task_path_fixed_len;
kmp_str_buf_t stat_path;
int stat_file = -1;
int stat_path_fixed_len;
#ifdef KMP_DEBUG
int total_processes = 0;
#endif
double call_time = 0.0;
__kmp_str_buf_init(&task_path);
__kmp_str_buf_init(&stat_path);
__kmp_elapsed(&call_time);
if (glb_call_time &&
(call_time - glb_call_time < __kmp_load_balance_interval)) {
running_threads = glb_running_threads;
goto finish;
}
glb_call_time = call_time;
if (permanent_error) {
running_threads = -1;
goto finish;
}
if (max <= 0) {
max = INT_MAX;
}
proc_dir = opendir("/proc");
if (proc_dir == NULL) {
running_threads = -1;
permanent_error = 1;
goto finish;
}
__kmp_str_buf_cat(&task_path, "/proc/", 6);
task_path_fixed_len = task_path.used;
proc_entry = readdir(proc_dir);
while (proc_entry != NULL) {
if (proc_entry->d_type == DT_DIR && isdigit(proc_entry->d_name[0])) {
#ifdef KMP_DEBUG
++total_processes;
#endif
KMP_DEBUG_ASSERT(total_processes != 1 ||
strcmp(proc_entry->d_name, "1") == 0);
task_path.used = task_path_fixed_len;
__kmp_str_buf_cat(&task_path, proc_entry->d_name,
KMP_STRLEN(proc_entry->d_name));
__kmp_str_buf_cat(&task_path, "/task", 5);
task_dir = opendir(task_path.str);
if (task_dir == NULL) {
if (strcmp(proc_entry->d_name, "1") == 0) {
running_threads = -1;
permanent_error = 1;
goto finish;
}
} else {
__kmp_str_buf_clear(&stat_path);
__kmp_str_buf_cat(&stat_path, task_path.str, task_path.used);
__kmp_str_buf_cat(&stat_path, "/", 1);
stat_path_fixed_len = stat_path.used;
task_entry = readdir(task_dir);
while (task_entry != NULL) {
if (proc_entry->d_type == DT_DIR && isdigit(task_entry->d_name[0])) {
stat_path.used =
stat_path_fixed_len;
__kmp_str_buf_cat(&stat_path, task_entry->d_name,
KMP_STRLEN(task_entry->d_name));
__kmp_str_buf_cat(&stat_path, "/stat", 5);
stat_file = open(stat_path.str, O_RDONLY);
if (stat_file == -1) {
} else {
24285 (program) S ...
It is a single line (if program name does not include funny
symbols). First number is a thread id, then name of executable
file name in paretheses, then state of the thread. We need just
thread state.
Good news: Length of program name is 15 characters max. Longer
names are truncated.
Thus, we need rather short buffer: 15 chars for program name +
2 parenthesis, + 3 spaces + ~7 digits of pid = 37.
Bad news: Program name may contain special symbols like space,
closing parenthesis, or even new line. This makes parsing
"stat" file not 100 % reliable. In case of fanny program names
parsing may fail (report incorrect thread state).
Parsing "status" file looks more promissing (due to different
file structure and escaping special symbols) but reading and
parsing of "status" file works slower.
-- ln
*/
char buffer[65];
ssize_t len;
len = read(stat_file, buffer, sizeof(buffer) - 1);
if (len >= 0) {
buffer[len] = 0;
char *close_parent = strstr(buffer, ") ");
if (close_parent != NULL) {
char state = *(close_parent + 2);
if (state == 'R') {
++running_threads;
if (running_threads >= max) {
goto finish;
}
}
}
}
close(stat_file);
stat_file = -1;
}
}
task_entry = readdir(task_dir);
}
closedir(task_dir);
task_dir = NULL;
}
}
proc_entry = readdir(proc_dir);
}
KMP_DEBUG_ASSERT(running_threads > 0);
if (running_threads <= 0) {
running_threads = 1;
}
finish:
if (proc_dir != NULL) {
closedir(proc_dir);
}
__kmp_str_buf_free(&task_path);
if (task_dir != NULL) {
closedir(task_dir);
}
__kmp_str_buf_free(&stat_path);
if (stat_file != -1) {
close(stat_file);
}
glb_running_threads = running_threads;
return running_threads;
}
#endif
#endif
#if !(KMP_ARCH_X86 || KMP_ARCH_X86_64 || KMP_MIC || \
((KMP_OS_LINUX || KMP_OS_DARWIN) && KMP_ARCH_AARCH64) || \
KMP_ARCH_PPC64 || KMP_ARCH_RISCV64 || KMP_ARCH_LOONGARCH64 || \
KMP_ARCH_ARM || KMP_ARCH_VE || KMP_ARCH_S390X || KMP_ARCH_PPC_XCOFF || \
KMP_ARCH_AARCH64_32)
typedef void (*microtask_t0)(int *, int *);
typedef void (*microtask_t1)(int *, int *, void *);
typedef void (*microtask_t2)(int *, int *, void *, void *);
typedef void (*microtask_t3)(int *, int *, void *, void *, void *);
typedef void (*microtask_t4)(int *, int *, void *, void *, void *, void *);
typedef void (*microtask_t5)(int *, int *, void *, void *, void *, void *,
void *);
typedef void (*microtask_t6)(int *, int *, void *, void *, void *, void *,
void *, void *);
typedef void (*microtask_t7)(int *, int *, void *, void *, void *, void *,
void *, void *, void *);
typedef void (*microtask_t8)(int *, int *, void *, void *, void *, void *,
void *, void *, void *, void *);
typedef void (*microtask_t9)(int *, int *, void *, void *, void *, void *,
void *, void *, void *, void *, void *);
typedef void (*microtask_t10)(int *, int *, void *, void *, void *, void *,
void *, void *, void *, void *, void *, void *);
typedef void (*microtask_t11)(int *, int *, void *, void *, void *, void *,
void *, void *, void *, void *, void *, void *,
void *);
typedef void (*microtask_t12)(int *, int *, void *, void *, void *, void *,
void *, void *, void *, void *, void *, void *,
void *, void *);
typedef void (*microtask_t13)(int *, int *, void *, void *, void *, void *,
void *, void *, void *, void *, void *, void *,
void *, void *, void *);
typedef void (*microtask_t14)(int *, int *, void *, void *, void *, void *,
void *, void *, void *, void *, void *, void *,
void *, void *, void *, void *);
typedef void (*microtask_t15)(int *, int *, void *, void *, void *, void *,
void *, void *, void *, void *, void *, void *,
void *, void *, void *, void *, void *);
int __kmp_invoke_microtask(microtask_t pkfn, int gtid, int tid, int argc,
void *p_argv[]
#if OMPT_SUPPORT
,
void **exit_frame_ptr
#endif
) {
#if OMPT_SUPPORT
*exit_frame_ptr = OMPT_GET_FRAME_ADDRESS(0);
#endif
switch (argc) {
default:
fprintf(stderr, "Too many args to microtask: %d!\n", argc);
fflush(stderr);
exit(-1);
case 0:
(*(microtask_t0)pkfn)(>id, &tid);
break;
case 1:
(*(microtask_t1)pkfn)(>id, &tid, p_argv[0]);
break;
case 2:
(*(microtask_t2)pkfn)(>id, &tid, p_argv[0], p_argv[1]);
break;
case 3:
(*(microtask_t3)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2]);
break;
case 4:
(*(microtask_t4)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
p_argv[3]);
break;
case 5:
(*(microtask_t5)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
p_argv[3], p_argv[4]);
break;
case 6:
(*(microtask_t6)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
p_argv[3], p_argv[4], p_argv[5]);
break;
case 7:
(*(microtask_t7)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
p_argv[3], p_argv[4], p_argv[5], p_argv[6]);
break;
case 8:
(*(microtask_t8)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
p_argv[3], p_argv[4], p_argv[5], p_argv[6],
p_argv[7]);
break;
case 9:
(*(microtask_t9)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
p_argv[3], p_argv[4], p_argv[5], p_argv[6], p_argv[7],
p_argv[8]);
break;
case 10:
(*(microtask_t10)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
p_argv[3], p_argv[4], p_argv[5], p_argv[6],
p_argv[7], p_argv[8], p_argv[9]);
break;
case 11:
(*(microtask_t11)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
p_argv[3], p_argv[4], p_argv[5], p_argv[6],
p_argv[7], p_argv[8], p_argv[9], p_argv[10]);
break;
case 12:
(*(microtask_t12)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
p_argv[3], p_argv[4], p_argv[5], p_argv[6],
p_argv[7], p_argv[8], p_argv[9], p_argv[10],
p_argv[11]);
break;
case 13:
(*(microtask_t13)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
p_argv[3], p_argv[4], p_argv[5], p_argv[6],
p_argv[7], p_argv[8], p_argv[9], p_argv[10],
p_argv[11], p_argv[12]);
break;
case 14:
(*(microtask_t14)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
p_argv[3], p_argv[4], p_argv[5], p_argv[6],
p_argv[7], p_argv[8], p_argv[9], p_argv[10],
p_argv[11], p_argv[12], p_argv[13]);
break;
case 15:
(*(microtask_t15)pkfn)(>id, &tid, p_argv[0], p_argv[1], p_argv[2],
p_argv[3], p_argv[4], p_argv[5], p_argv[6],
p_argv[7], p_argv[8], p_argv[9], p_argv[10],
p_argv[11], p_argv[12], p_argv[13], p_argv[14]);
break;
}
return 1;
}
#endif
#if KMP_OS_LINUX
namespace {
pthread_cond_t hidden_helper_threads_initz_cond_var;
pthread_mutex_t hidden_helper_threads_initz_lock;
volatile int hidden_helper_initz_signaled = FALSE;
pthread_cond_t hidden_helper_threads_deinitz_cond_var;
pthread_mutex_t hidden_helper_threads_deinitz_lock;
volatile int hidden_helper_deinitz_signaled = FALSE;
pthread_cond_t hidden_helper_main_thread_cond_var;
pthread_mutex_t hidden_helper_main_thread_lock;
volatile int hidden_helper_main_thread_signaled = FALSE;
sem_t hidden_helper_task_sem;
}
void __kmp_hidden_helper_worker_thread_wait() {
int status = sem_wait(&hidden_helper_task_sem);
KMP_CHECK_SYSFAIL("sem_wait", status);
}
void __kmp_do_initialize_hidden_helper_threads() {
int status =
pthread_cond_init(&hidden_helper_threads_initz_cond_var, nullptr);
KMP_CHECK_SYSFAIL("pthread_cond_init", status);
status = pthread_cond_init(&hidden_helper_threads_deinitz_cond_var, nullptr);
KMP_CHECK_SYSFAIL("pthread_cond_init", status);
status = pthread_cond_init(&hidden_helper_main_thread_cond_var, nullptr);
KMP_CHECK_SYSFAIL("pthread_cond_init", status);
status = pthread_mutex_init(&hidden_helper_threads_initz_lock, nullptr);
KMP_CHECK_SYSFAIL("pthread_mutex_init", status);
status = pthread_mutex_init(&hidden_helper_threads_deinitz_lock, nullptr);
KMP_CHECK_SYSFAIL("pthread_mutex_init", status);
status = pthread_mutex_init(&hidden_helper_main_thread_lock, nullptr);
KMP_CHECK_SYSFAIL("pthread_mutex_init", status);
status = sem_init(&hidden_helper_task_sem, 0, 0);
KMP_CHECK_SYSFAIL("sem_init", status);
pthread_t handle;
status = pthread_create(
&handle, nullptr,
[](void *) -> void * {
__kmp_hidden_helper_threads_initz_routine();
return nullptr;
},
nullptr);
KMP_CHECK_SYSFAIL("pthread_create", status);
}
void __kmp_hidden_helper_threads_initz_wait() {
int status = pthread_mutex_lock(&hidden_helper_threads_initz_lock);
KMP_CHECK_SYSFAIL("pthread_mutex_lock", status);
if (!TCR_4(hidden_helper_initz_signaled)) {
status = pthread_cond_wait(&hidden_helper_threads_initz_cond_var,
&hidden_helper_threads_initz_lock);
KMP_CHECK_SYSFAIL("pthread_cond_wait", status);
}
status = pthread_mutex_unlock(&hidden_helper_threads_initz_lock);
KMP_CHECK_SYSFAIL("pthread_mutex_unlock", status);
}
void __kmp_hidden_helper_initz_release() {
int status = pthread_mutex_lock(&hidden_helper_threads_initz_lock);
KMP_CHECK_SYSFAIL("pthread_mutex_lock", status);
status = pthread_cond_signal(&hidden_helper_threads_initz_cond_var);
KMP_CHECK_SYSFAIL("pthread_cond_wait", status);
TCW_SYNC_4(hidden_helper_initz_signaled, TRUE);
status = pthread_mutex_unlock(&hidden_helper_threads_initz_lock);
KMP_CHECK_SYSFAIL("pthread_mutex_unlock", status);
}
void __kmp_hidden_helper_main_thread_wait() {
int status = pthread_mutex_lock(&hidden_helper_main_thread_lock);
KMP_CHECK_SYSFAIL("pthread_mutex_lock", status);
if (!TCR_4(hidden_helper_main_thread_signaled)) {
status = pthread_cond_wait(&hidden_helper_main_thread_cond_var,
&hidden_helper_main_thread_lock);
KMP_CHECK_SYSFAIL("pthread_cond_wait", status);
}
status = pthread_mutex_unlock(&hidden_helper_main_thread_lock);
KMP_CHECK_SYSFAIL("pthread_mutex_unlock", status);
}
void __kmp_hidden_helper_main_thread_release() {
int status = pthread_mutex_lock(&hidden_helper_main_thread_lock);
KMP_CHECK_SYSFAIL("pthread_mutex_lock", status);
status = pthread_cond_signal(&hidden_helper_main_thread_cond_var);
KMP_CHECK_SYSFAIL("pthread_cond_signal", status);
TCW_SYNC_4(hidden_helper_main_thread_signaled, TRUE);
status = pthread_mutex_unlock(&hidden_helper_main_thread_lock);
KMP_CHECK_SYSFAIL("pthread_mutex_unlock", status);
}
void __kmp_hidden_helper_worker_thread_signal() {
int status = sem_post(&hidden_helper_task_sem);
KMP_CHECK_SYSFAIL("sem_post", status);
}
void __kmp_hidden_helper_threads_deinitz_wait() {
int status = pthread_mutex_lock(&hidden_helper_threads_deinitz_lock);
KMP_CHECK_SYSFAIL("pthread_mutex_lock", status);
if (!TCR_4(hidden_helper_deinitz_signaled)) {
status = pthread_cond_wait(&hidden_helper_threads_deinitz_cond_var,
&hidden_helper_threads_deinitz_lock);
KMP_CHECK_SYSFAIL("pthread_cond_wait", status);
}
status = pthread_mutex_unlock(&hidden_helper_threads_deinitz_lock);
KMP_CHECK_SYSFAIL("pthread_mutex_unlock", status);
}
void __kmp_hidden_helper_threads_deinitz_release() {
int status = pthread_mutex_lock(&hidden_helper_threads_deinitz_lock);
KMP_CHECK_SYSFAIL("pthread_mutex_lock", status);
status = pthread_cond_signal(&hidden_helper_threads_deinitz_cond_var);
KMP_CHECK_SYSFAIL("pthread_cond_wait", status);
TCW_SYNC_4(hidden_helper_deinitz_signaled, TRUE);
status = pthread_mutex_unlock(&hidden_helper_threads_deinitz_lock);
KMP_CHECK_SYSFAIL("pthread_mutex_unlock", status);
}
#else
void __kmp_hidden_helper_worker_thread_wait() {
KMP_ASSERT(0 && "Hidden helper task is not supported on this OS");
}
void __kmp_do_initialize_hidden_helper_threads() {
KMP_ASSERT(0 && "Hidden helper task is not supported on this OS");
}
void __kmp_hidden_helper_threads_initz_wait() {
KMP_ASSERT(0 && "Hidden helper task is not supported on this OS");
}
void __kmp_hidden_helper_initz_release() {
KMP_ASSERT(0 && "Hidden helper task is not supported on this OS");
}
void __kmp_hidden_helper_main_thread_wait() {
KMP_ASSERT(0 && "Hidden helper task is not supported on this OS");
}
void __kmp_hidden_helper_main_thread_release() {
KMP_ASSERT(0 && "Hidden helper task is not supported on this OS");
}
void __kmp_hidden_helper_worker_thread_signal() {
KMP_ASSERT(0 && "Hidden helper task is not supported on this OS");
}
void __kmp_hidden_helper_threads_deinitz_wait() {
KMP_ASSERT(0 && "Hidden helper task is not supported on this OS");
}
void __kmp_hidden_helper_threads_deinitz_release() {
KMP_ASSERT(0 && "Hidden helper task is not supported on this OS");
}
#endif
bool __kmp_detect_shm() {
DIR *dir = opendir("/dev/shm");
if (dir) {
closedir(dir);
return true;
} else if (ENOENT == errno) {
return false;
} else {
return false;
}
}
bool __kmp_detect_tmp() {
DIR *dir = opendir("/tmp");
if (dir) {
closedir(dir);
return true;
} else if (ENOENT == errno) {
return false;
} else {
return false;
}
}