aboutsummaryrefslogtreecommitdiffstats
path: root/erts
diff options
context:
space:
mode:
Diffstat (limited to 'erts')
-rw-r--r--erts/doc/src/erlang.xml108
-rw-r--r--erts/emulator/Makefile.in31
-rw-r--r--erts/emulator/beam/erl_thr_progress.h13
-rw-r--r--erts/emulator/beam/io.c2
-rw-r--r--erts/emulator/drivers/common/efile_drv.c102
-rw-r--r--erts/emulator/drivers/common/inet_drv.c40
-rw-r--r--erts/emulator/drivers/common/zlib_drv.c10
-rw-r--r--erts/emulator/drivers/unix/unix_efile.c21
-rw-r--r--erts/emulator/test/erts_debug_SUITE.erl65
-rw-r--r--erts/etc/common/escript.c3
-rw-r--r--erts/etc/unix/etp-commands32
-rw-r--r--erts/lib_src/common/erl_misc_utils.c8
-rw-r--r--erts/lib_src/common/ethr_atomics.c144
-rwxr-xr-xerts/lib_src/utils/make_atomics_api45
-rw-r--r--erts/preloaded/ebin/prim_inet.beambin69980 -> 70100 bytes
-rw-r--r--erts/preloaded/ebin/zlib.beambin12432 -> 12804 bytes
-rw-r--r--erts/preloaded/src/prim_inet.erl6
-rw-r--r--erts/preloaded/src/zlib.erl72
-rw-r--r--erts/test/otp_SUITE.erl3
19 files changed, 491 insertions, 214 deletions
diff --git a/erts/doc/src/erlang.xml b/erts/doc/src/erlang.xml
index fbe7b36163..8c438b0bd7 100644
--- a/erts/doc/src/erlang.xml
+++ b/erts/doc/src/erlang.xml
@@ -4881,6 +4881,7 @@ true</pre>
<v>Type, Res -- see below</v>
</type>
<desc>
+ <p>All times are in milliseconds unless otherwise specified.</p>
<p>Returns information about the system as specified by
<c>Type</c>:</p>
<taglist>
@@ -4894,15 +4895,20 @@ true</pre>
<item>
<p>Returns
<c>{Total_Exact_Reductions, Exact_Reductions_Since_Last_Call}</c>.</p>
- <p><em>NOTE:</em><c>statistics(exact_reductions)</c> is
- a more expensive operation than
- <seealso marker="#statistics_reductions">statistics(reductions)</seealso>
- especially on an Erlang machine with SMP support.</p>
+ <note><p><c>statistics(exact_reductions)</c> is
+ a more expensive operation than
+ <seealso marker="#statistics_reductions">statistics(reductions)</seealso>
+ especially on an Erlang machine with SMP support.</p>
+ </note>
</item>
<tag><c>garbage_collection</c></tag>
<item>
<p>Returns <c>{Number_of_GCs, Words_Reclaimed, 0}</c>. This
information may not be valid for all implementations.</p>
+ <pre>
+> <input>statistics(garbage_collection).</input>
+{85,23961,0}
+</pre>
</item>
<tag><c>io</c></tag>
<item>
@@ -4914,12 +4920,18 @@ true</pre>
<tag><marker id="statistics_reductions"><c>reductions</c></marker></tag>
<item>
<p>Returns
- <c>{Total_Reductions, Reductions_Since_Last_Call}</c>.</p>
- <p><em>NOTE:</em> From erts version 5.5 (OTP release R11B)
- this value does not include reductions performed in current
- time slices of currently scheduled processes. If an
- exact value is wanted, use
- <seealso marker="#statistics_exact_reductions">statistics(exact_reductions)</seealso>.</p>
+ <c>{Total_Reductions, Reductions_Since_Last_Call}</c>.</p>
+ <note>
+ <p>From erts version 5.5 (OTP release R11B)
+ this value does not include reductions performed in current
+ time slices of currently scheduled processes. If an
+ exact value is wanted, use
+ <seealso marker="#statistics_exact_reductions">statistics(exact_reductions)</seealso>.</p>
+ </note>
+ <pre>
+> <input>statistics(reductions).</input>
+{2046,11}
+</pre>
</item>
<tag><c>run_queue</c></tag>
<item>
@@ -4932,20 +4944,72 @@ true</pre>
Note that the run-time is the sum of the run-time for all
threads in the Erlang run-time system and may therefore be greater
than the wall-clock time.</p>
+ <pre>
+> <input>statistics(runtime).</input>
+{1690,1620}
+</pre>
</item>
<tag><marker id="statistics_scheduler_wall_time"><c>scheduler_wall_time</c></marker></tag>
<item>
- <p>Returns
- <c>[{Scheduler_Id, Scheduler_Worked_Time, Scheduler_Total_Time}]</c>, time lapses are since the
- the system flag <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso>
- was set to true.
+ <p>Returns a list of tuples with
+ <c>{SchedulerId, ActiveTime, TotalTime}</c>, where <c>SchedulerId</c> is an integer id of the scheduler, <c>ActiveTime</c> is
+ the duration the scheduler has been busy, <c>TotalTime</c> is the total time duration since
+ <seealso marker="#system_flag_scheduler_wall_time">scheduler_wall_time</seealso>
+ activation. The time unit is not defined and may be subject to change
+ between releases, operating systems and system restarts.
+ <c>scheduler_wall_time</c> should only be used to calculate relative
+ values for scheduler-utilization. <c>ActiveTime</c> can never exceed <c>TotalTime</c>.
+ </p>
+
+ <p>The definition of a busy scheduler is when it is not idle or not
+ scheduling (selecting) a process or port, meaning; executing process
+ code, executing linked-in-driver or NIF code, executing
+ built-in-functions or any other runtime handling, garbage collecting
+ or handling any other memory management. Note, a scheduler may also be
+ busy even if the operating system has scheduled out the scheduler
+ thread.
+ </p>
+
+ <p>
Returns <c>undefined</c> if the system flag <seealso marker="#system_flag_scheduler_wall_time">
- scheduler_wall_time</seealso> is set to false.
+ scheduler_wall_time</seealso> is turned off.
</p>
- <p>The list of scheduler information is unsorted and may come in different order
- between calls. The time unit is undefined and may be changed and should only be used
- to calculate relative utilization.
+
+ <p>The list of scheduler information is unsorted and may appear in different order
+ between calls.
</p>
+ <p>Using <c>scheduler_wall_time</c> to calculate scheduler utilization.</p>
+<pre>
+> <input>erlang:system_flag(scheduler_wall_time, true).</input>
+false
+> <input>Ts0 = lists:sort(erlang:statistics(scheduler_wall_time)), ok.</input>
+ok
+</pre>
+ <p>Some time later we will take another snapshot and calculate scheduler-utilization per scheduler.</p>
+<pre>
+> <input>Ts1 = lists:sort(erlang:statistics(scheduler_wall_time)), ok.</input>
+ok
+> <input>lists:map(fun({{I, A0, T0}, {I, A1, T1}}) ->
+ {I, (A1 - A0)/(T1 - T0)} end, lists:zip(Ts0,Ts1)).</input>
+[{1,0.9743474730177548},
+ {2,0.9744843782751444},
+ {3,0.9995902361669045},
+ {4,0.9738012596572161},
+ {5,0.9717956667018103},
+ {6,0.9739235846420741},
+ {7,0.973237033077876},
+ {8,0.9741297293248656}]
+</pre>
+ <p>Using the same snapshots to calculate a total scheduler-utilization.</p>
+<pre>
+> <input>{A, T} = lists:foldl(fun({{_, A0, T0}, {_, A1, T1}}, {Ai,Ti}) ->
+ {Ai + (A1 - A0), Ti + (T1 - T0)} end, {0, 0}, lists:zip(Ts0,Ts1)), A/T.</input>
+0.9769136803764825
+</pre>
+
+ <note>
+ <p><c>scheduler_wall_time</c> is by default disabled. Use <c>erlang:system_flag(scheduler_wall_time, true)</c> to enable it. </p>
+ </note>
</item>
<tag><c>wall_clock</c></tag>
@@ -4957,14 +5021,6 @@ true</pre>
opposed to runtime or CPU time.</p>
</item>
</taglist>
- <p>All times are in milliseconds.</p>
- <pre>
-> <input>statistics(runtime).</input>
-{1690,1620}
-> <input>statistics(reductions).</input>
-{2046,11}
-> <input>statistics(garbage_collection).</input>
-{85,23961,0}</pre>
</desc>
</func>
<func>
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in
index 2bd7297231..279844adb2 100644
--- a/erts/emulator/Makefile.in
+++ b/erts/emulator/Makefile.in
@@ -546,12 +546,17 @@ $(TTF_DIR)/driver_tab.c: Makefile.in
LANG=C $(PERL) utils/make_driver_tab -o $@ $(DRV_OBJS)
GENERATE += $(TTF_DIR)/driver_tab.c
+
+
# Preloaded code.
#
# This list must be consistent with PRE_LOADED_MODULES in
# lib/kernel/src/Makefile.
ifeq ($(TARGET),win32)
-$(TARGET)/beams.rc: $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
+# On windows the preloaded objects are in a resource object.
+PRELOAD_OBJ = $(OBJDIR)/beams.$(RES_EXT)
+PRELOAD_SRC = $(TARGET)/beams.rc
+$(PRELOAD_SRC): $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
$(ERL_TOP)/erts/preloaded/ebin/init.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_inet.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_file.beam \
@@ -560,9 +565,10 @@ $(TARGET)/beams.rc: $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
$(ERL_TOP)/erts/preloaded/ebin/erl_prim_loader.beam \
$(ERL_TOP)/erts/preloaded/ebin/erlang.beam
LANG=C $(PERL) utils/make_preload $(MAKE_PRELOAD_EXTRA) -rc $^ > $@
-GENERATE += $(TARGET)/beams.rc
else
-$(TARGET)/preload.c: $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
+PRELOAD_OBJ = $(OBJDIR)/preload.o
+PRELOAD_SRC = $(TARGET)/preload.c
+$(PRELOAD_SRC): $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
$(ERL_TOP)/erts/preloaded/ebin/init.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_inet.beam \
$(ERL_TOP)/erts/preloaded/ebin/prim_file.beam \
@@ -571,7 +577,6 @@ $(TARGET)/preload.c: $(ERL_TOP)/erts/preloaded/ebin/otp_ring0.beam \
$(ERL_TOP)/erts/preloaded/ebin/erl_prim_loader.beam \
$(ERL_TOP)/erts/preloaded/ebin/erlang.beam
LANG=C $(PERL) utils/make_preload -old $^ > $@
-GENERATE += $(TARGET)/preload.c
endif
.PHONY : generate
@@ -579,7 +584,8 @@ ifdef VOID_EMULATOR
generate:
@echo $(VOID_EMULATOR)' - omitted target generate'
else
-generate: $(TTF_DIR)/GENERATED
+generate: $(TTF_DIR)/GENERATED $(PRELOAD_SRC)
+
$(TTF_DIR)/GENERATED: $(GENERATE)
echo $? >$(TTF_DIR)/GENERATED
endif
@@ -660,7 +666,7 @@ endif
#
CS_SRC = sys/$(ERLANG_OSTYPE)/erl_child_setup.c
-$(BINDIR)/$(CS_EXECUTABLE): $(TTF_DIR)/GENERATED $(CS_SRC) $(ERTS_LIB)
+$(BINDIR)/$(CS_EXECUTABLE): $(TTF_DIR)/GENERATED $(PRELOAD_SRC) $(CS_SRC) $(ERTS_LIB)
$(CS_PURIFY) $(CC) $(CS_LDFLAGS) -o $(BINDIR)/$(CS_EXECUTABLE) \
$(CS_CFLAGS) $(COMMON_INCLUDES) $(CS_SRC) $(CS_LIBS)
@@ -689,16 +695,7 @@ $(ERL_TOP)/lib/%.beam:
# Object files
#
-# On windows the preloaded objects are in a resource object.
-
-ifeq ($(TARGET),win32)
-PRELOAD = $(OBJDIR)/beams.$(RES_EXT)
-else
-PRELOAD = $(OBJDIR)/preload.o
-endif
-
-
-INIT_OBJS = $(OBJDIR)/erl_main.o $(PRELOAD)
+INIT_OBJS = $(OBJDIR)/erl_main.o $(PRELOAD_OBJ)
EMU_OBJS = \
$(OBJDIR)/beam_emu.o $(OBJDIR)/beam_opcodes.o \
@@ -1035,7 +1032,7 @@ depend:
@echo $(VOID_EMULATOR)' - omitted target depend'
else
depend: $(TTF_DIR)/depend.mk
-$(TTF_DIR)/depend.mk: $(TTF_DIR)/GENERATED
+$(TTF_DIR)/depend.mk: $(TTF_DIR)/GENERATED $(PRELOAD_SRC)
$(DEP_CC) $(DEP_FLAGS) $(BEAM_SRC) \
| $(SED_DEPEND) > $(TTF_DIR)/depend.mk
$(DEP_CC) $(DEP_FLAGS) -DLIBSCTP=$(LIBSCTP) $(DRV_COMMON_SRC) \
diff --git a/erts/emulator/beam/erl_thr_progress.h b/erts/emulator/beam/erl_thr_progress.h
index 1bbc49993e..a71724b813 100644
--- a/erts/emulator/beam/erl_thr_progress.h
+++ b/erts/emulator/beam/erl_thr_progress.h
@@ -138,6 +138,7 @@ ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_prgr_read_acqb__(ERTS_THR_PRGR_ATOMIC *a
ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_prgr_read_mb__(ERTS_THR_PRGR_ATOMIC *atmc);
ERTS_GLB_INLINE int erts_thr_progress_is_managed_thread(void);
+ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_progress_current_to_later__(ErtsThrPrgrVal val);
ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_progress_later_than(ErtsThrPrgrVal val);
ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_progress_later(void);
ERTS_GLB_INLINE ErtsThrPrgrVal erts_thr_progress_current(void);
@@ -218,9 +219,8 @@ erts_thr_progress_is_managed_thread(void)
}
ERTS_GLB_INLINE ErtsThrPrgrVal
-erts_thr_progress_later_than(ErtsThrPrgrVal val)
+erts_thr_progress_current_to_later__(ErtsThrPrgrVal val)
{
- ERTS_THR_MEMORY_BARRIER;
if (val == (ERTS_THR_PRGR_VAL_WAITING-((ErtsThrPrgrVal)2)))
return ((ErtsThrPrgrVal) 0);
else if (val == (ERTS_THR_PRGR_VAL_WAITING-((ErtsThrPrgrVal)1)))
@@ -230,10 +230,17 @@ erts_thr_progress_later_than(ErtsThrPrgrVal val)
}
ERTS_GLB_INLINE ErtsThrPrgrVal
+erts_thr_progress_later_than(ErtsThrPrgrVal val)
+{
+ ERTS_THR_MEMORY_BARRIER;
+ return erts_thr_progress_current_to_later__(val);
+}
+
+ERTS_GLB_INLINE ErtsThrPrgrVal
erts_thr_progress_later(void)
{
ErtsThrPrgrVal val = erts_thr_prgr_read_mb__(&erts_thr_prgr__.current);
- return erts_thr_progress_later_than(val);
+ return erts_thr_progress_current_to_later__(val);
}
ERTS_GLB_INLINE ErtsThrPrgrVal
diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c
index b23b1f628d..fe1a7ba345 100644
--- a/erts/emulator/beam/io.c
+++ b/erts/emulator/beam/io.c
@@ -743,7 +743,7 @@ driver_create_port(ErlDrvPort creator_port_ix, /* Creating port */
return (ErlDrvTermData) -1; /* pid does not exist */
}
if ((port_num = get_free_port()) < 0) {
- errno = ENFILE;
+ errno = SYSTEM_LIMIT;
erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
erts_smp_mtx_unlock(&erts_driver_list_lock);
return (ErlDrvTermData) -1;
diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c
index 36ed108b76..a251b064da 100644
--- a/erts/emulator/drivers/common/efile_drv.c
+++ b/erts/emulator/drivers/common/efile_drv.c
@@ -156,11 +156,11 @@ static ErlDrvSysInfo sys_info;
* DARWIN. The testcase t_sendfile_crashduring reproduces
* this error when using +A 10.
*/
-#if !defined(DARWIN)
-#define USE_THRDS_FOR_SENDFILE (sys_info.async_threads > 0)
-#else
+#if defined(__APPLE__) && defined(__MACH__)
#define USE_THRDS_FOR_SENDFILE 0
-#endif /* !DARWIN */
+#else
+#define USE_THRDS_FOR_SENDFILE (sys_info.async_threads > 0)
+#endif /* defined(__APPLE__) && defined(__MACH__) */
@@ -259,6 +259,7 @@ static void file_stop_select(ErlDrvEvent event, void* _);
enum e_timer {timer_idle, timer_again, timer_write};
#ifdef HAVE_SENDFILE
enum e_sendfile {sending, not_sending};
+static void free_sendfile(void *data);
#endif /* HAVE_SENDFILE */
struct t_data;
@@ -445,6 +446,8 @@ struct t_data
} fadvise;
#ifdef HAVE_SENDFILE
struct {
+ ErlDrvPort port;
+ ErlDrvPDL q_mtx;
int out_fd;
off_t offset;
Uint64 nbytes;
@@ -752,15 +755,6 @@ file_stop(ErlDrvData e)
TRACE_C('p');
-#ifdef HAVE_SENDFILE
- if (desc->sendfile_state == sending && !USE_THRDS_FOR_SENDFILE) {
- driver_select(desc->port,(ErlDrvEvent)(long)desc->d->c.sendfile.out_fd,
- ERL_DRV_WRITE|ERL_DRV_USE,0);
- } else if (desc->sendfile_state == sending) {
- SET_NONBLOCKING(desc->d->c.sendfile.out_fd);
- }
-#endif /* HAVE_SENDFILE */
-
if (desc->fd != FILE_FD_INVALID) {
do_close(desc->flags, desc->fd);
desc->fd = FILE_FD_INVALID;
@@ -1783,26 +1777,31 @@ static void invoke_sendfile(void *data)
d->c.sendfile.written += nbytes;
- if (result == 1) {
- if (USE_THRDS_FOR_SENDFILE) {
- d->result_ok = 0;
- } else if (d->c.sendfile.nbytes == 0 && nbytes != 0) {
- d->result_ok = 1;
- } else if ((d->c.sendfile.nbytes - nbytes) != 0) {
- d->result_ok = 1;
- d->c.sendfile.nbytes -= nbytes;
- } else {
- d->result_ok = 0;
- }
+ if (result == 1 || (result == 0 && USE_THRDS_FOR_SENDFILE)) {
+ d->result_ok = 0;
} else if (result == 0 && (d->errInfo.posix_errno == EAGAIN
|| d->errInfo.posix_errno == EINTR)) {
+ if ((d->c.sendfile.nbytes - nbytes) != 0) {
d->result_ok = 1;
+ if (d->c.sendfile.nbytes != 0)
+ d->c.sendfile.nbytes -= nbytes;
+ } else
+ d->result_ok = 0;
} else {
d->result_ok = -1;
}
}
static void free_sendfile(void *data) {
+ struct t_data *d = (struct t_data *)data;
+ if (USE_THRDS_FOR_SENDFILE) {
+ SET_NONBLOCKING(d->c.sendfile.out_fd);
+ } else {
+ MUTEX_LOCK(d->c.sendfile.q_mtx);
+ driver_deq(d->c.sendfile.port,1);
+ MUTEX_UNLOCK(d->c.sendfile.q_mtx);
+ driver_select(d->c.sendfile.port, (ErlDrvEvent)(long)d->c.sendfile.out_fd, ERL_DRV_USE_NO_CALLBACK|ERL_DRV_WRITE, 0);
+ }
EF_FREE(data);
}
@@ -1812,7 +1811,7 @@ static void file_ready_output(ErlDrvData data, ErlDrvEvent event)
switch (fd->d->command) {
case FILE_SENDFILE:
- driver_select(fd->port, event,
+ driver_select(fd->d->c.sendfile.port, event,
(int)ERL_DRV_WRITE,(int) 0);
invoke_sendfile((void *)fd->d);
file_async_ready(data, (ErlDrvThreadData)fd->d);
@@ -1826,6 +1825,15 @@ static void file_stop_select(ErlDrvEvent event, void* _)
{
}
+
+static int flush_sendfile(file_descriptor *desc,void *_) {
+ if (desc->sendfile_state == sending) {
+ desc->d->result_ok = -1;
+ desc->d->errInfo.posix_errno = ECONNABORTED;
+ file_async_ready((ErlDrvData)desc,(ErlDrvThreadData)desc->d);
+ }
+ return 1;
+}
#endif /* HAVE_SENDFILE */
@@ -2248,36 +2256,23 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data)
#ifdef HAVE_SENDFILE
case FILE_SENDFILE:
if (d->result_ok == -1) {
- desc->sendfile_state = not_sending;
if (d->errInfo.posix_errno == ECONNRESET ||
d->errInfo.posix_errno == ENOTCONN ||
d->errInfo.posix_errno == EPIPE)
reply_string_error(desc,"closed");
else
reply_error(desc, &d->errInfo);
- if (USE_THRDS_FOR_SENDFILE) {
- SET_NONBLOCKING(d->c.sendfile.out_fd);
- free_sendfile(data);
- } else {
- driver_select(desc->port, (ErlDrvEvent)(long)d->c.sendfile.out_fd,
- ERL_DRV_USE, 0);
- free_sendfile(data);
- }
- } else if (d->result_ok == 0) {
desc->sendfile_state = not_sending;
+ free_sendfile(data);
+ } else if (d->result_ok == 0) {
reply_Sint64(desc, d->c.sendfile.written);
- if (USE_THRDS_FOR_SENDFILE) {
- SET_NONBLOCKING(d->c.sendfile.out_fd);
- free_sendfile(data);
- } else {
- driver_select(desc->port, (ErlDrvEvent)(long)d->c.sendfile.out_fd, ERL_DRV_USE, 0);
- free_sendfile(data);
- }
+ desc->sendfile_state = not_sending;
+ free_sendfile(data);
} else if (d->result_ok == 1) { // If we are using select to send the rest of the data
desc->sendfile_state = sending;
desc->d = d;
driver_select(desc->port, (ErlDrvEvent)(long)d->c.sendfile.out_fd,
- ERL_DRV_USE|ERL_DRV_WRITE, 1);
+ ERL_DRV_USE_NO_CALLBACK|ERL_DRV_WRITE, 1);
}
break;
#endif
@@ -2655,6 +2650,10 @@ file_flush(ErlDrvData e) {
TRACE_C('f');
+#ifdef HAVE_SENDFILE
+ flush_sendfile(desc, NULL);
+#endif
+
#ifdef DEBUG
r =
#endif
@@ -3454,11 +3453,13 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
d->fd = desc->fd;
d->command = command;
d->invoke = invoke_sendfile;
- d->free = NULL;
+ d->free = free_sendfile;
d->level = 2;
d->c.sendfile.out_fd = (int) out_fd;
d->c.sendfile.written = 0;
+ d->c.sendfile.port = desc->port;
+ d->c.sendfile.q_mtx = desc->q_mtx;
#if SIZEOF_OFF_T == 4
if (offsetH != 0) {
@@ -3474,6 +3475,19 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) {
if (USE_THRDS_FOR_SENDFILE) {
SET_BLOCKING(d->c.sendfile.out_fd);
+ } else {
+ /**
+ * Write a place holder to queue in order to force file_flush
+ * to be called before the driver is closed.
+ */
+ char tmp[1] = "";
+ MUTEX_LOCK(d->c.sendfile.q_mtx);
+ if (driver_enq(d->c.sendfile.port, tmp, 1)) {
+ MUTEX_UNLOCK(d->c.sendfile.q_mtx);
+ reply_posix_error(desc, ENOMEM);
+ goto done;
+ }
+ MUTEX_UNLOCK(d->c.sendfile.q_mtx);
}
cq_enq(desc, d);
diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c
index 47a99fdbe6..d1c2dbf94c 100644
--- a/erts/emulator/drivers/common/inet_drv.c
+++ b/erts/emulator/drivers/common/inet_drv.c
@@ -553,6 +553,12 @@ static int my_strncasecmp(const char *s1, const char *s2, size_t n)
# define VALGRIND_MAKE_MEM_DEFINED(ptr,size)
#endif
+/*
+ Magic errno value used locally for return of {error, system_limit}
+ - the emulator definition of SYSTEM_LIMIT is not available here.
+*/
+#define INET_ERRNO_SYSTEM_LIMIT (15 << 8)
+
/*----------------------------------------------------------------------------
** Interface constants.
**
@@ -1645,6 +1651,17 @@ static struct erl_drv_entry dummy_sctp_driver_entry =
#endif
+/* return lowercase string form of errno value */
+static char *errno_str(int err)
+{
+ switch (err) {
+ case INET_ERRNO_SYSTEM_LIMIT:
+ return "system_limit";
+ default:
+ return erl_errno_id(err);
+ }
+}
+
/* general control reply function */
static ErlDrvSSizeT ctl_reply(int rep, char* buf, ErlDrvSizeT len,
char** rbuf, ErlDrvSizeT rsize)
@@ -1665,13 +1682,9 @@ static ErlDrvSSizeT ctl_reply(int rep, char* buf, ErlDrvSizeT len,
/* general control error reply function */
static ErlDrvSSizeT ctl_error(int err, char** rbuf, ErlDrvSizeT rsize)
{
- char response[256]; /* Response buffer. */
- char* s;
- char* t;
+ char* s = errno_str(err);
- for (s = erl_errno_id(err), t = response; *s; s++, t++)
- *t = tolower(*s);
- return ctl_reply(INET_REP_ERROR, response, t-response, rbuf, rsize);
+ return ctl_reply(INET_REP_ERROR, s, strlen(s), rbuf, rsize);
}
static ErlDrvSSizeT ctl_xerror(char* xerr, char** rbuf, ErlDrvSizeT rsize)
@@ -1683,14 +1696,7 @@ static ErlDrvSSizeT ctl_xerror(char* xerr, char** rbuf, ErlDrvSizeT rsize)
static ErlDrvTermData error_atom(int err)
{
- char errstr[256];
- char* s;
- char* t;
-
- for (s = erl_errno_id(err), t = errstr; *s; s++, t++)
- *t = tolower(*s);
- *t = '\0';
- return driver_mk_atom(errstr);
+ return driver_mk_atom(errno_str(err));
}
@@ -4089,6 +4095,7 @@ static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr)
addr->sa_family = AF_INET;
return ptr + sizeof(struct in_addr);
}
+#if defined(HAVE_IN6) && defined(AF_INET6)
case INET_AF_INET6: {
struct in6_addr *p = &((struct sockaddr_in6*)addr)->sin6_addr;
buf_check(ptr,end,sizeof(struct in6_addr));
@@ -4096,6 +4103,7 @@ static char* buf_to_sockaddr(char* ptr, char* end, struct sockaddr* addr)
addr->sa_family = AF_INET6;
return ptr + sizeof(struct in6_addr);
}
+#endif
}
error:
return NULL;
@@ -8051,7 +8059,7 @@ static ErlDrvData tcp_inet_start(ErlDrvPort port, char* args)
/* Copy a descriptor, by creating a new port with same settings
* as the descriptor desc.
- * return NULL on error (ENFILE no ports avail)
+ * return NULL on error (SYSTEM_LIMIT no ports avail)
*/
static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s,
ErlDrvTermData owner, int* err)
@@ -8090,7 +8098,7 @@ static tcp_descriptor* tcp_inet_copy(tcp_descriptor* desc,SOCKET s,
/* The new port will be linked and connected to the original caller */
port = driver_create_port(port, owner, "tcp_inet", (ErlDrvData) copy_desc);
if ((long)port == -1) {
- *err = ENFILE;
+ *err = INET_ERRNO_SYSTEM_LIMIT;
FREE(copy_desc);
return NULL;
}
diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c
index da4a17db1a..a4b02b845e 100644
--- a/erts/emulator/drivers/common/zlib_drv.c
+++ b/erts/emulator/drivers/common/zlib_drv.c
@@ -64,6 +64,7 @@
static int zlib_init(void);
static ErlDrvData zlib_start(ErlDrvPort port, char* buf);
static void zlib_stop(ErlDrvData e);
+static void zlib_flush(ErlDrvData e);
static ErlDrvSSizeT zlib_ctl(ErlDrvData drv_data, unsigned int command, char *buf,
ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen);
static void zlib_outputv(ErlDrvData drv_data, ErlIOVec *ev);
@@ -82,7 +83,7 @@ ErlDrvEntry zlib_driver_entry = {
NULL, /* timeout */
zlib_outputv,
NULL, /* read_async */
- NULL, /* flush */
+ zlib_flush,
NULL, /* call */
NULL, /* event */
ERL_DRV_EXTENDED_MARKER,
@@ -410,6 +411,13 @@ static void zlib_stop(ErlDrvData e)
driver_free(d);
}
+static void zlib_flush(ErlDrvData drv_data)
+{
+ ZLibData* d = (ZLibData*) drv_data;
+
+ driver_deq(d->port, driver_sizeq(d->port));
+}
+
static ErlDrvSSizeT zlib_ctl(ErlDrvData drv_data, unsigned int command, char *buf,
ErlDrvSizeT len, char **rbuf, ErlDrvSizeT rlen)
{
diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c
index 796843a735..dfb6cece14 100644
--- a/erts/emulator/drivers/unix/unix_efile.c
+++ b/erts/emulator/drivers/unix/unix_efile.c
@@ -1426,6 +1426,14 @@ efile_fadvise(Efile_error* errInfo, int fd, Sint64 offset,
* you would have to emulate it in linux and on BSD/Darwin some complex
* calculations have to be made when using a non blocking socket to figure
* out how much of the header/file/trailer was sent in each command.
+ *
+ * The semantics of the API is this:
+ * Return value: 1 if all data was sent and the function does not need to
+ * be called again. 0 if an error occures OR if there is more data which
+ * has to be sent (EAGAIN or EINTR will be set appropriately)
+ *
+ * The amount of data written in a call is returned through nbytes.
+ *
*/
int
@@ -1446,8 +1454,11 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
*nbytes -= retval;
}
} while (retval == SENDFILE_CHUNK_SIZE);
- *nbytes = written;
- return check_error(retval == -1 ? -1 : 0, errInfo);
+ if (written != 0) {
+ // -1 is not returned by the linux API so we have to simulate it
+ retval = -1;
+ errno = EAGAIN;
+ }
#elif defined(__sun) && defined(__SVR4) && defined(HAVE_SENDFILEV)
ssize_t retval;
size_t len;
@@ -1469,8 +1480,6 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
written += len;
}
} while (len == SENDFILE_CHUNK_SIZE);
- *nbytes = written;
- return check_error(retval == -1 ? -1 : 0, errInfo);
#elif defined(DARWIN)
int retval;
off_t len;
@@ -1487,8 +1496,6 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
written += len;
}
} while (len == SENDFILE_CHUNK_SIZE);
- *nbytes = written;
- return check_error(retval, errInfo);
#elif defined(__FreeBSD__) || defined(__DragonFly__)
off_t len;
int retval;
@@ -1504,8 +1511,8 @@ efile_sendfile(Efile_error* errInfo, int in_fd, int out_fd,
written += len;
}
} while(len == SENDFILE_CHUNK_SIZE);
+#endif
*nbytes = written;
return check_error(retval, errInfo);
-#endif
}
#endif /* HAVE_SENDFILE */
diff --git a/erts/emulator/test/erts_debug_SUITE.erl b/erts/emulator/test/erts_debug_SUITE.erl
index 4dc2fbaae2..76667772c7 100644
--- a/erts/emulator/test/erts_debug_SUITE.erl
+++ b/erts/emulator/test/erts_debug_SUITE.erl
@@ -23,13 +23,13 @@
-export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1,
init_per_group/2,end_per_group/2,
init_per_testcase/2,end_per_testcase/2,
- flat_size/1,flat_size_big/1,df/1,
+ test_size/1,flat_size_big/1,df/1,
instructions/1]).
suite() -> [{ct_hooks,[ts_install_cth]}].
all() ->
- [flat_size, flat_size_big, df, instructions].
+ [test_size, flat_size_big, df, instructions].
groups() ->
[].
@@ -55,16 +55,58 @@ end_per_testcase(_Func, Config) ->
Dog=?config(watchdog, Config),
?t:timetrap_cancel(Dog).
-flat_size(Config) when is_list(Config) ->
- 0 = erts_debug:flat_size([]),
- 0 = erts_debug:flat_size(42),
- 2 = erts_debug:flat_size([a|b]),
- 1 = erts_debug:flat_size({}),
- 2 = erts_debug:flat_size({[]}),
- 3 = erts_debug:flat_size({a,b}),
- 7 = erts_debug:flat_size({a,[b,c]}),
+test_size(Config) when is_list(Config) ->
+ ConsCell1 = id([a|b]),
+ ConsCell2 = id(ConsCell1),
+ ConsCellSz = 2,
+
+ 0 = do_test_size([]),
+ 0 = do_test_size(42),
+ ConsCellSz = do_test_size(ConsCell1),
+ 1 = do_test_size({}),
+ 2 = do_test_size({[]}),
+ 3 = do_test_size({a,b}),
+ 7 = do_test_size({a,[b,c]}),
+
+ %% Test internal consistency of sizes, but without testing
+ %% exact sizes.
+ Const = id(42),
+ AnotherConst = id(7),
+
+ %% Fun environment size = 0 (the smallest fun possible)
+ SimplestFun = fun() -> ok end,
+ FunSz0 = do_test_size(SimplestFun),
+
+ %% Fun environment size = 1
+ FunSz1 = do_test_size(fun() -> Const end),
+ FunSz1 = FunSz0 + 1,
+
+ %% Fun environment size = 2
+ FunSz2 = do_test_size(fun() -> Const+AnotherConst end),
+ FunSz2 = FunSz1 + 1,
+
+ FunSz1 = do_test_size(fun() -> ConsCell1 end) - do_test_size(ConsCell1),
+
+ %% Test shared data structures.
+ do_test_size([ConsCell1|ConsCell1],
+ 3*ConsCellSz,
+ 2*ConsCellSz),
+ do_test_size(fun() -> {ConsCell1,ConsCell2} end,
+ FunSz2 + 2*ConsCellSz,
+ FunSz2 + ConsCellSz),
+ do_test_size({SimplestFun,SimplestFun},
+ 2*FunSz0+do_test_size({a,b}),
+ FunSz0+do_test_size({a,b})),
ok.
+do_test_size(Term) ->
+ Sz = erts_debug:flat_size(Term),
+ Sz = erts_debug:size(Term).
+
+do_test_size(Term, FlatSz, Sz) ->
+ FlatSz = erts_debug:flat_size(Term),
+ Sz = erts_debug:size(Term).
+
flat_size_big(Config) when is_list(Config) ->
%% Build a term whose external size only fits in a big num (on 32-bit CPU).
flat_size_big_1(16#11111111111111117777777777777777888889999, 0, 16#FFFFFFF).
@@ -96,3 +138,6 @@ instructions(Config) when is_list(Config) ->
?line Is = erts_debug:instructions(),
?line _ = [list_to_atom(I) || I <- Is],
ok.
+
+id(I) ->
+ I.
diff --git a/erts/etc/common/escript.c b/erts/etc/common/escript.c
index 6ed79c91e3..e70c95b67c 100644
--- a/erts/etc/common/escript.c
+++ b/erts/etc/common/escript.c
@@ -377,7 +377,8 @@ main(int argc, char** argv)
last_opt = argv;
#ifdef __WIN32__
- if (_stricmp(basename, "escript.exe") == 0) {
+ if ( (_stricmp(basename, "escript.exe") == 0)
+ ||(_stricmp(basename, "escript") == 0)) {
#else
if (strcmp(basename, "escript") == 0) {
#endif
diff --git a/erts/etc/unix/etp-commands b/erts/etc/unix/etp-commands
index 6a01e0b7e0..79e5d6b1d8 100644
--- a/erts/etc/unix/etp-commands
+++ b/erts/etc/unix/etp-commands
@@ -1883,6 +1883,28 @@ document etp-ets-tables
%---------------------------------------------------------------------------
end
+define etp-ets-obj
+# Args: DbTerm*
+#
+ set $etp_ets_obj_i = 1
+ while $etp_ets_obj_i <= (($arg0)->tpl[0] >> 6)
+ if $etp_ets_obj_i == 1
+ printf "{"
+ else
+ printf ", "
+ end
+ set $etp_ets_elem = ($arg0)->tpl[$etp_ets_obj_i]
+ if ($etp_ets_elem & 3) == 0
+ printf "<compressed>"
+ else
+ etp-1 $etp_ets_elem 0
+ end
+ set $etp_ets_obj_i++
+ end
+ printf "}"
+end
+
+
define etp-ets-tabledump
# Args: int tableindex
#
@@ -1896,10 +1918,10 @@ define etp-ets-tabledump
if $etp_ets_tabledump_t->common.status & 0x130
# Hash table
set $etp_ets_tabledump_h = $etp_ets_tabledump_t->hash
- printf "%% nitems=%d\n", $etp_ets_tabledump_t->common.nitems
- while $etp_ets_tabledump_i < $etp_ets_tabledump_h->nactive
- set $etp_ets_tabledump_l = $etp_ets_tabledump_h->seg \
- [$etp_ets_tabledump_i>>8][$etp_ets_tabledump_i&0xFF]
+ printf "%% nitems=%d\n", (long) $etp_ets_tabledump_t->common.nitems
+ while $etp_ets_tabledump_i < (long) $etp_ets_tabledump_h->nactive
+ set $etp_ets_tabledump_seg = ((struct segment**)$etp_ets_tabledump_h->segtab)[$etp_ets_tabledump_i>>8]
+ set $etp_ets_tabledump_l = $etp_ets_tabledump_seg->buckets[$etp_ets_tabledump_i&0xFF]
if $etp_ets_tabledump_l
printf "%% Slot %d:\n", $etp_ets_tabledump_i
while $etp_ets_tabledump_l
@@ -1909,7 +1931,7 @@ define etp-ets-tabledump
printf "["
end
set $etp_ets_tabledump_n++
- etp-1 ((Eterm)($etp_ets_tabledump_l->dbterm.tpl)|0x2) 0
+ etp-ets-obj &($etp_ets_tabledump_l->dbterm)
if $etp_ets_tabledump_l->hvalue == ((unsigned long)-1)
printf "% *\n"
else
diff --git a/erts/lib_src/common/erl_misc_utils.c b/erts/lib_src/common/erl_misc_utils.c
index 5e94ff19db..162c908285 100644
--- a/erts/lib_src/common/erl_misc_utils.c
+++ b/erts/lib_src/common/erl_misc_utils.c
@@ -727,7 +727,7 @@ adjust_processor_nodes(erts_cpu_info_t *cpuinfo, int no_nodes)
prev = NULL;
this = &cpuinfo->topology[0];
- last = &cpuinfo->topology[cpuinfo->configured-1];
+ last = &cpuinfo->topology[cpuinfo->topology_size-1];
while (1) {
if (processor == this->processor) {
if (node != this->node)
@@ -834,8 +834,8 @@ read_topology(erts_cpu_info_t *cpuinfo)
ix = -1;
if (realpath(ERTS_SYS_NODE_PATH, npath)) {
- got_nodes = 1;
ndir = opendir(npath);
+ got_nodes = (ndir != NULL);
}
do {
@@ -939,7 +939,7 @@ read_topology(erts_cpu_info_t *cpuinfo)
if (res > 1) {
prev = this++;
- last = &cpuinfo->topology[cpuinfo->configured-1];
+ last = &cpuinfo->topology[cpuinfo->topology_size-1];
while (1) {
this->thread = ((this->node == prev->node
@@ -1094,7 +1094,7 @@ read_topology(erts_cpu_info_t *cpuinfo)
if (res > 1) {
prev = this++;
- last = &cpuinfo->topology[cpuinfo->configured-1];
+ last = &cpuinfo->topology[cpuinfo->topology_size-1];
while (1) {
this->thread = ((this->node == prev->node
diff --git a/erts/lib_src/common/ethr_atomics.c b/erts/lib_src/common/ethr_atomics.c
index e4213e1eef..c52166a7ec 100644
--- a/erts/lib_src/common/ethr_atomics.c
+++ b/erts/lib_src/common/ethr_atomics.c
@@ -561,12 +561,14 @@ int ethr_dw_atomic_cmpxchg(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_s
}
#endif
-int ETHR_DW_ATOMIC_FUNC__(cmpxchg_ddrb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val)
+int ethr_dw_atomic_cmpxchg_ddrb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val, ethr_dw_sint_t *old_val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
- return ETHR_DW_ATOMIC_FUNC__(cmpxchg)(var, val, old_val);
+#if defined(ETHR_HAVE_DOUBLE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ return ethr_dw_atomic_cmpxchg_ddrb__(var, val, old_val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
+ return ethr_dw_atomic_cmpxchg(var, val, old_val);
#else
- return ETHR_DW_ATOMIC_FUNC__(cmpxchg_rb)(var, val, old_val);
+ return ethr_dw_atomic_cmpxchg_rb(var, val, old_val);
#endif
}
@@ -784,12 +786,14 @@ void ethr_dw_atomic_set(ethr_dw_atomic_t *var, ethr_dw_sint_t *val)
}
#endif
-void ETHR_DW_ATOMIC_FUNC__(set_ddrb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val)
+void ethr_dw_atomic_set_ddrb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
- ETHR_DW_ATOMIC_FUNC__(set)(var, val);
+#if defined(ETHR_HAVE_DOUBLE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ ethr_dw_atomic_set_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
+ ethr_dw_atomic_set(var, val);
#else
- ETHR_DW_ATOMIC_FUNC__(set_rb)(var, val);
+ ethr_dw_atomic_set_rb(var, val);
#endif
}
@@ -947,12 +951,14 @@ void ethr_dw_atomic_read(ethr_dw_atomic_t *var, ethr_dw_sint_t *val)
}
#endif
-void ETHR_DW_ATOMIC_FUNC__(read_ddrb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val)
+void ethr_dw_atomic_read_ddrb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
- ETHR_DW_ATOMIC_FUNC__(read)(var, val);
+#if defined(ETHR_HAVE_DOUBLE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ ethr_dw_atomic_read_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
+ ethr_dw_atomic_read(var, val);
#else
- ETHR_DW_ATOMIC_FUNC__(read_rb)(var, val);
+ ethr_dw_atomic_read_rb(var, val);
#endif
}
@@ -1107,12 +1113,14 @@ void ethr_dw_atomic_init(ethr_dw_atomic_t *var, ethr_dw_sint_t *val)
}
#endif
-void ETHR_DW_ATOMIC_FUNC__(init_ddrb)(ethr_dw_atomic_t *var, ethr_dw_sint_t *val)
+void ethr_dw_atomic_init_ddrb(ethr_dw_atomic_t *var, ethr_dw_sint_t *val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
- ETHR_DW_ATOMIC_FUNC__(init)(var, val);
+#if defined(ETHR_HAVE_DOUBLE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ ethr_dw_atomic_init_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
+ ethr_dw_atomic_init(var, val);
#else
- ETHR_DW_ATOMIC_FUNC__(init_rb)(var, val);
+ ethr_dw_atomic_init_rb(var, val);
#endif
}
@@ -1278,7 +1286,9 @@ ethr_sint_t ethr_atomic_cmpxchg(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t
ethr_sint_t ethr_atomic_cmpxchg_ddrb(ethr_atomic_t *var, ethr_sint_t val, ethr_sint_t old_val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ return ethr_atomic_cmpxchg_ddrb__(var, val, old_val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic_cmpxchg(var, val, old_val);
#else
return ethr_atomic_cmpxchg_rb(var, val, old_val);
@@ -1398,7 +1408,9 @@ ethr_sint_t ethr_atomic_xchg(ethr_atomic_t *var, ethr_sint_t val)
ethr_sint_t ethr_atomic_xchg_ddrb(ethr_atomic_t *var, ethr_sint_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ return ethr_atomic_xchg_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic_xchg(var, val);
#else
return ethr_atomic_xchg_rb(var, val);
@@ -1512,7 +1524,9 @@ void ethr_atomic_set(ethr_atomic_t *var, ethr_sint_t val)
void ethr_atomic_set_ddrb(ethr_atomic_t *var, ethr_sint_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ ethr_atomic_set_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
ethr_atomic_set(var, val);
#else
ethr_atomic_set_rb(var, val);
@@ -1620,7 +1634,9 @@ void ethr_atomic_init(ethr_atomic_t *var, ethr_sint_t val)
void ethr_atomic_init_ddrb(ethr_atomic_t *var, ethr_sint_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ ethr_atomic_init_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
ethr_atomic_init(var, val);
#else
ethr_atomic_init_rb(var, val);
@@ -1725,7 +1741,9 @@ ethr_sint_t ethr_atomic_add_read(ethr_atomic_t *var, ethr_sint_t val)
ethr_sint_t ethr_atomic_add_read_ddrb(ethr_atomic_t *var, ethr_sint_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ return ethr_atomic_add_read_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic_add_read(var, val);
#else
return ethr_atomic_add_read_rb(var, val);
@@ -1840,7 +1858,9 @@ ethr_sint_t ethr_atomic_read(ethr_atomic_t *var)
ethr_sint_t ethr_atomic_read_ddrb(ethr_atomic_t *var)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ return ethr_atomic_read_ddrb__(var);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic_read(var);
#else
return ethr_atomic_read_rb(var);
@@ -1954,7 +1974,9 @@ ethr_sint_t ethr_atomic_inc_read(ethr_atomic_t *var)
ethr_sint_t ethr_atomic_inc_read_ddrb(ethr_atomic_t *var)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ return ethr_atomic_inc_read_ddrb__(var);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic_inc_read(var);
#else
return ethr_atomic_inc_read_rb(var);
@@ -2069,7 +2091,9 @@ ethr_sint_t ethr_atomic_dec_read(ethr_atomic_t *var)
ethr_sint_t ethr_atomic_dec_read_ddrb(ethr_atomic_t *var)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ return ethr_atomic_dec_read_ddrb__(var);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic_dec_read(var);
#else
return ethr_atomic_dec_read_rb(var);
@@ -2183,7 +2207,9 @@ void ethr_atomic_add(ethr_atomic_t *var, ethr_sint_t val)
void ethr_atomic_add_ddrb(ethr_atomic_t *var, ethr_sint_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ ethr_atomic_add_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
ethr_atomic_add(var, val);
#else
ethr_atomic_add_rb(var, val);
@@ -2292,7 +2318,9 @@ void ethr_atomic_inc(ethr_atomic_t *var)
void ethr_atomic_inc_ddrb(ethr_atomic_t *var)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ ethr_atomic_inc_ddrb__(var);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
ethr_atomic_inc(var);
#else
ethr_atomic_inc_rb(var);
@@ -2401,7 +2429,9 @@ void ethr_atomic_dec(ethr_atomic_t *var)
void ethr_atomic_dec_ddrb(ethr_atomic_t *var)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ ethr_atomic_dec_ddrb__(var);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
ethr_atomic_dec(var);
#else
ethr_atomic_dec_rb(var);
@@ -2511,7 +2541,9 @@ ethr_sint_t ethr_atomic_read_band(ethr_atomic_t *var, ethr_sint_t val)
ethr_sint_t ethr_atomic_read_band_ddrb(ethr_atomic_t *var, ethr_sint_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ return ethr_atomic_read_band_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic_read_band(var, val);
#else
return ethr_atomic_read_band_rb(var, val);
@@ -2626,7 +2658,9 @@ ethr_sint_t ethr_atomic_read_bor(ethr_atomic_t *var, ethr_sint_t val)
ethr_sint_t ethr_atomic_read_bor_ddrb(ethr_atomic_t *var, ethr_sint_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_WORD_SZ_NATIVE_ATOMIC_OPS)
+ return ethr_atomic_read_bor_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic_read_bor(var, val);
#else
return ethr_atomic_read_bor_rb(var, val);
@@ -2761,7 +2795,9 @@ ethr_sint32_t ethr_atomic32_cmpxchg(ethr_atomic32_t *var, ethr_sint32_t val, eth
ethr_sint32_t ethr_atomic32_cmpxchg_ddrb(ethr_atomic32_t *var, ethr_sint32_t val, ethr_sint32_t old_val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ return ethr_atomic32_cmpxchg_ddrb__(var, val, old_val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic32_cmpxchg(var, val, old_val);
#else
return ethr_atomic32_cmpxchg_rb(var, val, old_val);
@@ -2858,7 +2894,9 @@ ethr_sint32_t ethr_atomic32_xchg(ethr_atomic32_t *var, ethr_sint32_t val)
ethr_sint32_t ethr_atomic32_xchg_ddrb(ethr_atomic32_t *var, ethr_sint32_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ return ethr_atomic32_xchg_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic32_xchg(var, val);
#else
return ethr_atomic32_xchg_rb(var, val);
@@ -2954,7 +2992,9 @@ void ethr_atomic32_set(ethr_atomic32_t *var, ethr_sint32_t val)
void ethr_atomic32_set_ddrb(ethr_atomic32_t *var, ethr_sint32_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ ethr_atomic32_set_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
ethr_atomic32_set(var, val);
#else
ethr_atomic32_set_rb(var, val);
@@ -3044,7 +3084,9 @@ void ethr_atomic32_init(ethr_atomic32_t *var, ethr_sint32_t val)
void ethr_atomic32_init_ddrb(ethr_atomic32_t *var, ethr_sint32_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ ethr_atomic32_init_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
ethr_atomic32_init(var, val);
#else
ethr_atomic32_init_rb(var, val);
@@ -3131,7 +3173,9 @@ ethr_sint32_t ethr_atomic32_add_read(ethr_atomic32_t *var, ethr_sint32_t val)
ethr_sint32_t ethr_atomic32_add_read_ddrb(ethr_atomic32_t *var, ethr_sint32_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ return ethr_atomic32_add_read_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic32_add_read(var, val);
#else
return ethr_atomic32_add_read_rb(var, val);
@@ -3228,7 +3272,9 @@ ethr_sint32_t ethr_atomic32_read(ethr_atomic32_t *var)
ethr_sint32_t ethr_atomic32_read_ddrb(ethr_atomic32_t *var)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ return ethr_atomic32_read_ddrb__(var);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic32_read(var);
#else
return ethr_atomic32_read_rb(var);
@@ -3325,7 +3371,9 @@ ethr_sint32_t ethr_atomic32_inc_read(ethr_atomic32_t *var)
ethr_sint32_t ethr_atomic32_inc_read_ddrb(ethr_atomic32_t *var)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ return ethr_atomic32_inc_read_ddrb__(var);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic32_inc_read(var);
#else
return ethr_atomic32_inc_read_rb(var);
@@ -3422,7 +3470,9 @@ ethr_sint32_t ethr_atomic32_dec_read(ethr_atomic32_t *var)
ethr_sint32_t ethr_atomic32_dec_read_ddrb(ethr_atomic32_t *var)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ return ethr_atomic32_dec_read_ddrb__(var);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic32_dec_read(var);
#else
return ethr_atomic32_dec_read_rb(var);
@@ -3518,7 +3568,9 @@ void ethr_atomic32_add(ethr_atomic32_t *var, ethr_sint32_t val)
void ethr_atomic32_add_ddrb(ethr_atomic32_t *var, ethr_sint32_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ ethr_atomic32_add_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
ethr_atomic32_add(var, val);
#else
ethr_atomic32_add_rb(var, val);
@@ -3609,7 +3661,9 @@ void ethr_atomic32_inc(ethr_atomic32_t *var)
void ethr_atomic32_inc_ddrb(ethr_atomic32_t *var)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ ethr_atomic32_inc_ddrb__(var);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
ethr_atomic32_inc(var);
#else
ethr_atomic32_inc_rb(var);
@@ -3700,7 +3754,9 @@ void ethr_atomic32_dec(ethr_atomic32_t *var)
void ethr_atomic32_dec_ddrb(ethr_atomic32_t *var)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ ethr_atomic32_dec_ddrb__(var);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
ethr_atomic32_dec(var);
#else
ethr_atomic32_dec_rb(var);
@@ -3792,7 +3848,9 @@ ethr_sint32_t ethr_atomic32_read_band(ethr_atomic32_t *var, ethr_sint32_t val)
ethr_sint32_t ethr_atomic32_read_band_ddrb(ethr_atomic32_t *var, ethr_sint32_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ return ethr_atomic32_read_band_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic32_read_band(var, val);
#else
return ethr_atomic32_read_band_rb(var, val);
@@ -3889,7 +3947,9 @@ ethr_sint32_t ethr_atomic32_read_bor(ethr_atomic32_t *var, ethr_sint32_t val)
ethr_sint32_t ethr_atomic32_read_bor_ddrb(ethr_atomic32_t *var, ethr_sint32_t val)
{
-#ifdef ETHR_ORDERED_READ_DEPEND
+#if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
+ return ethr_atomic32_read_bor_ddrb__(var, val);
+#elif defined(ETHR_ORDERED_READ_DEPEND)
return ethr_atomic32_read_bor(var, val);
#else
return ethr_atomic32_read_bor_rb(var, val);
diff --git a/erts/lib_src/utils/make_atomics_api b/erts/lib_src/utils/make_atomics_api
index d8b1a56100..74736c5a2d 100755
--- a/erts/lib_src/utils/make_atomics_api
+++ b/erts/lib_src/utils/make_atomics_api
@@ -805,17 +805,40 @@ rtchk_fallback_call(Return, #atomic_context{dw = DW,
non_native_barrier(B) ->
lists:member(B, ?NON_NATIVE_BARRIERS).
-non_native_barrier_impl(AC, Type, Macro, Op, B) ->
+non_native_barrier_impl(AC, inline_implementation = Type, Op, B) ->
["
-", func_header(AC, Type, Macro, Op, B), "
+", func_header(AC, Type, false, Op, B), "
{",
case B of
ddrb ->
["
#ifdef ETHR_ORDERED_READ_DEPEND
- ", func_call(AC, Type, Macro, Op, none, true), "
+ ", func_call(AC, Type, Op, none, true), "
#else
- ", func_call(AC, Type, Macro, Op, rb, true), "
+ ", func_call(AC, Type, Op, rb, true), "
+#endif
+"
+ ]
+ end,
+ "}
+"
+ ];
+non_native_barrier_impl(#atomic_context{have_native_atomic_ops = HaveNative} = AC,
+ implementation = Type,
+ Op,
+ B) ->
+ ["
+", func_header(AC, Type, false, Op, B), "
+{",
+ case B of
+ ddrb ->
+ ["
+#if defined(", HaveNative, ")
+ ", func_call(AC, Type, Op, B, true), "
+#elif defined(ETHR_ORDERED_READ_DEPEND)
+ ", func_call(AC, symbol_implementation, Op, none, true), "
+#else
+ ", func_call(AC, symbol_implementation, Op, rb, true), "
#endif
"
]
@@ -824,12 +847,12 @@ non_native_barrier_impl(AC, Type, Macro, Op, B) ->
"
].
-func_call(#atomic_context{'ATMC' = ATMC} = AC, inline_implementation, _Macro, Op, B, RetStatement) ->
+func_call(#atomic_context{'ATMC' = ATMC} = AC, inline_implementation, Op, B, RetStatement) ->
func_call(AC, Op, ["ETHR_", ATMC, "_FUNC__(", opstr(Op), op_barrier_ext(B), ")"], RetStatement);
-func_call(#atomic_context{atomic = Atomic} = AC, implementation, false, Op, B, RetStatement) ->
- func_call(AC, Op, [Atomic, "_", opstr(Op), op_barrier_ext(B)], RetStatement);
-func_call(AC, implementation, Macro, Op, B, RetStatement) ->
- func_call(AC, Op, [Macro, "(", opstr(Op), op_barrier_ext(B), ")"], RetStatement).
+func_call(#atomic_context{atomic = Atomic} = AC, implementation, Op, B, RetStatement) ->
+ func_call(AC, Op, [Atomic, "_", opstr(Op), op_barrier_ext(B), "__"], RetStatement);
+func_call(#atomic_context{atomic = Atomic} = AC, symbol_implementation, Op, B, RetStatement) ->
+ func_call(AC, Op, [Atomic, "_", opstr(Op), op_barrier_ext(B)], RetStatement).
func_call(#atomic_context{dw = DW, arg1 = Arg1, arg2 = Arg2, arg3 = Arg3} = AC, Op, Func, true) ->
op_call(Op, DW, case is_return_op(AC, Op) of
@@ -901,7 +924,7 @@ make_implementations(#atomic_context{dw = DW,
lists:map(fun (B) ->
case non_native_barrier(B) of
true ->
- non_native_barrier_impl(AC, inline_implementation, false, Op, B);
+ non_native_barrier_impl(AC, inline_implementation, Op, B);
false ->
TryBarriers = try_barrier_order(B),
["
@@ -1211,7 +1234,7 @@ int ethr_have_native_dw_atomic(void)
end,
case non_native_barrier(B) of
true ->
- non_native_barrier_impl(AC, implementation, Macro, Op, B);
+ non_native_barrier_impl(AC, implementation, Op, B);
false ->
["\n",
func_header(AC, implementation, Macro, Op, B),
diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam
index f382236af7..b2f3ab6c5b 100644
--- a/erts/preloaded/ebin/prim_inet.beam
+++ b/erts/preloaded/ebin/prim_inet.beam
Binary files differ
diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam
index bf88a51502..7a1f896d36 100644
--- a/erts/preloaded/ebin/zlib.beam
+++ b/erts/preloaded/ebin/zlib.beam
Binary files differ
diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl
index 0cedd284db..14bf3b6c69 100644
--- a/erts/preloaded/src/prim_inet.erl
+++ b/erts/preloaded/src/prim_inet.erl
@@ -83,8 +83,10 @@ open(Protocol, Family, Type, Req, Data) ->
end
catch
%% The only (?) way to get here is to try to open
- %% the sctp driver when it does not exist
- error:badarg -> {error,eprotonosupport}
+ %% the sctp driver when it does not exist (badarg)
+ error:badarg -> {error, eprotonosupport};
+ %% system_limit if out of port slots
+ error:system_limit -> {error, system_limit}
end.
enc_family(inet) -> ?INET_AF_INET;
diff --git a/erts/preloaded/src/zlib.erl b/erts/preloaded/src/zlib.erl
index 210532edac..71b730016d 100644
--- a/erts/preloaded/src/zlib.erl
+++ b/erts/preloaded/src/zlib.erl
@@ -349,10 +349,14 @@ getQSize(Z) ->
Compressed :: binary().
compress(Data) ->
Z = open(),
- deflateInit(Z, default),
- Bs = deflate(Z, Data, finish),
- deflateEnd(Z),
- close(Z),
+ Bs = try
+ deflateInit(Z, default),
+ B = deflate(Z, Data, finish),
+ deflateEnd(Z),
+ B
+ after
+ close(Z)
+ end,
iolist_to_binary(Bs).
-spec uncompress(Data) -> Decompressed when
@@ -364,10 +368,14 @@ uncompress(Data) ->
if
Size >= 8 ->
Z = open(),
- inflateInit(Z),
- Bs = inflate(Z, Data),
- inflateEnd(Z),
- close(Z),
+ Bs = try
+ inflateInit(Z),
+ B = inflate(Z, Data),
+ inflateEnd(Z),
+ B
+ after
+ close(Z)
+ end,
iolist_to_binary(Bs);
true ->
erlang:error(data_error)
@@ -383,10 +391,14 @@ uncompress(Data) ->
Compressed :: binary().
zip(Data) ->
Z = open(),
- deflateInit(Z, default, deflated, -?MAX_WBITS, 8, default),
- Bs = deflate(Z, Data, finish),
- deflateEnd(Z),
- close(Z),
+ Bs = try
+ deflateInit(Z, default, deflated, -?MAX_WBITS, 8, default),
+ B = deflate(Z, Data, finish),
+ deflateEnd(Z),
+ B
+ after
+ close(Z)
+ end,
iolist_to_binary(Bs).
-spec unzip(Data) -> Decompressed when
@@ -394,10 +406,14 @@ zip(Data) ->
Decompressed :: binary().
unzip(Data) ->
Z = open(),
- inflateInit(Z, -?MAX_WBITS),
- Bs = inflate(Z, Data),
- inflateEnd(Z),
- close(Z),
+ Bs = try
+ inflateInit(Z, -?MAX_WBITS),
+ B = inflate(Z, Data),
+ inflateEnd(Z),
+ B
+ after
+ close(Z)
+ end,
iolist_to_binary(Bs).
-spec gzip(Data) -> Compressed when
@@ -405,10 +421,14 @@ unzip(Data) ->
Compressed :: binary().
gzip(Data) ->
Z = open(),
- deflateInit(Z, default, deflated, 16+?MAX_WBITS, 8, default),
- Bs = deflate(Z, Data, finish),
- deflateEnd(Z),
- close(Z),
+ Bs = try
+ deflateInit(Z, default, deflated, 16+?MAX_WBITS, 8, default),
+ B = deflate(Z, Data, finish),
+ deflateEnd(Z),
+ B
+ after
+ close(Z)
+ end,
iolist_to_binary(Bs).
-spec gunzip(Data) -> Decompressed when
@@ -416,10 +436,14 @@ gzip(Data) ->
Decompressed :: binary().
gunzip(Data) ->
Z = open(),
- inflateInit(Z, 16+?MAX_WBITS),
- Bs = inflate(Z, Data),
- inflateEnd(Z),
- close(Z),
+ Bs = try
+ inflateInit(Z, 16+?MAX_WBITS),
+ B = inflate(Z, Data),
+ inflateEnd(Z),
+ B
+ after
+ close(Z)
+ end,
iolist_to_binary(Bs).
-spec collect(zstream()) -> iolist().
diff --git a/erts/test/otp_SUITE.erl b/erts/test/otp_SUITE.erl
index 79cd91221f..b34d9a5422 100644
--- a/erts/test/otp_SUITE.erl
+++ b/erts/test/otp_SUITE.erl
@@ -151,6 +151,9 @@ ssl_crypto_filter(Undef) ->
{{error,bad_name},{error,bad_name}} ->
filter(fun({_,{ssl,_,_}}) -> false;
({_,{crypto,_,_}}) -> false;
+ ({_,{ssh,_,_}}) -> false;
+ ({_,{ssh_connection,_,_}}) -> false;
+ ({_,{ssh_sftp,_,_}}) -> false;
(_) -> true
end, Undef);
{_,_} -> Undef