aboutsummaryrefslogtreecommitdiffstats
path: root/erts/lib_src
diff options
context:
space:
mode:
Diffstat (limited to 'erts/lib_src')
-rw-r--r--erts/lib_src/common/erl_misc_utils.c19
-rw-r--r--erts/lib_src/common/erl_printf.c37
-rw-r--r--erts/lib_src/common/ethr_aux.c68
-rw-r--r--erts/lib_src/pthread/ethr_event.c74
-rw-r--r--erts/lib_src/pthread/ethread.c27
-rw-r--r--erts/lib_src/win/ethread.c27
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(&ethr_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);