diff options
Diffstat (limited to 'erts')
25 files changed, 270 insertions, 82 deletions
diff --git a/erts/doc/src/erl_nif.xml b/erts/doc/src/erl_nif.xml index 34042cb4de..d58ebd3171 100644 --- a/erts/doc/src/erl_nif.xml +++ b/erts/doc/src/erl_nif.xml @@ -2217,6 +2217,18 @@ enif_inspect_iovec(env, max_elements, term, &tail, &iovec); </func> <func> + <name since="OTP @OTP-15362@"><ret>ERL_NIF_TERM</ret> + <nametext>enif_make_monitor_term(ErlNifEnv* env, const ErlNifMonitor* mon)</nametext></name> + <fsummary>Make monitor term from the given monitor identifier.</fsummary> + <desc> + <p>Creates a term identifying the given monitor received from + <seealso marker="#enif_monitor_process"><c>enif_monitor_process</c> + </seealso>.</p> + <p>This function is primarily intended for debugging purpose.</p> + </desc> + </func> + + <func> <name since="OTP R14B"><ret>unsigned char *</ret><nametext>enif_make_new_binary(ErlNifEnv* env, size_t size, ERL_NIF_TERM* termp)</nametext></name> <fsummary>Allocate and create a new binary term.</fsummary> @@ -3079,16 +3091,18 @@ enif_map_iterator_destroy(env, &iter);</code> or the atom <c>undefined</c>. It will be passed as <c>Ref</c> in the notifications. If a selective <c>receive</c> statement is used to wait for the notification then a reference created just before the <c>receive</c> will exploit a runtime - optimization that bypasses all earlier received messages in the queue.</p> + optimization that bypasses all earlier received messages in the + queue.</p> <p>The notifications are one-shot only. To receive further notifications of the same type (read or write), repeated calls to <c>enif_select</c> must be made after receiving each notification.</p> <p><c>ERL_NIF_SELECT_CANCEL</c> can be used to cancel previously selected events. It must be used in a bitwise OR combination with <c>ERL_NIF_SELECT_READ</c> and/or <c>ERL_NIF_SELECT_WRITE</c> to - indicate which type of event to cancel. The return value will - tell if the event was actualy cancelled or if a notification may - already have been sent.</p> + indicate which type of event to cancel. Arguments <c>pid</c> and + <c>ref</c> are ignored when <c>ERL_NIF_SELECT_CANCEL</c> is specified. + The return value will tell if the event was actualy cancelled or if a + notification may already have been sent.</p> <p>Use <c>ERL_NIF_SELECT_STOP</c> as <c>mode</c> in order to safely close an event object that has been passed to <c>enif_select</c>. The <seealso marker="#ErlNifResourceStop"><c>stop</c></seealso> callback @@ -3097,7 +3111,9 @@ enif_map_iterator_destroy(env, &iter);</code> even if all notifications have been received (or cancelled) and no further calls to <c>enif_select</c> have been made. <c>ERL_NIF_SELECT_STOP</c> will first cancel any selected events - before it calls or schedules the <c>stop</c> callback.</p> + before it calls or schedules the <c>stop</c> callback. Arguments + <c>pid</c> and <c>ref</c> are ignored when <c>ERL_NIF_SELECT_STOP</c> + is specified.</p> <p>The first call to <c>enif_select</c> for a specific OS <c>event</c> will establish a relation between the event object and the containing resource. All subsequent calls for an <c>event</c> must pass its containing resource as argument @@ -3180,7 +3196,11 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { <c>enif_alloc_env</c></seealso>. If argument <c>msg_env</c> is <c>NULL</c> the term <c>msg</c> will be copied, otherwise both <c>msg</c> and <c>msg_env</c> will be invalidated by a successful call - to <c>enif_select_read</c> or <c>enif_select_write</c>.</p> + to <c>enif_select_read</c> or <c>enif_select_write</c>. The environment + is then to either be freed with <seealso marker="#enif_free_env"> + <c>enif_free_env</c></seealso> or cleared for reuse with + <seealso marker="#enif_clear_env"><c>enif_clear_env</c></seealso>. An + unsuccessful call will leave <c>msg</c> and <c>msg_env</c> still valid.</p> <p>Apart from the message format <c>enif_select_read</c> and <c>enif_select_write</c> behaves exactly the same as <seealso marker="#enif_select">enif_select</seealso> with argument <c>mode</c> as @@ -3234,8 +3254,9 @@ if (retval & ERL_NIF_SELECT_STOP_CALLED) { <c>msg</c>) is invalidated by a successful call to <c>enif_send</c>. The environment is to either be freed with <seealso marker="#enif_free_env"> - <c>enif_free_env</c></seealso> of cleared for reuse with - <seealso marker="#enif_clear_env"><c>enif_clear_env</c></seealso>.</p> + <c>enif_free_env</c></seealso> or cleared for reuse with + <seealso marker="#enif_clear_env"><c>enif_clear_env</c></seealso>. An + unsuccessful call will leave <c>msg</c> and <c>msg_env</c> still valid.</p> <p>If <c>msg_env</c> is set to <c>NULL</c>, the <c>msg</c> term is copied and the original term and its environment is still valid after the call.</p> diff --git a/erts/doc/src/notes.xml b/erts/doc/src/notes.xml index 2c23456ff1..3473a12526 100644 --- a/erts/doc/src/notes.xml +++ b/erts/doc/src/notes.xml @@ -31,6 +31,24 @@ </header> <p>This document describes the changes made to the ERTS application.</p> +<section><title>Erts 10.2.4</title> + + <section><title>Fixed Bugs and Malfunctions</title> + <list> + <item> + <p> + When using the <c>{linger,{true,T}}</c> option; + <c>gen_tcp:listen/2</c> used the full linger time before + returning for example <c>eaddrinuse</c>. This bug has now + been corrected.</p> + <p> + Own Id: OTP-14728 Aux Id: ERIERL-303 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 10.2.3</title> <section><title>Fixed Bugs and Malfunctions</title> @@ -1694,6 +1712,26 @@ </section> +<section><title>Erts 9.3.3.9</title> + + <section><title>Improvements and New Features</title> + <list> + <item> + <p>Added an optional <c>./configure</c> flag to compile + the emulator with spectre mitigation: + <c>--with-spectre-mitigation</c></p> + <p>Note that this requires a recent version of GCC with + support for spectre mitigation and the + <c>--mindirect-branch=thunk</c> flag, such as + <c>8.1</c>.</p> + <p> + Own Id: OTP-15430 Aux Id: ERIERL-237 </p> + </item> + </list> + </section> + +</section> + <section><title>Erts 9.3.3.8</title> <section><title>Fixed Bugs and Malfunctions</title> diff --git a/erts/doc/src/persistent_term.xml b/erts/doc/src/persistent_term.xml index 1eda7f8d76..9d3c9afd80 100644 --- a/erts/doc/src/persistent_term.xml +++ b/erts/doc/src/persistent_term.xml @@ -256,6 +256,22 @@ will be slower as the number of persistent terms increases.</pre> </func> <func> + <name name="get" arity="2" since="OTP 21.3"/> + <fsummary>Get the value for a persistent term.</fsummary> + <desc> + <p>Retrieve the value for the persistent term associated with + the key <c><anno>Key</anno></c>. The lookup will be made in + constant time and the value will not be copied to the heap + of the calling process.</p> + <p>This function returns <c><anno>Default</anno></c> if no + term has been stored with the key <c><anno>Key</anno></c>.</p> + <p>If the calling process holds on to the value of the + persistent term and the persistent term is deleted in the future, + the term will be copied to the process.</p> + </desc> + </func> + + <func> <name name="info" arity="0" since="OTP 21.2"/> <fsummary>Get information about persistent terms.</fsummary> <desc> diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index 18586b5ede..11941db8cd 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -737,3 +737,4 @@ bif erts_internal:spawn_system_process/3 bif erlang:integer_to_list/2 bif erlang:integer_to_binary/2 +bif persistent_term:get/2 diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h index da4dc84d10..ad19cce395 100644 --- a/erts/emulator/beam/big.h +++ b/erts/emulator/beam/big.h @@ -81,7 +81,11 @@ typedef Uint dsize_t; /* Vector size type */ * a Uint64 argument. Therefore, we must test the size of the argument * to ensure that the cast does not discard the high-order 32 bits. */ -#define _IS_SSMALL32(x) (((Uint32) ((((x)) >> (SMALL_BITS-1)) + 1)) < 2) +#if defined(ARCH_32) +# define _IS_SSMALL32(x) (((Uint32) ((((x)) >> (SMALL_BITS-1)) + 1)) < 2) +#else +# define _IS_SSMALL32(x) (1) +#endif #define _IS_SSMALL64(x) (((Uint64) ((((x)) >> (SMALL_BITS-1)) + 1)) < 2) #define IS_SSMALL(x) (sizeof(x) == sizeof(Uint32) ? _IS_SSMALL32(x) : _IS_SSMALL64(x)) diff --git a/erts/emulator/beam/erl_bif_binary.c b/erts/emulator/beam/erl_bif_binary.c index ca1ba55b22..4d6d31cd76 100644 --- a/erts/emulator/beam/erl_bif_binary.c +++ b/erts/emulator/beam/erl_bif_binary.c @@ -2735,7 +2735,7 @@ static BIF_RETTYPE do_encode_unsigned(Process *p, Eterm uns, Eterm endianess) dsize_t num_parts = BIG_SIZE(bigp); Eterm res; byte *b; - ErtsDigit d; + ErtsDigit d = 0; if(BIG_SIGN(bigp)) { goto badarg; @@ -2751,26 +2751,22 @@ static BIF_RETTYPE do_encode_unsigned(Process *p, Eterm uns, Eterm endianess) if (endianess == am_big) { Sint i,j; j = 0; - d = BIG_DIGIT(bigp,0); for (i=n-1;i>=0;--i) { - b[i] = d & 0xFF; - if (!((++j) % sizeof(ErtsDigit))) { + if (!((j++) % sizeof(ErtsDigit))) { d = BIG_DIGIT(bigp,j / sizeof(ErtsDigit)); - } else { - d >>= 8; } + b[i] = d & 0xFF; + d >>= 8; } } else { Sint i,j; j = 0; - d = BIG_DIGIT(bigp,0); for (i=0;i<n;++i) { - b[i] = d & 0xFF; - if (!((++j) % sizeof(ErtsDigit))) { + if (!((j++) % sizeof(ErtsDigit))) { d = BIG_DIGIT(bigp,j / sizeof(ErtsDigit)); - } else { - d >>= 8; } + b[i] = d & 0xFF; + d >>= 8; } } diff --git a/erts/emulator/beam/erl_bif_persistent.c b/erts/emulator/beam/erl_bif_persistent.c index 9dca768a18..5a78a043ce 100644 --- a/erts/emulator/beam/erl_bif_persistent.c +++ b/erts/emulator/beam/erl_bif_persistent.c @@ -332,6 +332,23 @@ BIF_RETTYPE persistent_term_get_1(BIF_ALIST_1) BIF_ERROR(BIF_P, BADARG); } +BIF_RETTYPE persistent_term_get_2(BIF_ALIST_2) +{ + Eterm key = BIF_ARG_1; + Eterm result = BIF_ARG_2; + HashTable* hash_table = (HashTable *) erts_atomic_read_nob(&the_hash_table); + Uint entry_index; + Eterm term; + + entry_index = lookup(hash_table, key); + term = hash_table->term[entry_index]; + if (is_boxed(term)) { + ASSERT(is_tuple_arity(term, 2)); + result = tuple_val(term)[2]; + } + BIF_RET(result); +} + BIF_RETTYPE persistent_term_erase_1(BIF_ALIST_1) { Eterm key = BIF_ARG_1; diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c index 93816542cd..62dd85e425 100644 --- a/erts/emulator/beam/erl_map.c +++ b/erts/emulator/beam/erl_map.c @@ -480,7 +480,7 @@ Eterm erts_hashmap_from_array(ErtsHeapFactory* factory, Eterm *leafs, Uint n, Eterm erts_map_from_ks_and_vs(ErtsHeapFactory *factory, Eterm *ks0, Eterm *vs0, Uint n) { - if (n < MAP_SMALL_MAP_LIMIT) { + if (n <= MAP_SMALL_MAP_LIMIT) { Eterm *ks, *vs, *hp; flatmap_t *mp; Eterm keys; diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index 4f317c9b25..b2bd28fcbb 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -2366,6 +2366,13 @@ static int dtor_demonitor(ErtsMonitor* mon, void* context, Sint reds) return 1; } +#ifdef DEBUG +int erts_dbg_is_resource_dying(ErtsResource* resource) +{ + return resource->monitors && rmon_is_dying(resource->monitors); +} +#endif + # define NIF_RESOURCE_DTOR &nif_resource_dtor static int nif_resource_dtor(Binary* bin) @@ -2706,8 +2713,12 @@ int enif_consume_timeslice(ErlNifEnv* env, int percent) { Process *proc; Sint reds; + int sched; - execution_state(env, &proc, NULL); + execution_state(env, &proc, &sched); + + if (sched < 0) + return 0; /* no-op on dirty scheduler */ ASSERT(is_proc_bound(env) && percent >= 1 && percent <= 100); if (percent < 1) percent = 1; @@ -3363,6 +3374,12 @@ int enif_monitor_process(ErlNifEnv* env, void* obj, const ErlNifPid* target_pid, return 0; } +ERL_NIF_TERM enif_make_monitor_term(ErlNifEnv* env, const ErlNifMonitor* monitor) +{ + Eterm* hp = alloc_heap(env, ERTS_REF_THING_SIZE); + return erts_driver_monitor_to_ref(hp, monitor); +} + int enif_demonitor_process(ErlNifEnv* env, void* obj, const ErlNifMonitor* monitor) { ErtsResource* rsrc = DATA_TO_RESOURCE(obj); diff --git a/erts/emulator/beam/erl_nif_api_funcs.h b/erts/emulator/beam/erl_nif_api_funcs.h index 129166562d..4ea6a2f7b0 100644 --- a/erts/emulator/beam/erl_nif_api_funcs.h +++ b/erts/emulator/beam/erl_nif_api_funcs.h @@ -211,6 +211,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_vsnprintf,(char*, size_t, const char *fmt, va_lis ERL_NIF_API_FUNC_DECL(int,enif_make_map_from_arrays,(ErlNifEnv *env, ERL_NIF_TERM keys[], ERL_NIF_TERM values[], size_t cnt, ERL_NIF_TERM *map_out)); ERL_NIF_API_FUNC_DECL(int,enif_select_x,(ErlNifEnv* env, ErlNifEvent e, enum ErlNifSelectFlags flags, void* obj, const ErlNifPid* pid, ERL_NIF_TERM msg, ErlNifEnv* msg_env)); +ERL_NIF_API_FUNC_DECL(ERL_NIF_TERM,enif_make_monitor_term,(ErlNifEnv* env, const ErlNifMonitor*)); /* @@ -396,6 +397,7 @@ ERL_NIF_API_FUNC_DECL(int,enif_select_x,(ErlNifEnv* env, ErlNifEvent e, enum Erl # define enif_vsnprintf ERL_NIF_API_FUNC_MACRO(enif_vsnprintf) # define enif_make_map_from_arrays ERL_NIF_API_FUNC_MACRO(enif_make_map_from_arrays) # define enif_select_x ERL_NIF_API_FUNC_MACRO(enif_select_x) +# define enif_make_monitor_term ERL_NIF_API_FUNC_MACRO(enif_make_monitor_term) /* ** ADD NEW ENTRIES HERE (before this comment) diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index ddb76a0b00..0a099e69bb 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -2462,6 +2462,13 @@ handle_reap_ports(ErtsAuxWorkData *awdp, erts_aint32_t aux_work, int waiting) erts_port_lock(prt); + if (prt->common.u.alive.reg && + prt->common.u.alive.reg->name == am_heart_port) { + /* Leave heart port to not get killed before flushing is done*/ + erts_port_release(prt); + continue; + } + state = erts_atomic32_read_nob(&prt->state); if (!(state & (ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP | ERTS_PORT_SFLG_HALT))) { diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 7aa136575f..73eae614fa 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -102,7 +102,7 @@ static byte* enc_term(ErtsAtomCacheMap *, Eterm, byte*, Uint32, struct erl_off_h struct TTBEncodeContext_; static int enc_term_int(struct TTBEncodeContext_*,ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, Uint32 dflags, struct erl_off_heap_header** off_heap, Sint *reds, byte **res); -static Uint is_external_string(Eterm obj, int* p_is_string); +static int is_external_string(Eterm obj, Uint* lenp); static byte* enc_atom(ErtsAtomCacheMap *, Eterm, byte*, Uint32); static byte* enc_pid(ErtsAtomCacheMap *, Eterm, byte*, Uint32); struct B2TContext_t; @@ -2613,11 +2613,21 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, { Eterm* cons = list_val(obj); Eterm tl; + Uint len_cnt = WSTACK_POP(s); obj = CAR(cons); tl = CDR(cons); - WSTACK_PUSH2(s, (is_list(tl) ? ENC_ONE_CONS : ENC_TERM), - tl); + if (is_list(tl)) { + len_cnt++; + WSTACK_PUSH3(s, len_cnt, ENC_ONE_CONS, tl); + } + else { + byte* list_lenp = (byte*) WSTACK_POP(s); + ASSERT(list_lenp[-1] == LIST_EXT); + put_int32(len_cnt, list_lenp); + + WSTACK_PUSH2(s, ENC_TERM, tl); + } } break; case ENC_PATCH_FUN_SIZE: @@ -2821,10 +2831,7 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, } case LIST_DEF: { - int is_str; - - i = is_external_string(obj, &is_str); - if (is_str) { + if (is_external_string(obj, &i)) { *ep++ = STRING_EXT; put_int16(i, ep); ep += 2; @@ -2833,9 +2840,12 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, *ep++ = unsigned_val(CAR(cons)); obj = CDR(cons); } + r -= i; } else { + r -= i/2; *ep++ = LIST_EXT; - put_int32(i, ep); + /* Patch list length when we find end of list */ + WSTACK_PUSH2(s, (UWord)ep, 1); ep += 4; goto encode_one_cons; } @@ -3093,9 +3103,13 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, return 0; } +/** @brief Is it a list of bytes not longer than MAX_STRING_LEN? + * @param lenp out: string length or number of list cells traversed + * @return true/false + */ static -Uint -is_external_string(Eterm list, int* p_is_string) +int +is_external_string(Eterm list, Uint* lenp) { Uint len = 0; @@ -3107,29 +3121,15 @@ is_external_string(Eterm list, int* p_is_string) Eterm* consp = list_val(list); Eterm hd = CAR(consp); - if (!is_byte(hd)) { - break; + if (!is_byte(hd) || ++len > MAX_STRING_LEN) { + *lenp = len; + return 0; } - len++; list = CDR(consp); } - /* - * If we have reached the end of the list, and we have - * not exceeded the maximum length of a string, this - * is a string. - */ - *p_is_string = is_nil(list) && len < MAX_STRING_LEN; - - /* - * Continue to calculate the length. - */ - while (is_list(list)) { - Eterm* consp = list_val(list); - len++; - list = CDR(consp); - } - return len; + *lenp = len; + return is_nil(list); } @@ -4207,8 +4207,8 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, for (;;) { ASSERT(!is_header(obj)); - if (ctx && --r == 0) { - *reds = r; + if (ctx && --r <= 0) { + *reds = 0; ctx->obj = obj; ctx->result = result; WSTACK_SAVE(s, &ctx->wstack); @@ -4298,8 +4298,10 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, result += (1 + encode_size_struct2(acmp, port_node_name(obj), dflags) + 4 + 1); break; - case LIST_DEF: - if ((m = is_string(obj)) && (m < MAX_STRING_LEN)) { + case LIST_DEF: { + int is_str = is_external_string(obj, &m); + r -= m/2; + if (is_str) { result += m + 2 + 1; } else { result += 5; @@ -4308,6 +4310,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, continue; /* big loop */ } break; + } case TUPLE_DEF: { Eterm* ptr = tuple_val(obj); @@ -4449,7 +4452,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, if (is_header(obj)) { switch (obj) { - case LIST_TAIL_OP: + case LIST_TAIL_OP: obj = (Eterm) WSTACK_POP(s); if (is_list(obj)) { Eterm* cons = list_val(obj); @@ -4475,7 +4478,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, WSTACK_DESTROY(s); if (ctx) { ASSERT(ctx->wstack.wstart == NULL); - *reds = r; + *reds = r < 0 ? 0 : r; } *res = result; return 0; diff --git a/erts/emulator/beam/global.h b/erts/emulator/beam/global.h index 52935d834c..f9bbe4167f 100644 --- a/erts/emulator/beam/global.h +++ b/erts/emulator/beam/global.h @@ -113,6 +113,9 @@ extern Eterm erts_bld_resource_ref(Eterm** hp, ErlOffHeap*, ErtsResource*); extern void erts_pre_nif(struct enif_environment_t*, Process*, struct erl_module_nif*, Process* tracee); extern void erts_post_nif(struct enif_environment_t* env); +#ifdef DEBUG +int erts_dbg_is_resource_dying(ErtsResource*); +#endif extern void erts_resource_stop(ErtsResource*, ErlNifEvent, int is_direct_call); void erts_fire_nif_monitor(ErtsMonitor *tmon); void erts_nif_demonitored(ErtsResource* resource); diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index 8e8198b0b0..a699ece23e 100644 --- a/erts/emulator/sys/common/erl_check_io.c +++ b/erts/emulator/sys/common/erl_check_io.c @@ -1061,7 +1061,7 @@ enif_select_x(ErlNifEnv* env, ErtsDrvSelectDataState *free_select = NULL; ErtsNifSelectDataState *free_nif = NULL; - ASSERT(!resource->monitors); + ASSERT(!erts_dbg_is_resource_dying(resource)); #ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS if (!grow_drv_ev_state(fd)) { diff --git a/erts/emulator/sys/common/erl_poll.c b/erts/emulator/sys/common/erl_poll.c index 27ffba58bd..c71d23f58c 100644 --- a/erts/emulator/sys/common/erl_poll.c +++ b/erts/emulator/sys/common/erl_poll.c @@ -872,8 +872,8 @@ update_pollset(ErtsPollSet *ps, int fd, ErtsPollOp op, ErtsPollEvents events) } } -#if defined(EV_DISPATCH) && !defined(__OpenBSD__) - /* If we have EV_DISPATCH we use it, unless we are on OpenBSD as the +#if defined(EV_DISPATCH) && !(defined(__OpenBSD__) || defined(__NetBSD__)) + /* If we have EV_DISPATCH we use it, unless we are on OpenBSD/NetBSD as the behavior of EV_EOF seems to be edge triggered there and we need it to be level triggered. diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 0d0930e124..168df76301 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -822,8 +822,11 @@ demonitor_process(Config) -> end), R_ptr = alloc_monitor_resource_nif(), {0,MonBin1} = monitor_process_nif(R_ptr, Pid, true, self()), + MonTerm1 = make_monitor_term_nif(MonBin1), [R_ptr] = monitored_by(Pid), {0,MonBin2} = monitor_process_nif(R_ptr, Pid, true, self()), + MonTerm2 = make_monitor_term_nif(MonBin2), + true = (MonTerm1 =/= MonTerm2), [R_ptr, R_ptr] = monitored_by(Pid), 0 = demonitor_process_nif(R_ptr, MonBin1), [R_ptr] = monitored_by(Pid), @@ -837,6 +840,10 @@ demonitor_process(Config) -> {R_ptr, _, 1} = last_resource_dtor_call(), [] = monitored_by(Pid), Pid ! return, + + erlang:garbage_collect(), + true = (MonTerm1 =/= MonTerm2), + io:format("MonTerm1 = ~p\nMonTerm2 = ~p\n", [MonTerm1, MonTerm2]), ok. @@ -1208,6 +1215,15 @@ maps(Config) when is_list(Config) -> M2 = maps_from_list_nif(maps:to_list(M2)), M3 = maps_from_list_nif(maps:to_list(M3)), + %% Test different map sizes (OTP-15567) + repeat_while(fun({35,_}) -> false; + ({K,Map}) -> + Map = maps_from_list_nif(maps:to_list(Map)), + Map = maps:filter(fun(K,V) -> V =:= K*100 end, Map), + {K+1, maps:put(K,K*100,Map)} + end, + {1,#{}}), + has_duplicate_keys = maps_from_list_nif([{1,1},{1,1}]), verify_tmpmem(TmpMem), @@ -2504,6 +2520,13 @@ repeat(0, _, Arg) -> repeat(N, Fun, Arg0) -> repeat(N-1, Fun, Fun(Arg0)). +repeat_while(Fun, Acc0) -> + case Fun(Acc0) of + false -> ok; + Acc1 -> + repeat_while(Fun, Acc1) + end. + check(Exp,Got,Line) -> case Got of Exp -> Exp; @@ -3421,6 +3444,7 @@ alloc_monitor_resource_nif() -> ?nif_stub. monitor_process_nif(_,_,_,_) -> ?nif_stub. demonitor_process_nif(_,_) -> ?nif_stub. compare_monitors_nif(_,_) -> ?nif_stub. +make_monitor_term_nif(_) -> ?nif_stub. monitor_frenzy_nif(_,_,_,_) -> ?nif_stub. ioq_nif(_) -> ?nif_stub. ioq_nif(_,_) -> ?nif_stub. diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 21af4b05b3..af2d062857 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -2847,6 +2847,16 @@ static ERL_NIF_TERM compare_monitors_nif(ErlNifEnv* env, int argc, const ERL_NIF return enif_make_int(env, enif_compare_monitors(&m1, &m2)); } +static ERL_NIF_TERM make_monitor_term_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]) +{ + ErlNifMonitor m; + if (!get_monitor(env, argv[0], &m)) { + return enif_make_badarg(env); + } + + return enif_make_monitor_term(env, &m); +} + /*********** monitor_frenzy ************/ @@ -3596,6 +3606,7 @@ static ErlNifFunc nif_funcs[] = {"monitor_process_nif", 4, monitor_process_nif}, {"demonitor_process_nif", 2, demonitor_process_nif}, {"compare_monitors_nif", 2, compare_monitors_nif}, + {"make_monitor_term_nif", 1, make_monitor_term_nif}, {"monitor_frenzy_nif", 4, monitor_frenzy_nif}, {"whereis_send", 3, whereis_send}, {"whereis_term", 2, whereis_term}, diff --git a/erts/emulator/test/persistent_term_SUITE.erl b/erts/emulator/test/persistent_term_SUITE.erl index 58038e24b7..93eb026ced 100644 --- a/erts/emulator/test/persistent_term_SUITE.erl +++ b/erts/emulator/test/persistent_term_SUITE.erl @@ -6,7 +6,7 @@ %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. %% You may obtain a copy of the License at -%5 +%% %% http://www.apache.org/licenses/LICENSE-2.0 %% %% Unless required by applicable law or agreed to in writing, software @@ -60,7 +60,8 @@ basic(_Config) -> Key = {?MODULE,{key,I}}, true = persistent_term:erase(Key), false = persistent_term:erase(Key), - {'EXIT',{badarg,_}} = (catch persistent_term:get(Key)) + {'EXIT',{badarg,_}} = (catch persistent_term:get(Key)), + {not_present,Key} = persistent_term:get(Key, {not_present,Key}) end || I <- Seq], [] = [P || {{?MODULE,_},_}=P <- pget(Chk)], chk(Chk). diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c index bd218ff725..bb843a616b 100644 --- a/erts/etc/common/heart.c +++ b/erts/etc/common/heart.c @@ -500,7 +500,7 @@ message_loop(erlin_fd, erlout_fd) #if defined(__WIN32__) static void -kill_old_erlang(void){ +kill_old_erlang(int reason){ HANDLE erlh; DWORD exit_code; char* envvar = NULL; @@ -536,7 +536,8 @@ kill_old_erlang(void){ } #else static void -kill_old_erlang(void){ +kill_old_erlang(int reason) +{ pid_t pid; int i, res; int sig = SIGKILL; @@ -546,14 +547,25 @@ kill_old_erlang(void){ if (envvar && strcmp(envvar, "TRUE") == 0) return; - envvar = get_env(HEART_KILL_SIGNAL); - if (envvar && strcmp(envvar, "SIGABRT") == 0) { - print_error("kill signal SIGABRT requested"); - sig = SIGABRT; - } - if(heart_beat_kill_pid != 0){ - pid = (pid_t) heart_beat_kill_pid; + pid = (pid_t) heart_beat_kill_pid; + if (reason == R_CLOSED) { + print_error("Wait 5 seconds for Erlang to terminate nicely"); + for (i=0; i < 5; ++i) { + res = kill(pid, 0); /* check if alive */ + if (res < 0 && errno == ESRCH) + return; + sleep(1); + } + print_error("Erlang still alive, kill it"); + } + + envvar = get_env(HEART_KILL_SIGNAL); + if (envvar && strcmp(envvar, "SIGABRT") == 0) { + print_error("kill signal SIGABRT requested"); + sig = SIGABRT; + } + res = kill(pid,sig); for(i=0; i < 5 && res == 0; ++i){ sleep(1); @@ -677,7 +689,7 @@ do_terminate(int erlin_fd, int reason) { if(!command) print_error("Would reboot. Terminating."); else { - kill_old_erlang(); + kill_old_erlang(reason); /* High prio combined with system() works badly indeed... */ SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); win_system(command); @@ -685,7 +697,7 @@ do_terminate(int erlin_fd, int reason) { } free_env_val(command); } else { - kill_old_erlang(); + kill_old_erlang(reason); /* High prio combined with system() works badly indeed... */ SetPriorityClass(GetCurrentProcess(), NORMAL_PRIORITY_CLASS); win_system(&cmd[0]); @@ -697,13 +709,13 @@ do_terminate(int erlin_fd, int reason) { if(!command) print_error("Would reboot. Terminating."); else { - kill_old_erlang(); + kill_old_erlang(reason); ret = system(command); print_error("Executed \"%s\" -> %d. Terminating.",command, ret); } free_env_val(command); } else { - kill_old_erlang(); + kill_old_erlang(reason); ret = system((char*)&cmd[0]); print_error("Executed \"%s\" -> %d. Terminating.",cmd, ret); } diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in index 2237553113..e8dc59156f 100644 --- a/erts/etc/unix/etp-commands.in +++ b/erts/etc/unix/etp-commands.in @@ -4435,8 +4435,6 @@ document etp-init %--------------------------------------------------------------------------- end -macro define offsetof(t, f) &((t *) 0)->f) - define hook-run set $_exitsignal = -1 end diff --git a/erts/preloaded/ebin/persistent_term.beam b/erts/preloaded/ebin/persistent_term.beam Binary files differindex e94ef983be..c882e4fad4 100644 --- a/erts/preloaded/ebin/persistent_term.beam +++ b/erts/preloaded/ebin/persistent_term.beam diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex f211971529..ff9268ad38 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/src/persistent_term.erl b/erts/preloaded/src/persistent_term.erl index 5d0c266127..ee7e49b6cb 100644 --- a/erts/preloaded/src/persistent_term.erl +++ b/erts/preloaded/src/persistent_term.erl @@ -19,7 +19,7 @@ %% -module(persistent_term). --export([erase/1,get/0,get/1,info/0,put/2]). +-export([erase/1,get/0,get/1,get/2,info/0,put/2]). -type key() :: term(). -type value() :: term(). @@ -41,6 +41,13 @@ get() -> get(_Key) -> erlang:nif_error(undef). +-spec get(Key, Default) -> Value when + Key :: key(), + Default :: value(), + Value :: value(). +get(_Key, _Default) -> + erlang:nif_error(undef). + -spec info() -> Info when Info :: #{'count':=Count,'memory':=Memory}, Count :: non_neg_integer(), diff --git a/erts/preloaded/src/prim_inet.erl b/erts/preloaded/src/prim_inet.erl index 4fe570ec53..d5abdd2483 100644 --- a/erts/preloaded/src/prim_inet.erl +++ b/erts/preloaded/src/prim_inet.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2018. All Rights Reserved. +%% Copyright Ericsson AB 2000-2019. All Rights Reserved. %% %% Licensed under the Apache License, Version 2.0 (the "License"); %% you may not use this file except in compliance with the License. @@ -172,8 +172,18 @@ close(S) when is_port(S) -> %% and is a contradiction in itself. %% We have hereby done our best... %% - Tref = erlang:start_timer(T * 1000, self(), close_port), - close_pend_loop(S, Tref, undefined); + case subscribe(S, [subs_empty_out_q]) of + {ok, [{subs_empty_out_q,0}]} -> + close_port(S); + {ok, [{subs_empty_out_q,N}]} when N > 0 -> + %% Wait for pending output to be sent + Tref = erlang:start_timer(T * 1000, self(), close_port), + close_pend_loop(S, Tref, N); + _ -> + %% Subscribe failed - wait full time + Tref = erlang:start_timer(T * 1000, self(), close_port), + close_pend_loop(S, Tref, undefined) + end; _ -> % Regard this as {ok,{false,_}} case subscribe(S, [subs_empty_out_q]) of {ok, [{subs_empty_out_q,N}]} when N > 0 -> diff --git a/erts/vsn.mk b/erts/vsn.mk index 9c912a422b..e4bdb1a8eb 100644 --- a/erts/vsn.mk +++ b/erts/vsn.mk @@ -18,7 +18,7 @@ # %CopyrightEnd% # -VSN = 10.2.3 +VSN = 10.2.4 # Port number 4365 in 4.2 # Port number 4366 in 4.3 |