diff options
Diffstat (limited to 'erts')
-rw-r--r-- | erts/doc/src/erlang.xml | 108 | ||||
-rw-r--r-- | erts/emulator/Makefile.in | 31 | ||||
-rw-r--r-- | erts/emulator/beam/big.c | 16 | ||||
-rw-r--r-- | erts/emulator/beam/erl_thr_progress.h | 13 | ||||
-rw-r--r-- | erts/emulator/beam/external.c | 3 | ||||
-rw-r--r-- | erts/emulator/beam/io.c | 2 | ||||
-rw-r--r-- | erts/emulator/drivers/common/efile_drv.c | 102 | ||||
-rw-r--r-- | erts/emulator/drivers/common/inet_drv.c | 38 | ||||
-rw-r--r-- | erts/emulator/drivers/unix/unix_efile.c | 21 | ||||
-rw-r--r-- | erts/emulator/test/erts_debug_SUITE.erl | 65 | ||||
-rw-r--r-- | erts/etc/unix/etp-commands | 32 | ||||
-rw-r--r-- | erts/lib_src/common/erl_misc_utils.c | 2 | ||||
-rw-r--r-- | erts/lib_src/common/ethr_atomics.c | 144 | ||||
-rwxr-xr-x | erts/lib_src/utils/make_atomics_api | 45 | ||||
-rw-r--r-- | erts/preloaded/ebin/prim_inet.beam | bin | 69980 -> 70100 bytes | |||
-rw-r--r-- | erts/preloaded/src/prim_inet.erl | 6 | ||||
-rw-r--r-- | erts/test/otp_SUITE.erl | 3 |
17 files changed, 443 insertions, 188 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/big.c b/erts/emulator/beam/big.c index 976f05c990..25ac790d81 100644 --- a/erts/emulator/beam/big.c +++ b/erts/emulator/beam/big.c @@ -1844,6 +1844,7 @@ dsize_t big_bytes(Eterm x) /* ** Load a bignum from bytes ** xsz is the number of bytes in xp +** *r is untouched if number fits in small */ Eterm bytes_to_big(byte *xp, dsize_t xsz, int xsgn, Eterm *r) { @@ -1852,7 +1853,7 @@ Eterm bytes_to_big(byte *xp, dsize_t xsz, int xsgn, Eterm *r) ErtsDigit d; int i; - while(xsz >= sizeof(ErtsDigit)) { + while(xsz > sizeof(ErtsDigit)) { d = 0; for(i = sizeof(ErtsDigit); --i >= 0;) d = (d << 8) | xp[i]; @@ -1867,11 +1868,20 @@ Eterm bytes_to_big(byte *xp, dsize_t xsz, int xsgn, Eterm *r) d = 0; for(i = xsz; --i >= 0;) d = (d << 8) | xp[i]; + if (++rsz == 1 && IS_USMALL(xsgn,d)) { + if (xsgn) d = -d; + return make_small(d); + } *rwp = d; rwp++; - rsz++; } - return big_norm(r, rsz, (short) xsgn); + if (xsgn) { + *r = make_neg_bignum_header(rsz); + } + else { + *r = make_pos_bignum_header(rsz); + } + return make_big(r); } /* 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/external.c b/erts/emulator/beam/external.c index 152dbcf085..9d52ed4e98 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -3118,6 +3118,9 @@ decoded_size(byte *ep, byte* endp, int internal_tags) case LARGE_BIG_EXT: CHKSIZE(4); n = get_int32(ep); + if (n > BIG_ARITY_MAX*sizeof(ErtsDigit)) { + return -1; + } SKIP2(n,4+1); /* skip, size,sign,digits */ heap_size += 1+1+(n+sizeof(Eterm)-1)/sizeof(Eterm); /* XXX: 1 too much? */ break; 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 33523d8e57..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)); } @@ -8053,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) @@ -8092,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/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/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..4806311dfe 100644 --- a/erts/lib_src/common/erl_misc_utils.c +++ b/erts/lib_src/common/erl_misc_utils.c @@ -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 { 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 Binary files differindex f382236af7..b2f3ab6c5b 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam 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/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 |