aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/sys/unix
diff options
context:
space:
mode:
Diffstat (limited to 'erts/emulator/sys/unix')
-rw-r--r--erts/emulator/sys/unix/erl_child_setup.c30
-rw-r--r--erts/emulator/sys/unix/erl_unix_sys.h26
-rw-r--r--erts/emulator/sys/unix/sys.c518
-rw-r--r--erts/emulator/sys/unix/sys_drivers.c386
-rw-r--r--erts/emulator/sys/unix/sys_env.c133
-rw-r--r--erts/emulator/sys/unix/sys_float.c10
-rw-r--r--erts/emulator/sys/unix/sys_time.c16
-rw-r--r--erts/emulator/sys/unix/sys_uds.c56
-rw-r--r--erts/emulator/sys/unix/sys_uds.h16
9 files changed, 426 insertions, 765 deletions
diff --git a/erts/emulator/sys/unix/erl_child_setup.c b/erts/emulator/sys/unix/erl_child_setup.c
index 69fc6c2879..129861ebd5 100644
--- a/erts/emulator/sys/unix/erl_child_setup.c
+++ b/erts/emulator/sys/unix/erl_child_setup.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. 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,8 @@
#include <stdio.h>
#include <stdarg.h>
#include <sys/wait.h>
+#include <sys/types.h>
+#include <sys/socket.h>
#define WANT_NONBLOCKING
@@ -131,6 +133,7 @@ static int sigchld_pipe[2];
static int
start_new_child(int pipes[])
{
+ struct sigaction sa;
int errln = -1;
int size, res, i, pos = 0;
char *buff, *o_buff;
@@ -141,6 +144,16 @@ start_new_child(int pipes[])
/* only child executes here */
+ /* Restore default handling of sigterm... */
+ sa.sa_handler = SIG_DFL;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+
+ if (sigaction(SIGTERM, &sa, 0) == -1) {
+ perror(NULL);
+ exit(1);
+ }
+
do {
res = read(pipes[0], (char*)&size, sizeof(size));
} while(res < 0 && (errno == EINTR || errno == ERRNO_BLOCK));
@@ -437,6 +450,21 @@ main(int argc, char *argv[])
exit(1);
}
+ /* Ignore SIGTERM.
+ Some container environments send SIGTERM to all processes
+ when terminating. We don't want erl_child_setup to terminate
+ in these cases as that will prevent beam from properly
+ cleaning up.
+ */
+ sa.sa_handler = SIG_IGN;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+
+ if (sigaction(SIGTERM, &sa, 0) == -1) {
+ perror(NULL);
+ exit(1);
+ }
+
forker_hash_init();
SET_CLOEXEC(uds_fd);
diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h
index b83837a7d2..ae7a3ea23e 100644
--- a/erts/emulator/sys/unix/erl_unix_sys.h
+++ b/erts/emulator/sys/unix/erl_unix_sys.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1997-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1997-2018. 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.
@@ -132,12 +132,8 @@
/* File descriptors are numbers anc consecutively allocated on Unix */
#define ERTS_SYS_CONTINOUS_FD_NUMBERS
-#ifndef ERTS_SMP
-# undef ERTS_POLL_NEED_ASYNC_INTERRUPT_SUPPORT
-# define ERTS_POLL_NEED_ASYNC_INTERRUPT_SUPPORT
-#endif
-typedef void *GETENV_STATE;
+void erts_sys_env_init(void);
/*
** For the erl_timer_sup module.
@@ -268,7 +264,7 @@ erts_os_monotonic_time(void)
ERTS_GLB_INLINE void
erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep)
{
- return (*erts_sys_time_data__.r.o.os_times)(mtimep, stimep);
+ (*erts_sys_time_data__.r.o.os_times)(mtimep, stimep);
}
#endif /* ERTS_OS_TIMES_INLINE_FUNC_PTR_CALL__ */
@@ -296,6 +292,8 @@ erts_sys_perf_counter()
/*
* Functions for measuring CPU time
+ *
+ * Note that gethrvtime is time per process and clock_gettime is per thread.
*/
#if (defined(HAVE_GETHRVTIME) || defined(HAVE_CLOCK_GETTIME_CPU_TIME))
@@ -304,15 +302,15 @@ typedef struct timespec SysTimespec;
#if defined(HAVE_GETHRVTIME)
#define sys_gethrvtime() gethrvtime()
-#define sys_get_proc_cputime(t,tp) (t) = sys_gethrvtime(), \
- (tp).tv_sec = (time_t)((t)/1000000000LL), \
- (tp).tv_nsec = (long)((t)%1000000000LL)
+#define sys_get_cputime(t,tp) (t) = sys_gethrvtime(), \
+ (tp).tv_sec = (time_t)((t)/1000000000LL), \
+ (tp).tv_nsec = (long)((t)%1000000000LL)
int sys_start_hrvtime(void);
int sys_stop_hrvtime(void);
#elif defined(HAVE_CLOCK_GETTIME_CPU_TIME)
#define sys_clock_gettime(cid,tp) clock_gettime((cid),&(tp))
-#define sys_get_proc_cputime(t,tp) sys_clock_gettime(CLOCK_PROCESS_CPUTIME_ID,(tp))
+#define sys_get_cputime(t,tp) sys_clock_gettime(CLOCK_THREAD_CPUTIME_ID,(tp))
#endif
#endif
@@ -358,9 +356,7 @@ extern void erts_sys_unix_later_init(void);
#ifdef NO_FPE_SIGNALS
#define erts_get_current_fp_exception() NULL
-#ifdef ERTS_SMP
#define erts_thread_init_fp_exception() do{}while(0)
-#endif
# define __ERTS_FP_CHECK_INIT(fpexnp) do {} while (0)
# define __ERTS_FP_ERROR(fpexnp, f, Action) if (!isfinite(f)) { Action; } else {}
# define __ERTS_FP_ERROR_THOROUGH(fpexnp, f, Action) __ERTS_FP_ERROR(fpexnp, f, Action)
@@ -373,9 +369,7 @@ extern void erts_sys_unix_later_init(void);
#else /* !NO_FPE_SIGNALS */
extern volatile unsigned long *erts_get_current_fp_exception(void);
-#ifdef ERTS_SMP
extern void erts_thread_init_fp_exception(void);
-#endif
# if (defined(__i386__) || defined(__x86_64__)) && defined(__GNUC__)
# define erts_fwait(fpexnp,f) \
__asm__ __volatile__("fwait" : "=m"(*(fpexnp)) : "m"(f))
@@ -442,10 +436,8 @@ void erts_sys_unblock_fpe(int);
/* Threads */
-#ifdef USE_THREADS
extern int init_async(int);
extern int exit_async(void);
-#endif
#define ERTS_EXIT_AFTER_DUMP _exit
diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c
index c1fa660cf9..4823e549ea 100644
--- a/erts/emulator/sys/unix/sys.c
+++ b/erts/emulator/sys/unix/sys.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. 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.
@@ -58,15 +58,10 @@
#define __DARWIN__ 1
#endif
-#ifdef USE_THREADS
#include "erl_threads.h"
-#endif
#include "erl_mseg.h"
-extern char **environ;
-erts_smp_rwmtx_t environ_rwmtx;
-
#define MAX_VSIZE 16 /* Max number of entries allowed in an I/O
* vector sock_sendv().
*/
@@ -79,7 +74,7 @@ erts_smp_rwmtx_t environ_rwmtx;
#include "erl_check_io.h"
#include "erl_cpu_topology.h"
-
+#include "erl_osenv.h"
extern int driver_interrupt(int, int);
extern void do_break(void);
@@ -94,19 +89,12 @@ extern void erts_sys_init_float(void);
static int debug_log = 0;
#endif
-#ifdef ERTS_SMP
-static erts_smp_atomic32_t have_prepared_crash_dump;
+static erts_atomic32_t have_prepared_crash_dump;
#define ERTS_PREPARED_CRASH_DUMP \
- ((int) erts_smp_atomic32_xchg_nob(&have_prepared_crash_dump, 1))
-#else
-static volatile int have_prepared_crash_dump;
-#define ERTS_PREPARED_CRASH_DUMP \
- (have_prepared_crash_dump++)
-#endif
+ ((int) erts_atomic32_xchg_nob(&have_prepared_crash_dump, 1))
-erts_smp_atomic_t sys_misc_mem_sz;
+erts_atomic_t sys_misc_mem_sz;
-#if defined(ERTS_SMP)
static void smp_sig_notify(int signum);
static int sig_notify_fds[2] = {-1, -1};
@@ -114,7 +102,6 @@ static int sig_notify_fds[2] = {-1, -1};
static int sig_suspend_fds[2] = {-1, -1};
#endif
-#endif
jmp_buf erts_sys_sigsegv_jmp;
@@ -128,38 +115,12 @@ static int max_files = -1;
/*
* a few variables used by the break handler
*/
-#ifdef ERTS_SMP
-erts_smp_atomic32_t erts_break_requested;
+erts_atomic32_t erts_break_requested;
#define ERTS_SET_BREAK_REQUESTED \
- erts_smp_atomic32_set_nob(&erts_break_requested, (erts_aint32_t) 1)
+ erts_atomic32_set_nob(&erts_break_requested, (erts_aint32_t) 1)
#define ERTS_UNSET_BREAK_REQUESTED \
- erts_smp_atomic32_set_nob(&erts_break_requested, (erts_aint32_t) 0)
-#else
-volatile int erts_break_requested = 0;
-#define ERTS_SET_BREAK_REQUESTED (erts_break_requested = 1)
-#define ERTS_UNSET_BREAK_REQUESTED (erts_break_requested = 0)
-#endif
+ erts_atomic32_set_nob(&erts_break_requested, (erts_aint32_t) 0)
-#ifndef ERTS_SMP
-static Eterm signalstate_sigterm[] = {
- am_sigint, /* 0 */
- am_sighup, /* 1 */
- am_sigquit, /* 2 */
- am_sigabrt, /* 3 */
- am_sigalrm, /* 4 */
- am_sigterm, /* 5 */
- am_sigusr1, /* 6 */
- am_sigusr2, /* 7 */
- am_sigchld, /* 8 */
- am_sigstop, /* 9 */
- am_sigtstp /* 10 */
-};
-
-volatile Uint erts_signal_state = 0;
-#define ERTS_SET_SIGNAL_STATE(S) (erts_signal_state |= signum_to_signalstate(S))
-#define ERTS_CLEAR_SIGNAL_STATE (erts_signal_state = 0)
-static ERTS_INLINE Uint signum_to_signalstate(int signum);
-#endif
/* set early so the break handler has access to initial mode */
static struct termios initial_tty_mode;
@@ -167,137 +128,6 @@ static int replace_intr = 0;
/* assume yes initially, ttsl_init will clear it */
int using_oldshell = 1;
-#ifdef ERTS_ENABLE_KERNEL_POLL
-
-int erts_use_kernel_poll = 0;
-
-struct {
- int (*select)(ErlDrvPort, ErlDrvEvent, int, int);
- int (*enif_select)(ErlNifEnv*, ErlNifEvent, enum ErlNifSelectFlags, void*, const ErlNifPid*, Eterm);
- int (*event)(ErlDrvPort, ErlDrvEvent, ErlDrvEventData);
- void (*check_io_as_interrupt)(void);
- void (*check_io_interrupt)(int);
- void (*check_io_interrupt_tmd)(int, ErtsMonotonicTime);
- void (*check_io)(int);
- Uint (*size)(void);
- Eterm (*info)(void *);
- int (*check_io_debug)(ErtsCheckIoDebugInfo *);
-} io_func = {0};
-
-
-int
-driver_select(ErlDrvPort port, ErlDrvEvent event, int mode, int on)
-{
- return (*io_func.select)(port, event, mode, on);
-}
-
-int
-driver_event(ErlDrvPort port, ErlDrvEvent event, ErlDrvEventData event_data)
-{
- return (*io_func.event)(port, event, event_data);
-}
-
-int enif_select(ErlNifEnv* env, ErlNifEvent event,
- enum ErlNifSelectFlags flags, void* obj, const ErlNifPid* pid, Eterm ref)
-{
- return (*io_func.enif_select)(env, event, flags, obj, pid, ref);
-}
-
-
-Eterm erts_check_io_info(void *p)
-{
- return (*io_func.info)(p);
-}
-
-int
-erts_check_io_debug(ErtsCheckIoDebugInfo *ip)
-{
- return (*io_func.check_io_debug)(ip);
-}
-
-
-static void
-init_check_io(void)
-{
- if (erts_use_kernel_poll) {
- io_func.select = driver_select_kp;
- io_func.enif_select = enif_select_kp;
- io_func.event = driver_event_kp;
-#ifdef ERTS_POLL_NEED_ASYNC_INTERRUPT_SUPPORT
- io_func.check_io_as_interrupt = erts_check_io_async_sig_interrupt_kp;
-#endif
- io_func.check_io_interrupt = erts_check_io_interrupt_kp;
- io_func.check_io_interrupt_tmd = erts_check_io_interrupt_timed_kp;
- io_func.check_io = erts_check_io_kp;
- io_func.size = erts_check_io_size_kp;
- io_func.info = erts_check_io_info_kp;
- io_func.check_io_debug = erts_check_io_debug_kp;
- erts_init_check_io_kp();
- max_files = erts_check_io_max_files_kp();
- }
- else {
- io_func.select = driver_select_nkp;
- io_func.enif_select = enif_select_nkp;
- io_func.event = driver_event_nkp;
-#ifdef ERTS_POLL_NEED_ASYNC_INTERRUPT_SUPPORT
- io_func.check_io_as_interrupt = erts_check_io_async_sig_interrupt_nkp;
-#endif
- io_func.check_io_interrupt = erts_check_io_interrupt_nkp;
- io_func.check_io_interrupt_tmd = erts_check_io_interrupt_timed_nkp;
- io_func.check_io = erts_check_io_nkp;
- io_func.size = erts_check_io_size_nkp;
- io_func.info = erts_check_io_info_nkp;
- io_func.check_io_debug = erts_check_io_debug_nkp;
- erts_init_check_io_nkp();
- max_files = erts_check_io_max_files_nkp();
- }
-}
-
-#ifdef ERTS_POLL_NEED_ASYNC_INTERRUPT_SUPPORT
-#define ERTS_CHK_IO_AS_INTR() (*io_func.check_io_as_interrupt)()
-#else
-#define ERTS_CHK_IO_AS_INTR() (*io_func.check_io_interrupt)(1)
-#endif
-#define ERTS_CHK_IO_INTR (*io_func.check_io_interrupt)
-#define ERTS_CHK_IO_INTR_TMD (*io_func.check_io_interrupt_tmd)
-#define ERTS_CHK_IO (*io_func.check_io)
-#define ERTS_CHK_IO_SZ (*io_func.size)
-
-#else /* !ERTS_ENABLE_KERNEL_POLL */
-
-static void
-init_check_io(void)
-{
- erts_init_check_io();
- max_files = erts_check_io_max_files();
-}
-
-#ifdef ERTS_POLL_NEED_ASYNC_INTERRUPT_SUPPORT
-#define ERTS_CHK_IO_AS_INTR() erts_check_io_async_sig_interrupt()
-#else
-#define ERTS_CHK_IO_AS_INTR() erts_check_io_interrupt(1)
-#endif
-#define ERTS_CHK_IO_INTR erts_check_io_interrupt
-#define ERTS_CHK_IO_INTR_TMD erts_check_io_interrupt_timed
-#define ERTS_CHK_IO erts_check_io
-#define ERTS_CHK_IO_SZ erts_check_io_size
-
-#endif
-
-void
-erts_sys_schedule_interrupt(int set)
-{
- ERTS_CHK_IO_INTR(set);
-}
-
-#ifdef ERTS_SMP
-void
-erts_sys_schedule_interrupt_timed(int set, ErtsMonotonicTime timeout_time)
-{
- ERTS_CHK_IO_INTR_TMD(set, timeout_time);
-}
-#endif
-
UWord
erts_sys_get_page_size(void)
{
@@ -313,8 +143,8 @@ erts_sys_get_page_size(void)
Uint
erts_sys_misc_mem_sz(void)
{
- Uint res = ERTS_CHK_IO_SZ();
- res += erts_smp_atomic_read_mb(&sys_misc_mem_sz);
+ Uint res = erts_check_io_size();
+ res += erts_atomic_read_mb(&sys_misc_mem_sz);
return res;
}
@@ -339,7 +169,6 @@ MALLOC_USE_HASH(1);
#endif
#endif
-#ifdef USE_THREADS
#ifdef ERTS_THR_HAVE_SIG_FUNCS
@@ -418,19 +247,15 @@ thr_create_prepare_child(void *vtcdp)
erts_sched_bind_atthrcreate_child(tcdp->sched_bind_data);
}
-#endif /* #ifdef USE_THREADS */
void
erts_sys_pre_init(void)
{
-#ifdef USE_THREADS
erts_thr_init_data_t eid = ERTS_THR_INIT_DATA_DEF_INITER;
-#endif
erts_printf_add_cr_to_stdout = 1;
erts_printf_add_cr_to_stderr = 1;
-#ifdef USE_THREADS
eid.thread_create_child_func = thr_create_prepare_child;
/* Before creation in parent */
@@ -452,23 +277,15 @@ erts_sys_pre_init(void)
erts_lc_init();
#endif
-#endif /* USE_THREADS */
erts_init_sys_time_sup();
-#ifdef USE_THREADS
-#ifdef ERTS_SMP
- erts_smp_atomic32_init_nob(&erts_break_requested, 0);
- erts_smp_atomic32_init_nob(&have_prepared_crash_dump, 0);
-#else
- erts_break_requested = 0;
- have_prepared_crash_dump = 0;
-#endif
+ erts_atomic32_init_nob(&erts_break_requested, 0);
+ erts_atomic32_init_nob(&have_prepared_crash_dump, 0);
-#endif /* USE_THREADS */
- erts_smp_atomic_init_nob(&sys_misc_mem_sz, 0);
+ erts_atomic_init_nob(&sys_misc_mem_sz, 0);
{
/*
@@ -531,10 +348,8 @@ SIGFUNC sys_signal(int sig, SIGFUNC func)
return(oact.sa_handler);
}
-#ifdef USE_THREADS
#undef sigprocmask
#define sigprocmask erts_thr_sigmask
-#endif
void sys_sigblock(int sig)
{
@@ -636,10 +451,10 @@ prepare_crash_dump(int secs)
close(crashdump_companion_cube_fd);
envsz = sizeof(env);
- i = erts_sys_getenv__("ERL_CRASH_DUMP_NICE", env, &envsz);
- if (i >= 0) {
+ i = erts_sys_explicit_8bit_getenv("ERL_CRASH_DUMP_NICE", env, &envsz);
+ if (i != 0) {
int nice_val;
- nice_val = i != 0 ? 0 : atoi(env);
+ nice_val = (i != 1) ? 0 : atoi(env);
if (nice_val > 39) {
nice_val = 39;
}
@@ -672,7 +487,7 @@ static void signal_notify_requested(Eterm type) {
erts_queue_message(p, locks, msgp, msg, am_system);
if (locks)
- erts_smp_proc_unlock(p, locks);
+ erts_proc_unlock(p, locks);
erts_proc_dec_refc(p);
}
}
@@ -685,23 +500,17 @@ break_requested(void)
* just set a flag - checked for and handled by
* scheduler threads erts_check_io() (not signal handler).
*/
-#ifdef DEBUG
- fprintf(stderr,"break!\n");
-#endif
if (ERTS_BREAK_REQUESTED)
erts_exit(ERTS_INTR_EXIT, "");
ERTS_SET_BREAK_REQUESTED;
- ERTS_CHK_IO_AS_INTR(); /* Make sure we don't sleep in poll */
+ /* Wake aux thread to get handle break */
+ erts_aux_thread_poke();
}
static RETSIGTYPE request_break(int signum)
{
-#ifdef ERTS_SMP
smp_sig_notify(signum);
-#else
- break_requested();
-#endif
}
#ifdef ETHR_UNUSABLE_SIGUSRX
@@ -789,8 +598,6 @@ signalterm_to_signum(Eterm signal)
}
}
-#ifdef ERTS_SMP
-
static ERTS_INLINE Eterm
signum_to_signalterm(int signum)
{
@@ -812,37 +619,9 @@ signum_to_signalterm(int signum)
}
}
-#endif
-
-#ifndef ERTS_SMP
-static ERTS_INLINE Uint
-signum_to_signalstate(int signum)
-{
- switch (signum) {
- case SIGINT: return (1 << 0);
- case SIGHUP: return (1 << 1);
- case SIGQUIT: return (1 << 2);
- case SIGABRT: return (1 << 3);
- case SIGALRM: return (1 << 4);
- case SIGTERM: return (1 << 5);
- case SIGUSR1: return (1 << 6);
- case SIGUSR2: return (1 << 7);
- case SIGCHLD: return (1 << 8);
- case SIGSTOP: return (1 << 9);
- case SIGTSTP: return (1 << 10);
- default: return 0;
- }
-}
-#endif
-
static RETSIGTYPE generic_signal_handler(int signum)
{
-#ifdef ERTS_SMP
smp_sig_notify(signum);
-#else
- ERTS_SET_SIGNAL_STATE(signum);
- ERTS_CHK_IO_AS_INTR(); /* Make sure we don't sleep in poll */
-#endif
}
int erts_set_signal(Eterm signal, Eterm type) {
@@ -914,7 +693,7 @@ erts_sys_unix_later_init(void)
int sys_max_files(void)
{
- return(max_files);
+ return max_files;
}
/************************** OS info *******************************/
@@ -967,34 +746,6 @@ void os_version(int *pMajor, int *pMinor, int *pBuild) {
*pBuild = get_number(&release); /* Pointer to build number. */
}
-void init_getenv_state(GETENV_STATE *state)
-{
- erts_smp_rwmtx_rlock(&environ_rwmtx);
- *state = NULL;
-}
-
-char *getenv_string(GETENV_STATE *state0)
-{
- char **state = (char **) *state0;
- char *cp;
-
- ERTS_SMP_LC_ASSERT(erts_smp_lc_rwmtx_is_rlocked(&environ_rwmtx));
-
- if (state == NULL)
- state = environ;
-
- cp = *state++;
- *state0 = (GETENV_STATE) state;
-
- return cp;
-}
-
-void fini_getenv_state(GETENV_STATE *state)
-{
- *state = NULL;
- erts_smp_rwmtx_runlock(&environ_rwmtx);
-}
-
void erts_do_break_handling(void)
{
struct termios temp_mode;
@@ -1005,7 +756,7 @@ void erts_do_break_handling(void)
* therefore, make sure that all threads but this one are blocked before
* proceeding!
*/
- erts_smp_thr_progress_block();
+ erts_thr_progress_block();
/* during break we revert to initial settings */
/* this is done differently for oldshell */
@@ -1033,25 +784,9 @@ void erts_do_break_handling(void)
tcsetattr(0,TCSANOW,&temp_mode);
}
- erts_smp_thr_progress_unblock();
+ erts_thr_progress_unblock();
}
-#ifdef ERTS_SIGNAL_STATE
-void erts_handle_signal_state(void) {
- Uint signal_state = ERTS_SIGNAL_STATE;
- Uint i = 0;
-
- ERTS_CLEAR_SIGNAL_STATE;
-
- while (signal_state) {
- if (signal_state & 0x1) {
- signal_notify_requested(signalstate_sigterm[i]);
- }
- i++;
- signal_state = signal_state >> 1;
- }
-}
-#endif
/* Fills in the systems representation of the jam/beam process identifier.
** The Pid is put in STRING representation in the supplied buffer,
@@ -1064,90 +799,6 @@ void sys_get_pid(char *buffer, size_t buffer_size){
erts_snprintf(buffer, buffer_size, "%lu",(unsigned long) p);
}
-int
-erts_sys_putenv_raw(char *key, char *value) {
- return erts_sys_putenv(key, value);
-}
-int
-erts_sys_putenv(char *key, char *value)
-{
- int res;
- char *env;
- Uint need = strlen(key) + strlen(value) + 2;
-
-#ifdef HAVE_COPYING_PUTENV
- env = erts_alloc(ERTS_ALC_T_TMP, need);
-#else
- env = erts_alloc(ERTS_ALC_T_PUTENV_STR, need);
- erts_smp_atomic_add_nob(&sys_misc_mem_sz, need);
-#endif
- strcpy(env,key);
- strcat(env,"=");
- strcat(env,value);
- erts_smp_rwmtx_rwlock(&environ_rwmtx);
- res = putenv(env);
- erts_smp_rwmtx_rwunlock(&environ_rwmtx);
-#ifdef HAVE_COPYING_PUTENV
- erts_free(ERTS_ALC_T_TMP, env);
-#endif
- return res;
-}
-
-int
-erts_sys_getenv__(char *key, char *value, size_t *size)
-{
- int res;
- char *orig_value = getenv(key);
- if (!orig_value)
- res = -1;
- else {
- size_t len = sys_strlen(orig_value);
- if (len >= *size) {
- *size = len + 1;
- res = 1;
- }
- else {
- *size = len;
- sys_memcpy((void *) value, (void *) orig_value, len+1);
- res = 0;
- }
- }
- return res;
-}
-
-int
-erts_sys_getenv_raw(char *key, char *value, size_t *size) {
- return erts_sys_getenv(key, value, size);
-}
-
-/*
- * erts_sys_getenv
- * returns:
- * -1, if environment key is not set with a value
- * 0, if environment key is set and value fits into buffer size
- * 1, if environment key is set but does not fit into buffer size
- * size is set with the needed buffer size value
- */
-
-int
-erts_sys_getenv(char *key, char *value, size_t *size)
-{
- int res;
- erts_smp_rwmtx_rlock(&environ_rwmtx);
- res = erts_sys_getenv__(key, value, size);
- erts_smp_rwmtx_runlock(&environ_rwmtx);
- return res;
-}
-
-int
-erts_sys_unsetenv(char *key)
-{
- int res;
- erts_smp_rwmtx_rwlock(&environ_rwmtx);
- res = unsetenv(key);
- erts_smp_rwmtx_rwunlock(&environ_rwmtx);
- return res;
-}
void sys_init_io(void) { }
void erts_sys_alloc_init(void) { }
@@ -1286,16 +937,6 @@ erl_assert_error(const char* expr, const char* func, const char* file, int line)
fprintf(stderr, "%s:%d:%s() Assertion failed: %s\n",
file, line, func, expr);
fflush(stderr);
-#if !defined(ERTS_SMP) && 0
- /* Writing a crashdump from a failed assertion when smp support
- * is enabled almost a guaranteed deadlocking, don't even bother.
- *
- * It could maybe be useful (but I'm not convinced) to write the
- * crashdump if smp support is disabled...
- */
- if (erts_initialized)
- erl_crash_dump(file, line, "Assertion failed: %s\n", expr);
-#endif
abort();
}
@@ -1317,22 +958,7 @@ erl_debug(char* fmt, ...)
#endif /* DEBUG */
-/*
- * Called from schedule() when it runs out of runnable processes,
- * or when Erlang code has performed INPUT_REDUCTIONS reduction
- * steps. runnable == 0 iff there are no runnable Erlang processes.
- */
-void
-erl_sys_schedule(int runnable)
-{
- ERTS_CHK_IO(!runnable);
- ERTS_SMP_LC_ASSERT(!erts_thr_progress_is_blocking());
-}
-
-
-#ifdef ERTS_SMP
-
-static erts_smp_tid_t sig_dispatcher_tid;
+static erts_tid_t sig_dispatcher_tid;
static void
smp_sig_notify(int signum)
@@ -1406,7 +1032,7 @@ signal_dispatcher_thread_func(void *unused)
}
signal_notify_requested(signal);
}
- ERTS_SMP_LC_ASSERT(!erts_thr_progress_is_blocking());
+ ERTS_LC_ASSERT(!erts_thr_progress_is_blocking());
}
return NULL;
}
@@ -1414,7 +1040,7 @@ signal_dispatcher_thread_func(void *unused)
static void
init_smp_sig_notify(void)
{
- erts_smp_thr_opts_t thr_opts = ERTS_SMP_THR_OPTS_DEFAULT_INITER;
+ erts_thr_opts_t thr_opts = ERTS_THR_OPTS_DEFAULT_INITER;
thr_opts.detached = 1;
thr_opts.name = "sys_sig_dispatcher";
@@ -1426,7 +1052,7 @@ init_smp_sig_notify(void)
}
/* Start signal handler thread */
- erts_smp_thr_create(&sig_dispatcher_tid,
+ erts_thr_create(&sig_dispatcher_tid,
signal_dispatcher_thread_func,
NULL,
&thr_opts);
@@ -1519,103 +1145,15 @@ erts_sys_main_thread(void)
}
}
-#endif /* ERTS_SMP */
-
-#ifdef ERTS_ENABLE_KERNEL_POLL /* get_value() is currently only used when
- kernel-poll is enabled */
-
-/* Get arg marks argument as handled by
- putting NULL in argv */
-static char *
-get_value(char* rest, char** argv, int* ip)
-{
- char *param = argv[*ip]+1;
- argv[*ip] = NULL;
- if (*rest == '\0') {
- char *next = argv[*ip + 1];
- if (next[0] == '-'
- && next[1] == '-'
- && next[2] == '\0') {
- erts_fprintf(stderr, "bad \"%s\" value: \n", param);
- erts_usage();
- }
- (*ip)++;
- argv[*ip] = NULL;
- return next;
- }
- return rest;
-}
-
-#endif /* ERTS_ENABLE_KERNEL_POLL */
-
void
erl_sys_args(int* argc, char** argv)
{
- int i, j;
-
- erts_smp_rwmtx_init(&environ_rwmtx, "environ", NIL,
- ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC);
-
- i = 1;
-
ASSERT(argc && argv);
- while (i < *argc) {
- if(argv[i][0] == '-') {
- switch (argv[i][1]) {
-#ifdef ERTS_ENABLE_KERNEL_POLL
- case 'K': {
- char *arg = get_value(argv[i] + 2, argv, &i);
- if (strcmp("true", arg) == 0) {
- erts_use_kernel_poll = 1;
- }
- else if (strcmp("false", arg) == 0) {
- erts_use_kernel_poll = 0;
- }
- else {
- erts_fprintf(stderr, "bad \"K\" value: %s\n", arg);
- erts_usage();
- }
- break;
- }
-#endif
- case '-':
- goto done_parsing;
- default:
- break;
- }
- }
- i++;
- }
-
- done_parsing:
-
-#ifdef ERTS_ENABLE_KERNEL_POLL
- if (erts_use_kernel_poll) {
- char no_kp[10];
- size_t no_kp_sz = sizeof(no_kp);
- int res = erts_sys_getenv_raw("ERL_NO_KERNEL_POLL", no_kp, &no_kp_sz);
- if (res > 0
- || (res == 0
- && sys_strcmp("false", no_kp) != 0
- && sys_strcmp("FALSE", no_kp) != 0)) {
- erts_use_kernel_poll = 0;
- }
- }
-#endif
-
- init_check_io();
+ max_files = erts_check_io_max_files();
-#ifdef ERTS_SMP
init_smp_sig_notify();
init_smp_sig_suspend();
-#endif
- /* Handled arguments have been marked with NULL. Slide arguments
- not handled towards the beginning of argv. */
- for (i = 0, j = 0; i < *argc; i++) {
- if (argv[i])
- argv[j++] = argv[i];
- }
- *argc = j;
+ erts_sys_env_init();
}
diff --git a/erts/emulator/sys/unix/sys_drivers.c b/erts/emulator/sys/unix/sys_drivers.c
index 834706d86f..042a091db1 100644
--- a/erts/emulator/sys/unix/sys_drivers.c
+++ b/erts/emulator/sys/unix/sys_drivers.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2017. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2018. 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.
@@ -50,17 +50,15 @@
#include <sys/ioctl.h>
#endif
+#include <sys/types.h>
+#include <sys/socket.h>
+
#define WANT_NONBLOCKING /* must define this to pull in defs from sys.h */
#include "sys.h"
-#ifdef USE_THREADS
#include "erl_threads.h"
-#endif
-extern char **environ;
-extern erts_smp_rwmtx_t environ_rwmtx;
-
-extern erts_smp_atomic_t sys_misc_mem_sz;
+extern erts_atomic_t sys_misc_mem_sz;
static Eterm forker_port;
@@ -86,12 +84,6 @@ static Eterm forker_port;
#define MAXIOV 16
#endif
-#ifdef USE_THREADS
-# define FDBLOCK 1
-#else
-# define FDBLOCK 0
-#endif
-
/* Used by the fd driver iff the fd could not be set to non-blocking */
typedef struct ErtsSysBlocking_ {
ErlDrvPDL pdl;
@@ -178,9 +170,7 @@ void
erl_sys_late_init(void)
{
SysDriverOpts opts;
-#ifdef ERTS_SMP
Port *port;
-#endif
sys_signal(SIGPIPE, SIG_IGN); /* Ignore - we'll handle the write failure */
@@ -190,20 +180,16 @@ erl_sys_late_init(void)
opts.read_write = 0;
opts.hide_window = 0;
opts.wd = NULL;
- opts.envir = NULL;
+ erts_osenv_init(&opts.envir);
opts.exit_status = 0;
opts.overlapped_io = 0;
opts.spawn_type = ERTS_SPAWN_ANY;
opts.argv = NULL;
opts.parallelism = erts_port_parallelism;
-#ifdef ERTS_SMP
port =
-#endif
erts_open_driver(&forker_driver, make_internal_pid(0), "forker", &opts, NULL, NULL);
-#ifdef ERTS_SMP
erts_mtx_unlock(port->lock);
-#endif
erts_sys_unix_later_init(); /* Need to be called after forker has been started */
}
@@ -220,10 +206,8 @@ static ErlDrvData vanilla_start(ErlDrvPort, char*, SysDriverOpts*);
/* II.III FD prototypes */
static ErlDrvData fd_start(ErlDrvPort, char*, SysDriverOpts*);
-#if FDBLOCK
static void fd_async(void *);
static void fd_ready_async(ErlDrvData drv_data, ErlDrvThreadData thread_data);
-#endif
static ErlDrvSSizeT fd_control(ErlDrvData, unsigned int, char *, ErlDrvSizeT,
char **, ErlDrvSizeT);
static void fd_stop(ErlDrvData);
@@ -287,11 +271,7 @@ struct erl_drv_entry fd_driver_entry = {
fd_control,
NULL,
outputv,
-#if FDBLOCK
fd_ready_async, /* ready_async */
-#else
- NULL,
-#endif
fd_flush, /* flush */
NULL, /* call */
NULL, /* event */
@@ -363,7 +343,7 @@ static int set_blocking_data(ErtsSysDriverData *dd) {
dd->blocking = erts_alloc(ERTS_ALC_T_SYS_BLOCKING, sizeof(ErtsSysBlocking));
- erts_smp_atomic_add_nob(&sys_misc_mem_sz, sizeof(ErtsSysBlocking));
+ erts_atomic_add_nob(&sys_misc_mem_sz, sizeof(ErtsSysBlocking));
dd->blocking->pdl = driver_pdl_create(dd->port_num);
dd->blocking->res = 0;
@@ -406,7 +386,7 @@ create_driver_data(ErlDrvPort port_num,
size += sizeof(ErtsSysFdData);
data = erts_alloc(ERTS_ALC_T_DRV_TAB,size);
- erts_smp_atomic_add_nob(&sys_misc_mem_sz, size);
+ erts_atomic_add_nob(&sys_misc_mem_sz, size);
driver_data = (ErtsSysDriverData*)data;
data += sizeof(*driver_data);
@@ -441,7 +421,7 @@ create_driver_data(ErlDrvPort port_num,
data += sizeof(*driver_data->ofd);
init_fd_data(driver_data->ofd, ofd);
}
- if (is_blocking && FDBLOCK)
+ if (is_blocking)
if (!set_blocking_data(driver_data)) {
erts_free(ERTS_ALC_T_DRV_TAB, driver_data);
return NULL;
@@ -463,85 +443,55 @@ static void close_pipes(int ifd[2], int ofd[2])
close(ofd[1]);
}
-static char **build_unix_environment(char *block)
+struct __add_spawn_env_state {
+ struct iovec *iov;
+ int *iov_index;
+
+ Sint32 *payload_size;
+ char *env_block;
+};
+
+static void add_spawn_env_block_foreach(void *_state,
+ const erts_osenv_data_t *key,
+ const erts_osenv_data_t *value)
{
- int i;
- int j;
- int len;
- char *cp;
- char **cpp;
- char** old_env;
-
- ERTS_SMP_LC_ASSERT(erts_smp_lc_rwmtx_is_rlocked(&environ_rwmtx));
-
- cp = block;
- len = 0;
- while (*cp != '\0') {
- cp += strlen(cp) + 1;
- len++;
- }
- old_env = environ;
- while (*old_env++ != NULL) {
- len++;
- }
-
- cpp = (char **) erts_alloc_fnf(ERTS_ALC_T_ENVIRONMENT,
- sizeof(char *) * (len+1));
- if (cpp == NULL) {
- return NULL;
- }
+ struct __add_spawn_env_state *state;
+ struct iovec *iov;
- cp = block;
- len = 0;
- while (*cp != '\0') {
- cpp[len] = cp;
- cp += strlen(cp) + 1;
- len++;
- }
-
- i = len;
- for (old_env = environ; *old_env; old_env++) {
- char* old = *old_env;
-
- for (j = 0; j < len; j++) {
- char *s, *t;
-
- /* check if cpp[j] equals old
- before the = sign,
- i.e.
- "TMPDIR=/tmp/" */
- s = cpp[j];
- t = old;
- while (*s == *t && *s != '=') {
- s++, t++;
- }
- if (*s == '=' && *t == '=') {
- break;
- }
- }
+ state = (struct __add_spawn_env_state*)(_state);
+ iov = &state->iov[*state->iov_index];
- if (j == len) { /* New version not found */
- cpp[len++] = old;
- }
- }
+ iov->iov_base = state->env_block;
- for (j = 0; j < i; ) {
- size_t last = strlen(cpp[j])-1;
- if (cpp[j][last] == '=' && strchr(cpp[j], '=') == cpp[j]+last) {
- cpp[j] = cpp[--len];
- if (len < i) {
- i--;
- } else {
- j++;
- }
- }
- else {
- j++;
- }
- }
+ sys_memcpy(state->env_block, key->data, key->length);
+ state->env_block += key->length;
+ *state->env_block++ = '=';
+ sys_memcpy(state->env_block, value->data, value->length);
+ state->env_block += value->length;
+ *state->env_block++ = '\0';
+
+ iov->iov_len = state->env_block - (char*)iov->iov_base;
+
+ (*state->payload_size) += iov->iov_len;
+ (*state->iov_index)++;
+}
+
+static void *add_spawn_env_block(const erts_osenv_t *env, struct iovec *iov,
+ int *iov_index, Sint32 *payload_size) {
+ struct __add_spawn_env_state add_state;
+ char *env_block;
+
+ env_block = erts_alloc(ERTS_ALC_T_TMP, env->content_size +
+ env->variable_count * sizeof("=\0"));
- cpp[len] = NULL;
- return cpp;
+ add_state.iov = iov;
+ add_state.iov_index = iov_index;
+ add_state.env_block = env_block;
+ add_state.payload_size = payload_size;
+
+ erts_osenv_foreach_native(env, &add_state, add_spawn_env_block_foreach);
+
+ return env_block;
}
static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
@@ -551,7 +501,6 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
#define CMD_LINE_PREFIX_STR_SZ (sizeof(CMD_LINE_PREFIX_STR) - 1)
int len;
- char **new_environ;
ErtsSysDriverData *dd;
char *cmd_line;
char wd_buff[MAXPATHLEN+1];
@@ -618,19 +567,7 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
memcpy((void *) (cmd_line + CMD_LINE_PREFIX_STR_SZ), (void *) name, len);
cmd_line[CMD_LINE_PREFIX_STR_SZ + len] = '\0';
len = CMD_LINE_PREFIX_STR_SZ + len + 1;
- }
-
- erts_smp_rwmtx_rlock(&environ_rwmtx);
-
- if (opts->envir == NULL) {
- new_environ = environ;
- } else if ((new_environ = build_unix_environment(opts->envir)) == NULL) {
- erts_smp_rwmtx_runlock(&environ_rwmtx);
- close_pipes(ifd, ofd);
- erts_free(ERTS_ALC_T_TMP, (void *) cmd_line);
- errno = ENOMEM;
- return ERL_DRV_ERROR_ERRNO;
- }
+}
if ((cwd = getcwd(wd_buff, MAXPATHLEN+1)) == NULL) {
/* on some OSs this call opens a fd in the
@@ -639,9 +576,6 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
int err = errno;
close_pipes(ifd, ofd);
erts_free(ERTS_ALC_T_TMP, (void *) cmd_line);
- if (new_environ != environ)
- erts_free(ERTS_ALC_T_ENVIRONMENT, (void *) new_environ);
- erts_smp_rwmtx_runlock(&environ_rwmtx);
errno = err;
return ERL_DRV_ERROR_ERRNO;
}
@@ -649,6 +583,7 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
wd = opts->wd;
{
+ void *environment_block;
struct iovec *io_vector;
int iov_len = 5;
char nullbuff[] = "\0";
@@ -661,10 +596,8 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
if (wd) iov_len++;
- /* count number of elements in environment */
- while(new_environ[env_len] != NULL)
- env_len++;
- iov_len += 1 + env_len; /* num envs including size int */
+ /* num envs including size int */
+ iov_len += 1 + opts->envir.variable_count;
/* count number of element in argument list */
if (opts->spawn_type == ERTS_SPAWN_EXECUTABLE) {
@@ -681,10 +614,7 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
if (!io_vector) {
close_pipes(ifd, ofd);
- erts_smp_rwmtx_runlock(&environ_rwmtx);
erts_free(ERTS_ALC_T_TMP, (void *) cmd_line);
- if (new_environ != environ)
- erts_free(ERTS_ALC_T_ENVIRONMENT, (void *) new_environ);
errno = ENOMEM;
return ERL_DRV_ERROR_ERRNO;
}
@@ -719,16 +649,13 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
io_vector[i++].iov_len = 1;
buffsz += io_vector[i-1].iov_len;
+ env_len = htonl(opts->envir.variable_count);
io_vector[i].iov_base = (void*)&env_len;
- env_len = htonl(env_len);
io_vector[i++].iov_len = sizeof(env_len);
buffsz += io_vector[i-1].iov_len;
- for (j = 0; new_environ[j] != NULL; j++) {
- io_vector[i].iov_base = new_environ[j];
- io_vector[i++].iov_len = strlen(new_environ[j]) + 1;
- buffsz += io_vector[i-1].iov_len;
- }
+ environment_block = add_spawn_env_block(&opts->envir, io_vector, &i,
+ &buffsz);
/* only append arguments if this was a spawn_executable */
if (opts->spawn_type == ERTS_SPAWN_EXECUTABLE) {
@@ -758,15 +685,12 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
/* we send the request to do the fork */
if ((res = writev(ofd[1], io_vector, iov_len > MAXIOV ? MAXIOV : iov_len)) < 0) {
- if (errno == ERRNO_BLOCK) {
+ if (errno == ERRNO_BLOCK || errno == EINTR) {
res = 0;
} else {
int err = errno;
close_pipes(ifd, ofd);
erts_free(ERTS_ALC_T_TMP, io_vector);
- if (new_environ != environ)
- erts_free(ERTS_ALC_T_ENVIRONMENT, (void *) new_environ);
- erts_smp_rwmtx_runlock(&environ_rwmtx);
erts_free(ERTS_ALC_T_TMP, (void *) cmd_line);
errno = err;
return ERL_DRV_ERROR_ERRNO;
@@ -787,16 +711,12 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
driver_select(port_num, ofd[1], ERL_DRV_WRITE|ERL_DRV_USE, 1);
}
+ erts_free(ERTS_ALC_T_TMP, environment_block);
erts_free(ERTS_ALC_T_TMP, io_vector);
}
erts_free(ERTS_ALC_T_TMP, (void *) cmd_line);
- if (new_environ != environ)
- erts_free(ERTS_ALC_T_ENVIRONMENT, (void *) new_environ);
-
- erts_smp_rwmtx_runlock(&environ_rwmtx);
-
dd = create_driver_data(port_num, ifd[0], ofd[1], opts->packet_bytes,
DO_WRITE | DO_READ, opts->exit_status,
0, 0);
@@ -812,7 +732,8 @@ static ErlDrvData spawn_start(ErlDrvPort port_num, char* name,
proto->u.start.fds[1] = ifd[1];
proto->u.start.fds[2] = stderrfd;
proto->u.start.port_id = opts->exit_status ? erts_drvport2id(port_num) : THE_NON_VALUE;
- if (erl_drv_port_control(forker_port, 'S', (char*)proto, sizeof(*proto))) {
+ if (erl_drv_port_control(forker_port, ERTS_FORKER_DRV_CONTROL_MAGIC_NUMBER,
+ (char*)proto, sizeof(*proto))) {
/* The forker port has been killed, we close both fd's which will
make open_port throw an epipe error */
close(ofd[0]);
@@ -839,6 +760,9 @@ static ErlDrvSSizeT spawn_control(ErlDrvData e, unsigned int cmd, char *buf,
ErtsSysDriverData *dd = (ErtsSysDriverData*)e;
ErtsSysForkerProto *proto = (ErtsSysForkerProto *)buf;
+ if (cmd != ERTS_SPAWN_DRV_CONTROL_MAGIC_NUMBER)
+ return -1;
+
ASSERT(len == sizeof(*proto));
ASSERT(proto->action == ErtsSysForkerProtoAction_SigChld);
@@ -879,6 +803,8 @@ static ErlDrvSSizeT fd_control(ErlDrvData drv_data,
{
int fd = (int)(long)drv_data;
char resbuff[2*sizeof(Uint32)];
+
+ command -= ERTS_TTYSL_DRV_CONTROL_MAGIC_NUMBER;
switch (command) {
case FD_CTRL_OP_GET_WINSIZE:
{
@@ -890,7 +816,7 @@ static ErlDrvSSizeT fd_control(ErlDrvData drv_data,
}
break;
default:
- return 0;
+ return -1;
}
if (rlen < 2*sizeof(Uint32)) {
*rbuf = driver_alloc(2*sizeof(Uint32));
@@ -1068,8 +994,8 @@ static void clear_fd_data(ErtsSysFdData *fdd)
{
if (fdd->sz > 0) {
erts_free(ERTS_ALC_T_FD_ENTRY_BUF, (void *) fdd->buf);
- ASSERT(erts_smp_atomic_read_nob(&sys_misc_mem_sz) >= fdd->sz);
- erts_smp_atomic_add_nob(&sys_misc_mem_sz, -1*fdd->sz);
+ ASSERT(erts_atomic_read_nob(&sys_misc_mem_sz) >= fdd->sz);
+ erts_atomic_add_nob(&sys_misc_mem_sz, -1*fdd->sz);
}
fdd->buf = NULL;
fdd->sz = 0;
@@ -1078,9 +1004,9 @@ static void clear_fd_data(ErtsSysFdData *fdd)
fdd->psz = 0;
}
-static void nbio_stop_fd(ErlDrvPort prt, ErtsSysFdData *fdd)
+static void nbio_stop_fd(ErlDrvPort prt, ErtsSysFdData *fdd, int use)
{
- driver_select(prt, abs(fdd->fd), DO_READ|DO_WRITE, 0);
+ driver_select(prt, abs(fdd->fd), use ? ERL_DRV_USE_NO_CALLBACK : 0|DO_READ|DO_WRITE, 0);
clear_fd_data(fdd);
SET_BLOCKING(abs(fdd->fd));
@@ -1092,25 +1018,23 @@ static void fd_stop(ErlDrvData ev) /* Does not close the fds */
ErlDrvPort prt = dd->port_num;
int sz = sizeof(ErtsSysDriverData);
-#if FDBLOCK
if (dd->blocking) {
erts_free(ERTS_ALC_T_SYS_BLOCKING, dd->blocking);
dd->blocking = NULL;
sz += sizeof(ErtsSysBlocking);
}
-#endif
if (dd->ifd) {
sz += sizeof(ErtsSysFdData);
- nbio_stop_fd(prt, dd->ifd);
+ nbio_stop_fd(prt, dd->ifd, 1);
}
if (dd->ofd && dd->ofd != dd->ifd) {
sz += sizeof(ErtsSysFdData);
- nbio_stop_fd(prt, dd->ofd);
+ nbio_stop_fd(prt, dd->ofd, 1);
}
erts_free(ERTS_ALC_T_DRV_TAB, dd);
- erts_smp_atomic_add_nob(&sys_misc_mem_sz, -sz);
+ erts_atomic_add_nob(&sys_misc_mem_sz, -sz);
}
static void fd_flush(ErlDrvData ev)
@@ -1152,12 +1076,12 @@ static void stop(ErlDrvData ev)
ErlDrvPort prt = dd->port_num;
if (dd->ifd) {
- nbio_stop_fd(prt, dd->ifd);
+ nbio_stop_fd(prt, dd->ifd, 0);
driver_select(prt, abs(dd->ifd->fd), ERL_DRV_USE, 0); /* close(ifd); */
}
if (dd->ofd && dd->ofd != dd->ifd) {
- nbio_stop_fd(prt, dd->ofd);
+ nbio_stop_fd(prt, dd->ofd, 0);
driver_select(prt, abs(dd->ofd->fd), ERL_DRV_USE, 0); /* close(ofd); */
}
@@ -1191,19 +1115,19 @@ static void outputv(ErlDrvData e, ErlIOVec* ev)
ev->iov[0].iov_len = pb;
ev->size += pb;
- if (dd->blocking && FDBLOCK)
+ if (dd->blocking)
driver_pdl_lock(dd->blocking->pdl);
if ((sz = driver_sizeq(ix)) > 0) {
driver_enqv(ix, ev, 0);
- if (dd->blocking && FDBLOCK)
+ if (dd->blocking)
driver_pdl_unlock(dd->blocking->pdl);
if (sz + ev->size >= (1 << 13))
set_busy_port(ix, 1);
}
- else if (!dd->blocking || !FDBLOCK) {
+ else if (!dd->blocking) {
/* We try to write directly if the fd in non-blocking */
int vsize = ev->vsize > MAX_VSIZE ? MAX_VSIZE : ev->vsize;
@@ -1220,7 +1144,6 @@ static void outputv(ErlDrvData e, ErlIOVec* ev)
driver_enqv(ix, ev, n); /* n is the skip value */
driver_select(ix, ofd, ERL_DRV_WRITE|ERL_DRV_USE, 1);
}
-#if FDBLOCK
else {
if (ev->size != 0) {
driver_enqv(ix, ev, 0);
@@ -1231,7 +1154,6 @@ static void outputv(ErlDrvData e, ErlIOVec* ev)
driver_pdl_unlock(dd->blocking->pdl);
}
}
-#endif
/* return 0;*/
}
@@ -1303,7 +1225,7 @@ static int port_inp_failure(ErtsSysDriverData *dd, int res)
clear_fd_data(dd->ifd);
}
- if (dd->blocking && FDBLOCK) {
+ if (dd->blocking) {
driver_pdl_lock(dd->blocking->pdl);
if (driver_sizeq(dd->port_num) > 0) {
driver_pdl_unlock(dd->blocking->pdl);
@@ -1341,6 +1263,8 @@ static int port_inp_failure(ErtsSysDriverData *dd, int res)
}
driver_failure_eof(dd->port_num);
} else if (dd->ifd) {
+ if (dd->alive == -1)
+ errno = dd->status;
erl_drv_init_ack(dd->port_num, ERL_DRV_ERROR_ERRNO);
} else {
driver_failure_posix(dd->port_num, err);
@@ -1371,10 +1295,10 @@ static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
int res;
if((res = read(ready_fd, &proto, sizeof(proto))) <= 0) {
+ if (res < 0 && (errno == ERRNO_BLOCK || errno == EINTR))
+ return;
/* hmm, child setup seems to have closed the pipe too early...
we close the port as there is not much else we can do */
- if (res < 0 && errno == ERRNO_BLOCK)
- return;
driver_select(port_num, ready_fd, ERL_DRV_READ, 0);
if (res == 0)
errno = EPIPE;
@@ -1408,7 +1332,7 @@ static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
if (dd->ifd->fd < 0) {
driver_select(port_num, abs(dd->ifd->fd), ERL_DRV_READ|ERL_DRV_USE, 0);
- erts_smp_atomic_add_nob(&sys_misc_mem_sz, -sizeof(ErtsSysFdData));
+ erts_atomic_add_nob(&sys_misc_mem_sz, -sizeof(ErtsSysFdData));
dd->ifd = NULL;
}
@@ -1508,13 +1432,13 @@ static void ready_input(ErlDrvData e, ErlDrvEvent ready_fd)
continue;
}
else { /* The last message we got was split */
- char *buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h);
+ char *buf = erts_alloc_fnf(ERTS_ALC_T_FD_ENTRY_BUF, h);
if (!buf) {
errno = ENOMEM;
port_inp_failure(dd, -1);
}
else {
- erts_smp_atomic_add_nob(&sys_misc_mem_sz, h);
+ erts_atomic_add_nob(&sys_misc_mem_sz, h);
sys_memcpy(buf, cpos, bytes_left);
dd->ifd->buf = buf;
dd->ifd->sz = h;
@@ -1549,7 +1473,7 @@ static void ready_output(ErlDrvData e, ErlDrvEvent ready_fd)
should close the output fd as soon as the command has
been sent. */
driver_select(ix, ready_fd, ERL_DRV_WRITE|ERL_DRV_USE, 0);
- erts_smp_atomic_add_nob(&sys_misc_mem_sz, -sizeof(ErtsSysFdData));
+ erts_atomic_add_nob(&sys_misc_mem_sz, -sizeof(ErtsSysFdData));
dd->ofd = NULL;
}
if (dd->terminating)
@@ -1579,7 +1503,6 @@ static void stop_select(ErlDrvEvent fd, void* _)
close((int)fd);
}
-#if FDBLOCK
static void
fd_async(void *async_data)
@@ -1658,7 +1581,6 @@ void fd_ready_async(ErlDrvData drv_data,
return; /* 0; */
}
-#endif
/* Forker driver */
@@ -1678,15 +1600,13 @@ static ErlDrvData forker_start(ErlDrvPort port_num, char* name,
forker_port = erts_drvport2id(port_num);
- res = erts_sys_getenv_raw("BINDIR", bindir, &bindirsz);
- if (res != 0) {
- if (res < 0)
- erts_exit(1,
- "Environment variable BINDIR is not set\n");
- if (res > 0)
- erts_exit(1,
- "Value of environment variable BINDIR is too large\n");
+ res = erts_sys_explicit_8bit_getenv("BINDIR", bindir, &bindirsz);
+ if (res == 0) {
+ erts_exit(1, "Environment variable BINDIR is not set\n");
+ } else if(res < 0) {
+ erts_exit(1, "Value of environment variable BINDIR is too large\n");
}
+
if (bindir[0] != DIR_SEPARATOR_CHAR)
erts_exit(1,
"Environment variable BINDIR does not contain an"
@@ -1749,8 +1669,6 @@ static ErlDrvData forker_start(ErlDrvPort port_num, char* name,
SET_NONBLOCKING(forker_fd);
- driver_select(port_num, forker_fd, ERL_DRV_READ|ERL_DRV_USE, 1);
-
return (ErlDrvData)port_num;
}
@@ -1760,15 +1678,38 @@ static void forker_stop(ErlDrvData e)
the port has been closed by the user. */
}
+static ErlDrvSizeT forker_deq(ErlDrvPort port_num, ErtsSysForkerProto *proto)
+{
+ close(proto->u.start.fds[0]);
+ close(proto->u.start.fds[1]);
+ if (proto->u.start.fds[1] != proto->u.start.fds[2])
+ close(proto->u.start.fds[2]);
+
+ return driver_deq(port_num, sizeof(*proto));
+}
+
+static void forker_sigchld(Eterm port_id, int error)
+{
+ ErtsSysForkerProto *proto = erts_alloc(ERTS_ALC_T_DRV_CTRL_DATA, sizeof(*proto));
+ proto->action = ErtsSysForkerProtoAction_SigChld;
+ proto->u.sigchld.error_number = error;
+ proto->u.sigchld.port_id = port_id;
+
+ /* ideally this would be a port_command call, but as command is
+ already used by the spawn_driver, we use control instead.
+ Note that when using erl_drv_port_control it is an asynchronous
+ control. */
+ erl_drv_port_control(port_id, ERTS_SPAWN_DRV_CONTROL_MAGIC_NUMBER,
+ (char*)proto, sizeof(*proto));
+}
+
static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
{
int res;
- ErtsSysForkerProto *proto;
-
- proto = erts_alloc(ERTS_ALC_T_DRV_CTRL_DATA, sizeof(*proto));
+ ErtsSysForkerProto proto;
- if ((res = read(fd, proto, sizeof(*proto))) < 0) {
- if (errno == ERRNO_BLOCK)
+ if ((res = read(fd, &proto, sizeof(proto))) < 0) {
+ if (errno == ERRNO_BLOCK || errno == EINTR)
return;
erts_exit(ERTS_DUMP_EXIT, "Failed to read from erl_child_setup: %d\n", errno);
}
@@ -1776,10 +1717,10 @@ static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
if (res == 0)
erts_exit(ERTS_DUMP_EXIT, "erl_child_setup closed\n");
- ASSERT(res == sizeof(*proto));
+ ASSERT(res == sizeof(proto));
#ifdef FORKER_PROTO_START_ACK
- if (proto->action == ErtsSysForkerProtoAction_StartAck) {
+ if (proto.action == ErtsSysForkerProtoAction_StartAck) {
/* Ideally we would like to not have to ack each Start
command being sent over the uds, but it would seem
that some operating systems (only observed on FreeBSD)
@@ -1789,28 +1730,15 @@ static void forker_ready_input(ErlDrvData e, ErlDrvEvent fd)
ErlDrvPort port_num = (ErlDrvPort)e;
int vlen;
SysIOVec *iov = driver_peekq(port_num, &vlen);
- ErtsSysForkerProto *proto = (ErtsSysForkerProto *)iov[0].iov_base;
-
- close(proto->u.start.fds[0]);
- close(proto->u.start.fds[1]);
- if (proto->u.start.fds[1] != proto->u.start.fds[2])
- close(proto->u.start.fds[2]);
+ ErtsSysForkerProto *qproto = (ErtsSysForkerProto *)iov[0].iov_base;
- driver_deq(port_num, sizeof(*proto));
-
- if (driver_sizeq(port_num) > 0)
+ if (forker_deq(port_num, qproto))
driver_select(port_num, forker_fd, ERL_DRV_WRITE|ERL_DRV_USE, 1);
} else
#endif
{
- ASSERT(proto->action == ErtsSysForkerProtoAction_SigChld);
-
- /* ideally this would be a port_command call, but as command is
- already used by the spawn_driver, we use control instead.
- Note that when using erl_drv_port_control it is an asynchronous
- control. */
- erl_drv_port_control(proto->u.sigchld.port_id, 'S',
- (char*)proto, sizeof(*proto));
+ ASSERT(proto.action == ErtsSysForkerProtoAction_SigChld);
+ forker_sigchld(proto.u.sigchld.port_id, proto.u.sigchld.error_number);
}
}
@@ -1820,7 +1748,8 @@ static void forker_ready_output(ErlDrvData e, ErlDrvEvent fd)
ErlDrvPort port_num = (ErlDrvPort)e;
#ifndef FORKER_PROTO_START_ACK
- while (driver_sizeq(port_num) > 0) {
+ int loops = 10;
+ while (driver_sizeq(port_num) > 0 && --loops) {
#endif
int vlen;
SysIOVec *iov = driver_peekq(port_num, &vlen);
@@ -1828,29 +1757,45 @@ static void forker_ready_output(ErlDrvData e, ErlDrvEvent fd)
ASSERT(iov[0].iov_len >= (sizeof(*proto)));
if (sys_uds_write(forker_fd, (char*)proto, sizeof(*proto),
proto->u.start.fds, 3, 0) < 0) {
- if (errno == ERRNO_BLOCK)
+ if (errno == ERRNO_BLOCK || errno == EINTR) {
return;
- erts_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
+ } else if (errno == EMFILE) {
+ forker_sigchld(proto->u.start.port_id, errno);
+ if (forker_deq(port_num, proto) == 0)
+ driver_select(port_num, forker_fd, ERL_DRV_WRITE, 0);
+ return;
+ } else {
+ erts_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
+ }
}
#ifndef FORKER_PROTO_START_ACK
- close(proto->u.start.fds[0]);
- close(proto->u.start.fds[1]);
- if (proto->u.start.fds[1] != proto->u.start.fds[2])
- close(proto->u.start.fds[2]);
- driver_deq(port_num, sizeof(*proto));
+ if (forker_deq(port_num, proto) == 0)
+ driver_select(port_num, forker_fd, ERL_DRV_WRITE, 0);
}
-#endif
-
+#else
driver_select(port_num, forker_fd, ERL_DRV_WRITE, 0);
+#endif
}
static ErlDrvSSizeT forker_control(ErlDrvData e, unsigned int cmd, char *buf,
ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen)
{
+ static int first_call = 1;
ErtsSysForkerProto *proto = (ErtsSysForkerProto *)buf;
ErlDrvPort port_num = (ErlDrvPort)e;
int res;
+ if (cmd != ERTS_FORKER_DRV_CONTROL_MAGIC_NUMBER)
+ return -1;
+
+ if (first_call) {
+ /*
+ * Do driver_select here when schedulers and their pollsets have started.
+ */
+ driver_select(port_num, forker_fd, ERL_DRV_READ|ERL_DRV_USE, 1);
+ first_call = 0;
+ }
+
driver_enq(port_num, buf, len);
if (driver_sizeq(port_num) > sizeof(*proto)) {
return 0;
@@ -1858,20 +1803,21 @@ static ErlDrvSSizeT forker_control(ErlDrvData e, unsigned int cmd, char *buf,
if ((res = sys_uds_write(forker_fd, (char*)proto, sizeof(*proto),
proto->u.start.fds, 3, 0)) < 0) {
- if (errno == ERRNO_BLOCK) {
+ if (errno == ERRNO_BLOCK || errno == EINTR) {
driver_select(port_num, forker_fd, ERL_DRV_WRITE|ERL_DRV_USE, 1);
return 0;
+ } else if (errno == EMFILE) {
+ forker_sigchld(proto->u.start.port_id, errno);
+ forker_deq(port_num, proto);
+ return 0;
+ } else {
+ erts_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
}
- erts_exit(ERTS_DUMP_EXIT, "Failed to write to erl_child_setup: %d\n", errno);
}
#ifndef FORKER_PROTO_START_ACK
ASSERT(res == sizeof(*proto));
- close(proto->u.start.fds[0]);
- close(proto->u.start.fds[1]);
- if (proto->u.start.fds[1] != proto->u.start.fds[2])
- close(proto->u.start.fds[2]);
- driver_deq(port_num, sizeof(*proto));
+ forker_deq(port_num, proto);
#endif
return 0;
diff --git a/erts/emulator/sys/unix/sys_env.c b/erts/emulator/sys/unix/sys_env.c
new file mode 100644
index 0000000000..4d8301f985
--- /dev/null
+++ b/erts/emulator/sys/unix/sys_env.c
@@ -0,0 +1,133 @@
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "sys.h"
+#include "erl_osenv.h"
+#include "erl_alloc.h"
+
+#include "erl_thr_progress.h"
+
+static erts_osenv_t sysenv_global_env;
+static erts_rwmtx_t sysenv_rwmtx;
+
+extern char **environ;
+
+static void import_initial_env(void);
+
+void erts_sys_env_init() {
+ erts_rwmtx_init(&sysenv_rwmtx, "environ", NIL,
+ ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC);
+
+ erts_osenv_init(&sysenv_global_env);
+ import_initial_env();
+}
+
+const erts_osenv_t *erts_sys_rlock_global_osenv() {
+ erts_rwmtx_rlock(&sysenv_rwmtx);
+ return &sysenv_global_env;
+}
+
+erts_osenv_t *erts_sys_rwlock_global_osenv() {
+ erts_rwmtx_rwlock(&sysenv_rwmtx);
+ return &sysenv_global_env;
+}
+
+void erts_sys_rwunlock_global_osenv() {
+ erts_rwmtx_rwunlock(&sysenv_rwmtx);
+}
+
+void erts_sys_runlock_global_osenv() {
+ erts_rwmtx_runlock(&sysenv_rwmtx);
+}
+
+int erts_sys_explicit_8bit_putenv(char *key, char *value) {
+ erts_osenv_data_t env_key, env_value;
+ int result;
+
+ env_key.length = sys_strlen(key);
+ env_key.data = key;
+
+ env_value.length = sys_strlen(value);
+ env_value.data = value;
+
+ {
+ erts_osenv_t *env = erts_sys_rwlock_global_osenv();
+ result = erts_osenv_put_native(env, &env_key, &env_value);
+ erts_sys_rwunlock_global_osenv();
+ }
+
+ return result;
+}
+
+int erts_sys_explicit_8bit_getenv(char *key, char *value, size_t *size) {
+ erts_osenv_data_t env_key, env_value;
+ int result;
+
+ env_key.length = sys_strlen(key);
+ env_key.data = key;
+
+ /* Reserve space for NUL termination. */
+ env_value.length = *size - 1;
+ env_value.data = value;
+
+ {
+ const erts_osenv_t *env = erts_sys_rlock_global_osenv();
+ result = erts_osenv_get_native(env, &env_key, &env_value);
+ erts_sys_runlock_global_osenv();
+ }
+
+ if(result == 1) {
+ value[env_value.length] = '\0';
+ }
+
+ *size = env_value.length;
+
+ return result;
+}
+
+int erts_sys_explicit_host_getenv(char *key, char *value, size_t *size) {
+ char *orig_value;
+ size_t length;
+
+ orig_value = getenv(key);
+
+ if(orig_value == NULL) {
+ return 0;
+ }
+
+ length = sys_strlen(orig_value);
+
+ if (length >= *size) {
+ *size = length + 1;
+ return -1;
+ }
+
+ sys_memcpy((void*)value, (void*)orig_value, length + 1);
+ *size = length;
+
+ return 1;
+}
+
+static void import_initial_env(void) {
+ char **environ_iterator, *environ_variable;
+
+ environ_iterator = environ;
+
+ while ((environ_variable = *(environ_iterator++)) != NULL) {
+ char *separator_index = strchr(environ_variable, '=');
+
+ if (separator_index != NULL) {
+ erts_osenv_data_t env_key, env_value;
+
+ env_key.length = separator_index - environ_variable;
+ env_key.data = environ_variable;
+
+ env_value.length = sys_strlen(separator_index) - 1;
+ env_value.data = separator_index + 1;
+
+ erts_osenv_put_native(&sysenv_global_env, &env_key, &env_value);
+ }
+ }
+}
diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c
index 6435da086f..832074f679 100644
--- a/erts/emulator/sys/unix/sys_float.c
+++ b/erts/emulator/sys/unix/sys_float.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2001-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2001-2018. 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.
@@ -39,7 +39,6 @@ erts_sys_init_float(void)
#else /* !NO_FPE_SIGNALS */
-#ifdef ERTS_SMP
static erts_tsd_key_t fpe_key;
/* once-only initialisation early in the main thread (via erts_sys_init_float()) */
@@ -61,11 +60,6 @@ static ERTS_INLINE volatile unsigned long *erts_thread_get_fp_exception(void)
{
return (volatile unsigned long*)erts_tsd_get(fpe_key);
}
-#else /* !SMP */
-#define erts_init_fp_exception() /*empty*/
-static volatile unsigned long fp_exception;
-#define erts_thread_get_fp_exception() (&fp_exception)
-#endif /* SMP */
volatile unsigned long *erts_get_current_fp_exception(void)
{
@@ -659,11 +653,9 @@ void erts_sys_init_float(void)
void erts_thread_init_float(void)
{
-#ifdef ERTS_SMP
/* This allows Erlang schedulers to leave Erlang-process context
and still have working FP exceptions. XXX: is this needed? */
erts_thread_init_fp_exception();
-#endif
#ifndef NO_FPE_SIGNALS
/* NOTE:
diff --git a/erts/emulator/sys/unix/sys_time.c b/erts/emulator/sys/unix/sys_time.c
index 102ef7bebf..8ba575b7b6 100644
--- a/erts/emulator/sys/unix/sys_time.c
+++ b/erts/emulator/sys/unix/sys_time.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2005-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2005-2018. 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.
@@ -160,7 +160,7 @@ struct sys_time_internal_state_read_mostly__ {
#ifdef ERTS_SYS_TIME_INTERNAL_STATE_WRITE_FREQ__
struct sys_time_internal_state_write_freq__ {
- erts_smp_mtx_t mtx;
+ erts_mtx_t mtx;
#if defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME)
ErtsMonotonicTime last_delivered;
#endif
@@ -304,7 +304,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp)
erts_sys_time_data__.r.o.os_times =
clock_gettime_times_verified;
#endif
- erts_smp_mtx_init(&internal_state.w.f.mtx, "os_monotonic_time", NIL,
+ erts_mtx_init(&internal_state.w.f.mtx, "os_monotonic_time", NIL,
ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_IO);
internal_state.w.f.last_delivered
= clock_gettime_monotonic();
@@ -525,12 +525,12 @@ static ErtsMonotonicTime clock_gettime_monotonic_verified(void)
mtime = (ErtsMonotonicTime) posix_clock_gettime(MONOTONIC_CLOCK_ID,
MONOTONIC_CLOCK_ID_STR);
- erts_smp_mtx_lock(&internal_state.w.f.mtx);
+ erts_mtx_lock(&internal_state.w.f.mtx);
if (mtime < internal_state.w.f.last_delivered)
mtime = internal_state.w.f.last_delivered;
else
internal_state.w.f.last_delivered = mtime;
- erts_smp_mtx_unlock(&internal_state.w.f.mtx);
+ erts_mtx_unlock(&internal_state.w.f.mtx);
return mtime;
}
@@ -547,12 +547,12 @@ static void clock_gettime_times_verified(ErtsMonotonicTime *mtimep,
WALL_CLOCK_ID_STR,
stimep);
- erts_smp_mtx_lock(&internal_state.w.f.mtx);
+ erts_mtx_lock(&internal_state.w.f.mtx);
if (*mtimep < internal_state.w.f.last_delivered)
*mtimep = internal_state.w.f.last_delivered;
else
internal_state.w.f.last_delivered = *mtimep;
- erts_smp_mtx_unlock(&internal_state.w.f.mtx);
+ erts_mtx_unlock(&internal_state.w.f.mtx);
}
#endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */
@@ -878,8 +878,6 @@ ErtsMonotonicTime
erts_os_monotonic_time(void)
{
Uint32 ticks = get_tick_count();
- ERTS_CHK_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd,
- ticks);
return ERTS_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd,
ticks) << internal_state.r.o.times_shift;
}
diff --git a/erts/emulator/sys/unix/sys_uds.c b/erts/emulator/sys/unix/sys_uds.c
index dd0a3b03ff..c9f73622ba 100644
--- a/erts/emulator/sys/unix/sys_uds.c
+++ b/erts/emulator/sys/unix/sys_uds.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. 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.
@@ -18,6 +18,42 @@
* %CopyrightEnd%
*/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#if defined(__sun__) && !defined(_XOPEN_SOURCE)
+#define _XOPEN_SOURCE 500
+#endif
+
+#include <limits.h>
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#ifdef HAVE_SYS_SOCKETIO_H
+# include <sys/socketio.h>
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+# include <sys/sockio.h>
+#endif
+
+#ifdef HAVE_NET_ERRNO_H
+#include <net/errno.h>
+#endif
+
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
#include "sys_uds.h"
int
@@ -52,8 +88,9 @@ sys_uds_readv(int fd, struct iovec *iov, size_t iov_len,
if((msg.msg_flags & MSG_CTRUNC) == MSG_CTRUNC)
{
/* We assume that we have given enough space for any header
- that are sent to us. So the only remaining reason to get
- this flag set is if the caller has run out of file descriptors.
+ that are sent to us. So the only remaining reasons to get
+ this flag set is if the caller has run out of file descriptors
+ or an SELinux policy prunes the response (eg. O_APPEND on STDERR).
*/
errno = EMFILE;
return -1;
@@ -96,7 +133,7 @@ sys_uds_writev(int fd, struct iovec *iov, size_t iov_len,
struct msghdr msg;
struct cmsghdr *cmsg = NULL;
- int res, i;
+ int res, i, error;
/* initialize socket message */
memset(&msg, 0, sizeof(struct msghdr));
@@ -137,11 +174,22 @@ sys_uds_writev(int fd, struct iovec *iov, size_t iov_len,
res = sendmsg(fd, &msg, flags);
+#ifdef ETOOMANYREFS
+ /* Linux may give ETOOMANYREFS when there are too many fds in transit.
+ We map this to EMFILE as bsd and other use this error code and we want
+ the behaviour to be the same on all OSs */
+ if (errno == ETOOMANYREFS)
+ errno = EMFILE;
+#endif
+ error = errno;
+
if (iov_len > MAXIOV)
free(iov[0].iov_base);
free(msg.msg_control);
+ errno = error;
+
return res;
}
diff --git a/erts/emulator/sys/unix/sys_uds.h b/erts/emulator/sys/unix/sys_uds.h
index a598102d5c..49a4b39250 100644
--- a/erts/emulator/sys/unix/sys_uds.h
+++ b/erts/emulator/sys/unix/sys_uds.h
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2002-2016. All Rights Reserved.
+ * Copyright Ericsson AB 2002-2018. 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.
@@ -21,18 +21,6 @@
#ifndef _ERL_UNIX_UDS_H
#define _ERL_UNIX_UDS_H
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#if defined(__sun__) && !defined(_XOPEN_SOURCE)
-#define _XOPEN_SOURCE 500
-#endif
-
-#include <limits.h>
-
-#include <sys/types.h>
-#include <sys/socket.h>
#include <sys/uio.h>
#if defined IOV_MAX
@@ -43,8 +31,6 @@
#define MAXIOV 16
#endif
-#include "sys.h"
-
int sys_uds_readv(int fd, struct iovec *iov, size_t iov_len,
int *fds, int fd_count, int flags);
int sys_uds_read(int fd, char *buff, size_t len,