diff options
Diffstat (limited to 'erts/lib_src')
-rw-r--r-- | erts/lib_src/common/erl_misc_utils.c | 19 | ||||
-rw-r--r-- | erts/lib_src/common/erl_printf.c | 37 | ||||
-rw-r--r-- | erts/lib_src/common/ethr_aux.c | 68 | ||||
-rw-r--r-- | erts/lib_src/pthread/ethr_event.c | 74 | ||||
-rw-r--r-- | erts/lib_src/pthread/ethread.c | 27 | ||||
-rw-r--r-- | erts/lib_src/win/ethread.c | 27 |
6 files changed, 199 insertions, 53 deletions
diff --git a/erts/lib_src/common/erl_misc_utils.c b/erts/lib_src/common/erl_misc_utils.c index 8186463b9c..55fac13e95 100644 --- a/erts/lib_src/common/erl_misc_utils.c +++ b/erts/lib_src/common/erl_misc_utils.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2016. All Rights Reserved. + * Copyright Ericsson AB 2006-2017. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -842,7 +842,7 @@ read_topology(erts_cpu_info_t *cpuinfo) cpuinfo->topology[ix].logical = -1; } - ix = -1; + ix = 0; if (realpath(ERTS_SYS_NODE_PATH, npath)) { ndir = opendir(npath); @@ -886,6 +886,7 @@ read_topology(erts_cpu_info_t *cpuinfo) cdir = NULL; break; } + if (sscanf(cde->d_name, "cpu%d", &cpu_id) == 1) { char buf[50]; /* Much more than enough for an integer */ int processor_id, core_id; @@ -906,23 +907,33 @@ read_topology(erts_cpu_info_t *cpuinfo) if (sscanf(buf, "%d", &core_id) != 1) continue; + /* + * The number of CPUs that proc fs presents is greater + * then the number of CPUs configured in sysconf. + * This has been known to happen in docker. When this + * happens we refuse to give a CPU topology. + */ + if (ix >= cpuinfo->configured) + goto error; + /* * We now know node id, processor id, and * core id of the logical processor with * the cpu id 'cpu_id'. */ - ix++; cpuinfo->topology[ix].node = node_id; cpuinfo->topology[ix].processor = processor_id; cpuinfo->topology[ix].processor_node = -1; /* Fixed later */ cpuinfo->topology[ix].core = core_id; cpuinfo->topology[ix].thread = 0; /* we'll numerate later */ cpuinfo->topology[ix].logical = cpu_id; + ix++; + } } } while (got_nodes); - res = ix+1; + res = ix; if (!res || res < cpuinfo->online) res = 0; diff --git a/erts/lib_src/common/erl_printf.c b/erts/lib_src/common/erl_printf.c index b5e90dfeef..7781fc2196 100644 --- a/erts/lib_src/common/erl_printf.c +++ b/erts/lib_src/common/erl_printf.c @@ -165,8 +165,8 @@ write_f(void *vfp, char* buf, size_t len) return len; } -static int -write_fd(void *vfdp, char* buf, size_t len) +int +erts_write_fd(void *vfdp, char* buf, size_t len) { ssize_t size; size_t res = len; @@ -226,8 +226,8 @@ write_sn(void *vwsnap, char* buf, size_t len) return rv; } -static int -write_ds(void *vdsbufp, char* buf, size_t len) +int +erts_write_ds(void *vdsbufp, char* buf, size_t len) { erts_dsprintf_buf_t *dsbufp = (erts_dsprintf_buf_t *) vdsbufp; size_t need_len = len + 1; /* Also trailing '\0' */ @@ -301,7 +301,7 @@ erts_fdprintf(int fd, const char *format, ...) va_list arglist; va_start(arglist, format); errno = 0; - res = erts_printf_format(write_fd,(void *)&fd,(char *)format,arglist); + res = erts_printf_format(erts_write_fd,(void *)&fd,(char *)format,arglist); va_end(arglist); return res; } @@ -355,7 +355,7 @@ erts_dsprintf(erts_dsprintf_buf_t *dsbufp, const char *format, ...) return -EINVAL; va_start(arglist, format); errno = 0; - res = erts_printf_format(write_ds, (void *)dsbufp, (char *)format, arglist); + res = erts_printf_format(erts_write_ds, (void *)dsbufp, (char *)format, arglist); if (dsbufp->str) { if (res < 0) dsbufp->str[0] = '\0'; @@ -366,6 +366,20 @@ erts_dsprintf(erts_dsprintf_buf_t *dsbufp, const char *format, ...) return res; } +/* + * Callback printf + */ +int erts_cbprintf(fmtfn_t cb_fn, void* cb_arg, const char* format, ...) +{ + int res; + va_list arglist; + va_start(arglist, format); + errno = 0; + res = erts_printf_format(cb_fn, cb_arg, (char *)format, arglist); + va_end(arglist); + return res; +} + int erts_vprintf(const char *format, va_list arglist) { @@ -411,7 +425,7 @@ erts_vfdprintf(int fd, const char *format, va_list arglist) { int res; errno = 0; - res = erts_printf_format(write_fd,(void *)&fd,(char *)format,arglist); + res = erts_printf_format(erts_write_fd,(void *)&fd,(char *)format,arglist); return res; } @@ -456,7 +470,7 @@ erts_vdsprintf(erts_dsprintf_buf_t *dsbufp, const char *format, va_list arglist) if (!dsbufp) return -EINVAL; errno = 0; - res = erts_printf_format(write_ds, (void *)dsbufp, (char *)format, arglist); + res = erts_printf_format(erts_write_ds, (void *)dsbufp, (char *)format, arglist); if (dsbufp->str) { if (res < 0) dsbufp->str[0] = '\0'; @@ -465,3 +479,10 @@ erts_vdsprintf(erts_dsprintf_buf_t *dsbufp, const char *format, va_list arglist) } return res; } + +int +erts_vcbprintf(fmtfn_t cb_fn, void* cb_arg, const char *format, va_list arglist) +{ + errno = 0; + return erts_printf_format(cb_fn, cb_arg, (char *)format, arglist); +} diff --git a/erts/lib_src/common/ethr_aux.c b/erts/lib_src/common/ethr_aux.c index 420efd725f..7b156fe01a 100644 --- a/erts/lib_src/common/ethr_aux.c +++ b/erts/lib_src/common/ethr_aux.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2016. All Rights Reserved. + * Copyright Ericsson AB 2010-2017. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -68,6 +68,8 @@ size_t ethr_max_stack_size__; /* kilo words */ ethr_rwmutex xhndl_rwmtx; ethr_xhndl_list *xhndl_list; +static ethr_tsd_key ethr_stacklimit_key__; + static int main_threads; static int init_ts_event_alloc(void); @@ -220,7 +222,7 @@ ethr_init_common__(ethr_init_data *id) ethr_min_stack_size__ += ethr_pagesize__; #endif /* The system may think that we need more stack */ -#if defined(PTHREAD_STACK_MIN) +#if defined(ETHR_HAVE_USABLE_PTHREAD_STACK_MIN) if (ethr_min_stack_size__ < PTHREAD_STACK_MIN) ethr_min_stack_size__ = PTHREAD_STACK_MIN; #elif defined(_SC_THREAD_STACK_MIN) @@ -237,13 +239,11 @@ ethr_init_common__(ethr_init_data *id) #endif ethr_min_stack_size__ = ETHR_PAGE_ALIGN(ethr_min_stack_size__); - ethr_min_stack_size__ = ETHR_B2KW(ethr_min_stack_size__); - ethr_max_stack_size__ = 32*1024*1024; #if SIZEOF_VOID_P == 8 ethr_max_stack_size__ *= 2; #endif - ethr_max_stack_size__ = ETHR_B2KW(ethr_max_stack_size__); + ethr_max_stack_size__ = ETHR_PAGE_ALIGN(ethr_max_stack_size__); res = ethr_init_atomics(); if (res != 0) @@ -253,6 +253,10 @@ ethr_init_common__(ethr_init_data *id) if (res != 0) return res; + res = ethr_tsd_key_create(ðr_stacklimit_key__, "stacklimit"); + if (res != 0) + return res; + xhndl_list = NULL; return 0; @@ -313,6 +317,60 @@ ethr_late_init_common__(ethr_late_init_data *lid) return 0; } +/* + * Stack limit + */ + +void *ethr_get_stacklimit(void) +{ + return ethr_tsd_get(ethr_stacklimit_key__); +} + +int ethr_set_stacklimit(void *limit) +{ + void *prev = ethr_tsd_get(ethr_stacklimit_key__); + if (prev) + return EACCES; + if (!limit) + return EINVAL; + return ethr_tsd_set(ethr_stacklimit_key__, limit); +} + +/* internal stacklimit (thread creation) */ + +void +ethr_set_stacklimit__(char *prev_c, size_t stacksize) +{ + /* + * We *don't* want this function inlined, i.e., it is + * risky to call this function from another function + * in ethr_aux.c + */ + void *limit = NULL; + char c; + int res; + + if (stacksize) { + char *start; + if (&c > prev_c) { + start = (char *) ((((ethr_uint_t) prev_c) + / ethr_pagesize__) + * ethr_pagesize__); + limit = start + stacksize; + } + else { + start = (char *) (((((ethr_uint_t) prev_c) - 1) + / ethr_pagesize__ + 1) + * ethr_pagesize__); + limit = start - stacksize; + } + } + + res = ethr_tsd_set(ethr_stacklimit_key__, limit); + if (res != 0) + ethr_abort__(); +} + int ethr_install_exit_handler(void (*funcp)(void)) { diff --git a/erts/lib_src/pthread/ethr_event.c b/erts/lib_src/pthread/ethr_event.c index eef88d5002..464875570a 100644 --- a/erts/lib_src/pthread/ethr_event.c +++ b/erts/lib_src/pthread/ethr_event.c @@ -184,6 +184,8 @@ return_event_on: #include <errno.h> #include <string.h> +#include "erl_misc_utils.h" + #ifdef __DARWIN__ struct ethr_event_fdsets___ { @@ -346,12 +348,9 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) ethr_sint32_t val; int res, ulres; int until_yield = ETHR_YIELD_AFTER_BUSY_LOOPS; - ethr_sint64_t time = 0; /* SHUT UP annoying faulty warning... */ + ethr_sint64_t time = 0; #ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME - ethr_sint64_t start = 0; /* SHUT UP annoying faulty warning... */ -#endif -#ifdef ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC - struct timespec cond_timeout; + ethr_sint64_t timeout_time = 0; /* SHUT UP annoying faulty warning... */ #endif val = ethr_atomic32_read(&e->state); @@ -365,30 +364,27 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) if (timeout == 0) return ETIMEDOUT; else { - time = timeout; - switch (e->fd[0]) { - case ETHR_EVENT_INVALID_FD__: #ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME - start = ethr_get_monotonic_time(); + timeout_time = ethr_get_monotonic_time(); + timeout_time += timeout; #endif + switch (e->fd[0]) { + case ETHR_EVENT_INVALID_FD__: + time = timeout; setup_nonblocking_pipe(e); break; #ifdef ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC case ETHR_EVENT_COND_TIMEDWAIT__: - time += ethr_get_monotonic_time(); - cond_timeout.tv_sec = time / (1000*1000*1000); - cond_timeout.tv_nsec = time % (1000*1000*1000); + time = -1; if (spincount == 0) goto set_event_off_waiter; break; #endif default: + time = timeout; /* Already initialized pipe... */ if (spincount == 0) goto set_select_timeout; -#ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME - start = ethr_get_monotonic_time(); -#endif break; } } @@ -418,6 +414,9 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) || e->fd[0] == ETHR_EVENT_COND_TIMEDWAIT__ #endif ) { +#ifdef ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC + struct timespec cond_timeout; +#endif set_event_off_waiter: @@ -446,9 +445,35 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) #ifdef ETHR_HAVE_PTHREAD_COND_TIMEDWAIT_MONOTONIC if (timeout > 0) { + if (time != timeout_time) { + time = timeout_time; + +#if ERTS_USE_PREMATURE_TIMEOUT + { + ethr_sint64_t rtmo; + + rtmo = timeout_time - ethr_get_monotonic_time(); + if (rtmo <= 0) { + res = ETIMEDOUT; + break; + } + time = timeout_time; + time -= ERTS_PREMATURE_TIMEOUT(rtmo, 1000*1000*1000); + } +#endif + + cond_timeout.tv_sec = time / (1000*1000*1000); + cond_timeout.tv_nsec = time % (1000*1000*1000); + } res = pthread_cond_timedwait(&e->cnd, &e->mtx, &cond_timeout); - if (res == EINTR || res == ETIMEDOUT) + if (res == EINTR + || (res == ETIMEDOUT +#if ERTS_USE_PREMATURE_TIMEOUT + && time == timeout_time +#endif + )) { break; + } } else #endif @@ -477,7 +502,11 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) struct timeval select_timeout; #ifdef ETHR_HAVE_ETHR_GET_MONOTONIC_TIME - time -= ethr_get_monotonic_time() - start; +#if ERTS_USE_PREMATURE_TIMEOUT + restart_select: +#endif + + time = timeout_time - ethr_get_monotonic_time(); if (time <= 0) return ETIMEDOUT; #endif @@ -492,6 +521,11 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) */ time = ((time - 1) / 1000) + 1; +#if defined(ETHR_HAVE_ETHR_GET_MONOTONIC_TIME) \ + && ERTS_USE_PREMATURE_TIMEOUT + time -= ERTS_PREMATURE_TIMEOUT(time, 1000*1000); +#endif + select_timeout.tv_sec = time / (1000*1000); select_timeout.tv_usec = time % (1000*1000); @@ -559,7 +593,11 @@ wait__(ethr_event *e, int spincount, ethr_sint64_t timeout) val = ethr_atomic32_read(&e->state); if (val == ETHR_EVENT_ON__) goto return_event_on; - +#if defined(ETHR_HAVE_ETHR_GET_MONOTONIC_TIME) \ + && ERTS_USE_PREMATURE_TIMEOUT + if (res == ETIMEDOUT) + goto restart_select; /* Verify timeout */ +#endif } return res; diff --git a/erts/lib_src/pthread/ethread.c b/erts/lib_src/pthread/ethread.c index 29bffa7e12..b4b12fcd86 100644 --- a/erts/lib_src/pthread/ethread.c +++ b/erts/lib_src/pthread/ethread.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2016. All Rights Reserved. + * Copyright Ericsson AB 2010-2017. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -81,6 +81,7 @@ typedef struct { void *(*thr_func)(void *); void *arg; void *prep_func_res; + size_t stacksize; char *name; char name_buff[16]; } ethr_thr_wrap_data__; @@ -88,12 +89,15 @@ typedef struct { static void *thr_wrapper(void *vtwd) { ethr_sint32_t result; + char c; void *res; ethr_thr_wrap_data__ *twd = (ethr_thr_wrap_data__ *) vtwd; void *(*thr_func)(void *) = twd->thr_func; void *arg = twd->arg; ethr_ts_event *tsep = NULL; + ethr_set_stacklimit__(&c, twd->stacksize); + result = (ethr_sint32_t) ethr_make_ts_event__(&tsep); if (result == 0) { @@ -330,6 +334,7 @@ ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg, twd.tse = ethr_get_ts_event(); twd.thr_func = func; twd.arg = arg; + twd.stacksize = 0; if (opts && opts->name) { snprintf(twd.name_buff, 16, "%s", opts->name); @@ -354,18 +359,24 @@ ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg, #ifdef ETHR_DEBUG suggested_stack_size /= 2; /* Make sure we got margin */ #endif + stack_size = ETHR_KW2B(suggested_stack_size); + stack_size = ETHR_PAGE_ALIGN(stack_size); + stack_size += ethr_pagesize__; /* For possible system usage */ #ifdef ETHR_STACK_GUARD_SIZE /* The guard is at least on some platforms included in the stack size passed when creating threads */ - suggested_stack_size += ETHR_B2KW(ETHR_STACK_GUARD_SIZE); + stack_size += ETHR_STACK_GUARD_SIZE; #endif - if (suggested_stack_size < ethr_min_stack_size__) - stack_size = ETHR_KW2B(ethr_min_stack_size__); - else if (suggested_stack_size > ethr_max_stack_size__) - stack_size = ETHR_KW2B(ethr_max_stack_size__); - else - stack_size = ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size)); + if (stack_size < ethr_min_stack_size__) + stack_size = ethr_min_stack_size__; + else if (stack_size > ethr_max_stack_size__) + stack_size = ethr_max_stack_size__; (void) pthread_attr_setstacksize(&attr, stack_size); + twd.stacksize = stack_size; + twd.stacksize -= ethr_pagesize__; /* For possible system usage */ +#ifdef ETHR_STACK_GUARD_SIZE + twd.stacksize -= ETHR_STACK_GUARD_SIZE; +#endif } #ifdef ETHR_STACK_GUARD_SIZE diff --git a/erts/lib_src/win/ethread.c b/erts/lib_src/win/ethread.c index e0f19f7ba1..aa43e03435 100644 --- a/erts/lib_src/win/ethread.c +++ b/erts/lib_src/win/ethread.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2010-2016. All Rights Reserved. + * Copyright Ericsson AB 2010-2017. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -56,6 +56,7 @@ typedef struct { void *(*thr_func)(void *); void *arg; void *prep_func_res; + size_t stacksize; } ethr_thr_wrap_data__; #define ETHR_INVALID_TID_ID -1 @@ -94,6 +95,7 @@ static void thr_exit_cleanup(ethr_tid *tid, void *res) static unsigned __stdcall thr_wrapper(LPVOID vtwd) { + char c; ethr_tid my_tid; ethr_sint32_t result; void *res; @@ -102,6 +104,8 @@ static unsigned __stdcall thr_wrapper(LPVOID vtwd) void *arg = twd->arg; ethr_ts_event *tsep = NULL; + ethr_set_stacklimit__(&c, twd->stacksize); + result = (ethr_sint32_t) ethr_make_ts_event__(&tsep); if (result == 0) { @@ -199,6 +203,8 @@ ethr_init(ethr_init_data *id) if (!ethr_not_inited__) return EINVAL; + ethr_not_inited__ = 0; + #ifdef _WIN32_WINNT os_version.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); GetVersionEx(&os_version); @@ -234,8 +240,6 @@ ethr_init(ethr_init_data *id) if (erts_get_cpu_configured(ethr_cpu_info__) == 1) child_wait_spin_count = 0; - ethr_not_inited__ = 0; - return 0; error: @@ -305,18 +309,21 @@ ethr_thr_create(ethr_tid *tid, void * (*func)(void *), void *arg, tid->jdata->res = NULL; } + twd.stacksize = 0; + if (use_stack_size >= 0) { size_t suggested_stack_size = (size_t) use_stack_size; #ifdef ETHR_DEBUG suggested_stack_size /= 2; /* Make sure we got margin */ #endif - if (suggested_stack_size < ethr_min_stack_size__) - stack_size = (unsigned) ETHR_KW2B(ethr_min_stack_size__); - else if (suggested_stack_size > ethr_max_stack_size__) - stack_size = (unsigned) ETHR_KW2B(ethr_max_stack_size__); - else - stack_size = (unsigned) - ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size)); + stack_size = (unsigned) ETHR_PAGE_ALIGN(ETHR_KW2B(suggested_stack_size)); + + if (stack_size < (unsigned) ethr_min_stack_size__) + stack_size = (unsigned) ethr_min_stack_size__; + else if (stack_size > (unsigned) ethr_max_stack_size__) + stack_size = (unsigned) ethr_max_stack_size__; + + twd.stacksize = stack_size; } ethr_atomic32_init(&twd.result, -1); |