diff options
56 files changed, 1133 insertions, 758 deletions
diff --git a/OTP_VERSION b/OTP_VERSION index 1fbc0d2431..9d7cce5373 100644 --- a/OTP_VERSION +++ b/OTP_VERSION @@ -1 +1 @@ -18.0-rc0 +18.0-rc1 diff --git a/bootstrap/lib/kernel/ebin/inet_dns.beam b/bootstrap/lib/kernel/ebin/inet_dns.beam Binary files differindex 618f9c407a..0c5b6c73e1 100644 --- a/bootstrap/lib/kernel/ebin/inet_dns.beam +++ b/bootstrap/lib/kernel/ebin/inet_dns.beam diff --git a/erts/aclocal.m4 b/erts/aclocal.m4 index fb5ae4f02d..83f735d332 100644 --- a/erts/aclocal.m4 +++ b/erts/aclocal.m4 @@ -745,9 +745,9 @@ AC_DEFUN(ERL_MONOTONIC_CLOCK, done ]) - AC_CHECK_FUNCS([clock_getres gethrtime]) + AC_CHECK_FUNCS([clock_getres clock_get_attributes gethrtime]) - AC_CACHE_CHECK([for mach clock_get_time()], erl_cv_mach_clock_get_time_monotonic, + AC_CACHE_CHECK([for mach clock_get_time() with monotonic clock type], erl_cv_mach_clock_get_time_monotonic, [ AC_TRY_COMPILE([ #include <mach/clock.h> @@ -854,9 +854,9 @@ AC_DEFUN(ERL_WALL_CLOCK, done ]) - AC_CHECK_FUNCS([clock_getres gettimeofday]) + AC_CHECK_FUNCS([clock_getres clock_get_attributes gettimeofday]) - AC_CACHE_CHECK([for mach clock_get_time()], erl_cv_mach_clock_get_time_wall, + AC_CACHE_CHECK([for mach clock_get_time() with wall clock type], erl_cv_mach_clock_get_time_wall, [ AC_TRY_COMPILE([ #include <mach/clock.h> diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 6526e87e4c..8fcdc72895 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -6602,8 +6602,8 @@ new_map(Process* p, Eterm* reg, BeamInstr* I) keys = make_tuple(thp); *thp++ = make_arityval(n/2); - mp = (flatmap_t *)mhp; mhp += MAP_HEADER_SIZE; - mp->thing_word = MAP_HEADER; + mp = (flatmap_t *)mhp; mhp += MAP_HEADER_FLATMAP_SZ; + mp->thing_word = MAP_HEADER_FLATMAP; mp->size = n/2; mp->keys = keys; @@ -6684,7 +6684,7 @@ update_map_assoc(Process* p, Eterm* reg, Eterm map, BeamInstr* I) * update list are new). */ - need = 2*(num_old+num_updates) + 1 + MAP_HEADER_SIZE; + need = 2*(num_old+num_updates) + 1 + MAP_HEADER_FLATMAP_SZ; if (HeapWordsLeft(p) < need) { Uint live = Arg(3); reg[live] = map; @@ -6723,8 +6723,8 @@ update_map_assoc(Process* p, Eterm* reg, Eterm map, BeamInstr* I) res = make_flatmap(hp); mp = (flatmap_t *)hp; - hp += MAP_HEADER_SIZE; - mp->thing_word = MAP_HEADER; + hp += MAP_HEADER_FLATMAP_SZ; + mp->thing_word = MAP_HEADER_FLATMAP; mp->keys = make_tuple(kp-1); old_vals = flatmap_get_values(old_mp); @@ -6906,7 +6906,7 @@ update_map_exact(Process* p, Eterm* reg, Eterm map, BeamInstr* I) * Allocate the exact heap space needed. */ - need = num_old + MAP_HEADER_SIZE; + need = num_old + MAP_HEADER_FLATMAP_SZ; if (HeapWordsLeft(p) < need) { Uint live = Arg(3); reg[live] = map; @@ -6927,8 +6927,8 @@ update_map_exact(Process* p, Eterm* reg, Eterm map, BeamInstr* I) res = make_flatmap(hp); mp = (flatmap_t *)hp; - hp += MAP_HEADER_SIZE; - mp->thing_word = MAP_HEADER; + hp += MAP_HEADER_FLATMAP_SZ; + mp->thing_word = MAP_HEADER_FLATMAP; mp->size = num_old; mp->keys = old_mp->keys; diff --git a/erts/emulator/beam/copy.c b/erts/emulator/beam/copy.c index 027b85b079..4d12dae787 100644 --- a/erts/emulator/beam/copy.c +++ b/erts/emulator/beam/copy.c @@ -127,8 +127,25 @@ Uint size_object(Eterm obj) obj = *bptr; break; } - case HASHMAP_SUBTAG: + case MAP_SUBTAG: switch (MAP_HEADER_TYPE(hdr)) { + case MAP_HEADER_TAG_FLATMAP_HEAD : + { + Uint n; + flatmap_t *mp; + mp = (flatmap_t*)flatmap_val_rel(obj,base); + ptr = (Eterm *)mp; + n = flatmap_get_size(mp) + 1; + sum += n + 2; + ptr += 2; /* hdr + size words */ + while (n--) { + obj = *ptr++; + if (!IS_CONST(obj)) { + ESTACK_PUSH(s, obj); + } + } + goto pop_next; + } case MAP_HEADER_TAG_HAMT_HEAD_BITMAP : case MAP_HEADER_TAG_HAMT_HEAD_ARRAY : case MAP_HEADER_TAG_HAMT_NODE_BITMAP : @@ -183,25 +200,7 @@ Uint size_object(Eterm obj) goto pop_next; } break; - case MAP_SUBTAG: - { - Uint n; - flatmap_t *mp; - mp = (flatmap_t*)flatmap_val_rel(obj,base); - ptr = (Eterm *)mp; - n = flatmap_get_size(mp) + 1; - sum += n + 2; - ptr += 2; /* hdr + size words */ - while (n--) { - obj = *ptr++; - if (!IS_CONST(obj)) { - ESTACK_PUSH(s, obj); - } - } - goto pop_next; - } - break; - case BIN_MATCHSTATE_SUBTAG: + case BIN_MATCHSTATE_SUBTAG: erl_exit(ERTS_ABORT_EXIT, "size_object: matchstate term not allowed"); default: @@ -369,15 +368,6 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) } } break; - case MAP_SUBTAG: - { - i = flatmap_get_size(objp) + 3; - *argp = make_flatmap_rel(htop, dst_base); - while (i--) { - *htop++ = *objp++; - } - } - break; case REFC_BINARY_SUBTAG: { ProcBin* pb; @@ -502,9 +492,16 @@ Eterm copy_struct(Eterm obj, Uint sz, Eterm** hpp, ErlOffHeap* off_heap) *argp = make_external_rel(tp, dst_base); } break; - case HASHMAP_SUBTAG: + case MAP_SUBTAG: tp = htop; switch (MAP_HEADER_TYPE(hdr)) { + case MAP_HEADER_TAG_FLATMAP_HEAD : + i = flatmap_get_size(objp) + 3; + *argp = make_flatmap_rel(htop, dst_base); + while (i--) { + *htop++ = *objp++; + } + break; case MAP_HEADER_TAG_HAMT_HEAD_BITMAP : case MAP_HEADER_TAG_HAMT_HEAD_ARRAY : *htop++ = *objp++; diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index 9d699d4b22..0bf562d937 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -2153,16 +2153,16 @@ restart: break; case matchMkFlatMap: n = *pc++; - ehp = HAllocX(build_proc, 1 + MAP_HEADER_SIZE + n, HEAP_XTRA); + ehp = HAllocX(build_proc, 1 + MAP_HEADER_FLATMAP_SZ + n, HEAP_XTRA); t = *ehp++ = *--esp; { flatmap_t *m = (flatmap_t *)ehp; - m->thing_word = MAP_HEADER; + m->thing_word = MAP_HEADER_FLATMAP; m->size = n; m->keys = t; } t = make_flatmap(ehp); - ehp += MAP_HEADER_SIZE; + ehp += MAP_HEADER_FLATMAP_SZ; while (n--) { *ehp++ = *--esp; } @@ -3540,14 +3540,10 @@ static DMCRet dmc_one_term(DMCContext *context, DMC_PUSH(*stack, c); break; case (_TAG_HEADER_MAP >> _TAG_PRIMARY_SIZE): - n = flatmap_get_size(flatmap_val(c)); - DMC_PUSH(*text, matchPushM); - ++(context->stack_used); - DMC_PUSH(*text, n); - DMC_PUSH(*stack, c); - break; - case (_TAG_HEADER_HASHMAP >> _TAG_PRIMARY_SIZE): - n = hashmap_size(c); + if (is_flatmap(c)) + n = flatmap_get_size(flatmap_val(c)); + else + n = hashmap_size(c); DMC_PUSH(*text, matchPushM); ++(context->stack_used); DMC_PUSH(*text, n); diff --git a/erts/emulator/beam/erl_gc.h b/erts/emulator/beam/erl_gc.h index 8afcb060a1..bd6dcc9078 100644 --- a/erts/emulator/beam/erl_gc.h +++ b/erts/emulator/beam/erl_gc.h @@ -55,9 +55,10 @@ do { \ nelts = header_arity(HDR); \ switch ((HDR) & _HEADER_SUBTAG_MASK) { \ case SUB_BINARY_SUBTAG: nelts++; break; \ - case MAP_SUBTAG: nelts+=flatmap_get_size(PTR) + 1; break; \ - case HASHMAP_SUBTAG: nelts=hashmap_bitcount(MAP_HEADER_VAL(HDR)); \ - nelts += is_hashmap_header_head(HDR) ? 1 : 0; break; \ + case MAP_SUBTAG: \ + if (is_flatmap_header(HDR)) nelts+=flatmap_get_size(PTR) + 1; \ + else nelts += hashmap_bitcount(MAP_HEADER_VAL(HDR)); \ + break; \ case FUN_SUBTAG: nelts+=((ErlFunThing*)(PTR))->num_free+1; break; \ } \ gval = make_boxed(HTOP); \ diff --git a/erts/emulator/beam/erl_map.c b/erts/emulator/beam/erl_map.c index 35446501d4..ab40f47919 100644 --- a/erts/emulator/beam/erl_map.c +++ b/erts/emulator/beam/erl_map.c @@ -303,10 +303,10 @@ static Eterm flatmap_from_validated_list(Process *p, Eterm list, Uint size) { hp += size; mp = (flatmap_t*)hp; res = make_flatmap(mp); - hp += MAP_HEADER_SIZE; + hp += MAP_HEADER_FLATMAP_SZ; vs = hp; - mp->thing_word = MAP_HEADER; + mp->thing_word = MAP_HEADER_FLATMAP; mp->size = size; /* set later, might shrink*/ mp->keys = keys; @@ -438,10 +438,10 @@ static Eterm hashmap_from_validated_list(Process *p, Eterm list, Uint size) { ks = hp; hp += n; mp = (flatmap_t*)hp; - hp += MAP_HEADER_SIZE; + hp += MAP_HEADER_FLATMAP_SZ; vs = hp; - mp->thing_word = MAP_HEADER; + mp->thing_word = MAP_HEADER_FLATMAP; mp->size = n; mp->keys = keys; @@ -710,8 +710,7 @@ static Eterm hashmap_from_chunked_array(ErtsHeapFactory *factory, } } - ESTACK_PUSH(stack, res); - ESTACK_PUSH(stack, 1 << slot); + ESTACK_PUSH2(stack,res,1 << slot); /* all of the other nodes .. */ elems = n - 2; /* remove first and last elements */ @@ -755,14 +754,12 @@ static Eterm hashmap_from_chunked_array(ErtsHeapFactory *factory, slot = maskval(v, d); bp = 1 << slot; /* no more collisions */ - ESTACK_PUSH(stack,res); - ESTACK_PUSH(stack,bp); + ESTACK_PUSH2(stack,res,bp); } else if (d == dn) { /* no collisions at all */ slot = maskval(v, d); bp = 1 << slot; - ESTACK_PUSH(stack,res); - ESTACK_PUSH(stack,hdr | bp); + ESTACK_PUSH2(stack,res,hdr | bp); } else { /* dn < n, we have a drop and we are done * build nodes and subtree */ @@ -786,8 +783,7 @@ static Eterm hashmap_from_chunked_array(ErtsHeapFactory *factory, hdr = ESTACK_POP(stack); d--; } - ESTACK_PUSH(stack, res); - ESTACK_PUSH(stack, hdr); + ESTACK_PUSH2(stack,res,hdr); } vp = v; @@ -944,16 +940,16 @@ static Eterm flatmap_merge(Process *p, Eterm nodeA, Eterm nodeB) { n1 = flatmap_get_size(mp1); n2 = flatmap_get_size(mp2); - need = MAP_HEADER_SIZE + 1 + 2*(n1 + n2); + need = MAP_HEADER_FLATMAP_SZ + 1 + 2 * (n1 + n2); hp = HAlloc(p, need); thp = hp; tup = make_tuple(thp); ks = hp + 1; hp += 1 + n1 + n2; - mp_new = (flatmap_t*)hp; hp += MAP_HEADER_SIZE; + mp_new = (flatmap_t*)hp; hp += MAP_HEADER_FLATMAP_SZ; vs = hp; hp += n1 + n2; - mp_new->thing_word = MAP_HEADER; + mp_new->thing_word = MAP_HEADER_FLATMAP; mp_new->size = 0; mp_new->keys = tup; @@ -1008,6 +1004,7 @@ static Eterm flatmap_merge(Process *p, Eterm nodeA, Eterm nodeB) { n = n1 + n2 - unused_size; *thp = make_arityval(n); + mp_new->size = n; /* Reshape map to a hashmap if the map exceeds the limit */ @@ -1043,8 +1040,6 @@ static Eterm flatmap_merge(Process *p, Eterm nodeA, Eterm nodeB) { return res; } - mp_new->size = n; - return make_flatmap(mp_new); } @@ -1344,12 +1339,12 @@ BIF_RETTYPE maps_new_0(BIF_ALIST_0) { Eterm tup; flatmap_t *mp; - hp = HAlloc(BIF_P, (MAP_HEADER_SIZE + 1)); + hp = HAlloc(BIF_P, (MAP_HEADER_FLATMAP_SZ + 1)); tup = make_tuple(hp); *hp++ = make_arityval(0); mp = (flatmap_t*)hp; - mp->thing_word = MAP_HEADER; + mp->thing_word = MAP_HEADER_FLATMAP; mp->size = 0; mp->keys = tup; @@ -1401,7 +1396,7 @@ int erts_maps_remove(Process *p, Eterm key, Eterm map, Eterm *res) { *thp++ = make_arityval(n - 1); *res = make_flatmap(mhp); - *mhp++ = MAP_HEADER; + *mhp++ = MAP_HEADER_FLATMAP; *mhp++ = n - 1; *mhp++ = tup; @@ -1478,9 +1473,9 @@ int erts_maps_update(Process *p, Eterm key, Eterm value, Eterm map, Eterm *res) * assume key-tuple will be intact */ - hp = HAlloc(p, MAP_HEADER_SIZE + n); + hp = HAlloc(p, MAP_HEADER_FLATMAP_SZ + n); shp = hp; - *hp++ = MAP_HEADER; + *hp++ = MAP_HEADER_FLATMAP; *hp++ = n; *hp++ = mp->keys; @@ -1502,7 +1497,7 @@ int erts_maps_update(Process *p, Eterm key, Eterm value, Eterm map, Eterm *res) } } - HRelease(p, shp + MAP_HEADER_SIZE + n, shp); + HRelease(p, shp + MAP_HEADER_FLATMAP_SZ + n, shp); return 0; found_key: @@ -1536,12 +1531,12 @@ Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) { n = flatmap_get_size(mp); if (n == 0) { - hp = HAlloc(p, MAP_HEADER_SIZE + 1 + 2); + hp = HAlloc(p, MAP_HEADER_FLATMAP_SZ + 1 + 2); tup = make_tuple(hp); *hp++ = make_arityval(1); *hp++ = key; res = make_flatmap(hp); - *hp++ = MAP_HEADER; + *hp++ = MAP_HEADER_FLATMAP; *hp++ = 1; *hp++ = tup; *hp++ = value; @@ -1556,10 +1551,10 @@ Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) { * assume key-tuple will be intact */ - hp = HAlloc(p, MAP_HEADER_SIZE + n); + hp = HAlloc(p, MAP_HEADER_FLATMAP_SZ + n); shp = hp; /* save hp, used if optimistic update fails */ res = make_flatmap(hp); - *hp++ = MAP_HEADER; + *hp++ = MAP_HEADER_FLATMAP; *hp++ = n; *hp++ = mp->keys; @@ -1591,7 +1586,7 @@ Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) { /* the map will grow */ if (n >= MAP_SMALL_MAP_LIMIT) { - HRelease(p, shp + MAP_HEADER_SIZE + n, shp); + HRelease(p, shp + MAP_HEADER_FLATMAP_SZ + n, shp); ks = flatmap_get_keys(mp); vs = flatmap_get_values(mp); @@ -1608,7 +1603,7 @@ Eterm erts_maps_put(Process *p, Eterm key, Eterm value, Eterm map) { hp = HAlloc(p, 3 + n + 1); res = make_flatmap(hp); - *hp++ = MAP_HEADER; + *hp++ = MAP_HEADER_FLATMAP; *hp++ = n + 1; *hp++ = tup; @@ -1946,8 +1941,7 @@ int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm node, Uint *sz, slot = hashmap_bitcount(hval & (bp - 1)); n = hashmap_bitcount(hval); - ESTACK_PUSH(*sp, n); - ESTACK_PUSH3(*sp, bp, slot, node); + ESTACK_PUSH4(*sp, n, bp, slot, node); /* occupied */ if (bp & hval) { @@ -1970,8 +1964,7 @@ int erts_hashmap_insert_down(Uint32 hx, Eterm key, Eterm node, Uint *sz, slot = hashmap_bitcount(hval & (bp - 1)); n = hashmap_bitcount(hval); - ESTACK_PUSH(*sp, n); - ESTACK_PUSH3(*sp, bp, slot, node); + ESTACK_PUSH4(*sp, n, bp, slot, node); /* occupied */ if (bp & hval) { @@ -2005,8 +1998,7 @@ insert_subnodes: cix = hashmap_index(chx); while (cix == ix) { - ESTACK_PUSH(*sp, 0); - ESTACK_PUSH3(*sp, 1 << ix, 0, MAP_HEADER_HAMT_NODE_BITMAP(0)); + ESTACK_PUSH4(*sp, 0, 1 << ix, 0, MAP_HEADER_HAMT_NODE_BITMAP(0)); size += HAMT_NODE_BITMAP_SZ(1); hx = hashmap_shift_hash(th,hx,lvl,key); chx = hashmap_shift_hash(th,chx,clvl,ckey); @@ -2194,8 +2186,7 @@ static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, Eterm map) { slot = hashmap_bitcount(hval & (bp - 1)); n = hashmap_bitcount(hval); - ESTACK_PUSH(stack, n); - ESTACK_PUSH3(stack, bp, slot, node); + ESTACK_PUSH4(stack, n, bp, slot, node); /* occupied */ if (bp & hval) { @@ -2214,8 +2205,7 @@ static Eterm hashmap_delete(Process *p, Uint32 hx, Eterm key, Eterm map) { slot = hashmap_bitcount(hval & (bp - 1)); n = hashmap_bitcount(hval); - ESTACK_PUSH(stack, n); - ESTACK_PUSH3(stack, bp, slot, node); + ESTACK_PUSH4(stack, n, bp, slot, node); /* occupied */ if (bp & hval) { @@ -2258,10 +2248,10 @@ unroll: ks = hp; hp += n; mp = (flatmap_t*)hp; - hp += MAP_HEADER_SIZE; + hp += MAP_HEADER_FLATMAP_SZ; vs = hp; - mp->thing_word = MAP_HEADER; + mp->thing_word = MAP_HEADER_FLATMAP; mp->size = n; mp->keys = keys; diff --git a/erts/emulator/beam/erl_map.h b/erts/emulator/beam/erl_map.h index 9fc1a72b68..2cc6768bfc 100644 --- a/erts/emulator/beam/erl_map.h +++ b/erts/emulator/beam/erl_map.h @@ -55,9 +55,9 @@ typedef struct flatmap_s { /* the head-node is a bitmap or array with an untagged size */ -#define hashmap_size(x) (((hashmap_head_t*) hashmap_val(x))->size) +#define hashmap_size(x) (((hashmap_head_t*) hashmap_val(x))->size) #define hashmap_size_rel(RTERM, BASE) hashmap_size(rterm2wterm(RTERM, BASE)) -#define hashmap_make_hash(Key) make_internal_hash(Key) +#define hashmap_make_hash(Key) make_internal_hash(Key) #define hashmap_restore_hash(Heap,Lvl,Key) \ (((Lvl) < 8) ? hashmap_make_hash(Key) >> (4*(Lvl)) : hashmap_make_hash(CONS(Heap, make_small((Lvl)>>3), (Key))) >> (4*((Lvl) & 7))) @@ -66,27 +66,15 @@ typedef struct flatmap_s { /* erl_term.h stuff */ -#define make_flatmap(x) make_boxed((Eterm*)(x)) -#define make_flatmap_rel(x, BASE) make_boxed_rel((Eterm*)(x),(BASE)) -#define is_flatmap(x) (is_boxed((x)) && is_flatmap_header(*boxed_val((x)))) -#define is_flatmap_rel(RTERM,BASE) is_flatmap(rterm2wterm(RTERM,BASE)) -#define is_not_flatmap(x) (!is_flatmap((x))) -#define is_flatmap_header(x) (((x) & (_TAG_HEADER_MASK)) == _TAG_HEADER_MAP) -#define header_is_flatmap(x) ((((x) & (_HEADER_SUBTAG_MASK)) == MAP_SUBTAG)) -#define flatmap_val(x) (_unchecked_boxed_val((x))) -#define flatmap_val_rel(RTERM, BASE) flatmap_val(rterm2wterm(RTERM, BASE)) - -#define flatmap_get_values(x) (((Eterm *)(x)) + 3) -#define flatmap_get_keys(x) (((Eterm *)tuple_val(((flatmap_t *)(x))->keys)) + 1) -#define flatmap_get_size(x) (((flatmap_t*)(x))->size) +#define flatmap_get_values(x) (((Eterm *)(x)) + 3) +#define flatmap_get_keys(x) (((Eterm *)tuple_val(((flatmap_t *)(x))->keys)) + 1) +#define flatmap_get_size(x) (((flatmap_t*)(x))->size) #ifdef DEBUG #define MAP_SMALL_MAP_LIMIT (3) #else #define MAP_SMALL_MAP_LIMIT (32) #endif -#define MAP_HEADER _make_header(1,_TAG_HEADER_MAP) -#define MAP_HEADER_SIZE (sizeof(flatmap_t) / sizeof(Eterm)) struct ErtsWStack_; struct ErtsEStack_; @@ -170,7 +158,10 @@ typedef struct hashmap_head_s { #define is_hashmap_header_head(x) ((MAP_HEADER_TYPE(x) & (0x2))) #define MAKE_MAP_HEADER(Type,Arity,Val) \ - (_make_header(((((Uint16)(Val)) << MAP_HEADER_ARITY_SZ) | (Arity)) << MAP_HEADER_TAG_SZ | (Type) , _TAG_HEADER_HASHMAP)) + (_make_header(((((Uint16)(Val)) << MAP_HEADER_ARITY_SZ) | (Arity)) << MAP_HEADER_TAG_SZ | (Type) , _TAG_HEADER_MAP)) + +#define MAP_HEADER_FLATMAP \ + MAKE_MAP_HEADER(MAP_HEADER_TAG_FLATMAP_HEAD,0x1,0x0) #define MAP_HEADER_HAMT_HEAD_ARRAY \ MAKE_MAP_HEADER(MAP_HEADER_TAG_HAMT_HEAD_ARRAY,0x1,0xffff) @@ -181,15 +172,22 @@ typedef struct hashmap_head_s { #define MAP_HEADER_HAMT_NODE_BITMAP(Bmp) \ MAKE_MAP_HEADER(MAP_HEADER_TAG_HAMT_NODE_BITMAP,0x0,Bmp) -#define HAMT_HEAD_EMPTY_SZ (2) -#define HAMT_HEAD_ARRAY_SZ (18) -#define HAMT_NODE_BITMAP_SZ(n) (1 + n) -#define HAMT_HEAD_BITMAP_SZ(n) (2 + n) +#define MAP_HEADER_FLATMAP_SZ (sizeof(flatmap_t) / sizeof(Eterm)) + +#define HAMT_NODE_ARRAY_SZ (17) +#define HAMT_HEAD_ARRAY_SZ (18) +#define HAMT_NODE_BITMAP_SZ(n) (1 + n) +#define HAMT_HEAD_BITMAP_SZ(n) (2 + n) + +/* 2 bits maps tag + 4 bits subtag + 2 ignore bits */ +#define _HEADER_MAP_SUBTAG_MASK (0xfc) +/* 1 bit map tag + 1 ignore bit + 4 bits subtag + 2 ignore bits */ +#define _HEADER_MAP_HASHMAP_HEAD_MASK (0xbc) -#define _HEADER_MAP_SUBTAG_MASK (0xfc) /* 2 bits maps tag + 4 bits subtag + 2 ignore bits */ -#define HAMT_SUBTAG_NODE_BITMAP ((MAP_HEADER_TAG_HAMT_NODE_BITMAP << _HEADER_ARITY_OFFS) | HASHMAP_SUBTAG) -#define HAMT_SUBTAG_HEAD_ARRAY ((MAP_HEADER_TAG_HAMT_HEAD_ARRAY << _HEADER_ARITY_OFFS) | HASHMAP_SUBTAG) -#define HAMT_SUBTAG_HEAD_BITMAP ((MAP_HEADER_TAG_HAMT_HEAD_BITMAP << _HEADER_ARITY_OFFS) | HASHMAP_SUBTAG) +#define HAMT_SUBTAG_NODE_BITMAP ((MAP_HEADER_TAG_HAMT_NODE_BITMAP << _HEADER_ARITY_OFFS) | MAP_SUBTAG) +#define HAMT_SUBTAG_HEAD_ARRAY ((MAP_HEADER_TAG_HAMT_HEAD_ARRAY << _HEADER_ARITY_OFFS) | MAP_SUBTAG) +#define HAMT_SUBTAG_HEAD_BITMAP ((MAP_HEADER_TAG_HAMT_HEAD_BITMAP << _HEADER_ARITY_OFFS) | MAP_SUBTAG) +#define HAMT_SUBTAG_HEAD_FLATMAP ((MAP_HEADER_TAG_FLATMAP_HEAD << _HEADER_ARITY_OFFS) | MAP_SUBTAG) #define hashmap_index(hash) (((Uint32)hash) & 0xf) diff --git a/erts/emulator/beam/erl_nif.c b/erts/emulator/beam/erl_nif.c index c7c8b3fee3..660f446a52 100644 --- a/erts/emulator/beam/erl_nif.c +++ b/erts/emulator/beam/erl_nif.c @@ -1926,14 +1926,14 @@ int enif_get_map_size(ErlNifEnv* env, ERL_NIF_TERM term, size_t *size) ERL_NIF_TERM enif_make_new_map(ErlNifEnv* env) { - Eterm* hp = alloc_heap(env,MAP_HEADER_SIZE+1); + Eterm* hp = alloc_heap(env,MAP_HEADER_FLATMAP_SZ+1); Eterm tup; flatmap_t *mp; tup = make_tuple(hp); *hp++ = make_arityval(0); mp = (flatmap_t*)hp; - mp->thing_word = MAP_HEADER; + mp->thing_word = MAP_HEADER_FLATMAP; mp->size = 0; mp->keys = tup; diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c index ac5b139f8d..e0dfbd31b8 100644 --- a/erts/emulator/beam/erl_printf_term.c +++ b/erts/emulator/beam/erl_printf_term.c @@ -565,77 +565,74 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, } break; case MAP_DEF: - { - Uint n; - Eterm *ks, *vs; - flatmap_t *mp = (flatmap_t *)flatmap_val(wobj); - n = flatmap_get_size(mp); - ks = flatmap_get_keys(mp); - vs = flatmap_get_values(mp); - - PRINT_CHAR(res, fn, arg, '#'); - PRINT_CHAR(res, fn, arg, '{'); - WSTACK_PUSH(s, PRT_CLOSE_TUPLE); - if (n > 0) { - n--; - WSTACK_PUSH5(s, vs[n], PRT_TERM, PRT_ASSOC, ks[n], PRT_TERM); - while (n--) { - WSTACK_PUSH6(s, PRT_COMMA, vs[n], PRT_TERM, PRT_ASSOC, - ks[n], PRT_TERM); - } - } - } - break; - case HASHMAP_DEF: - { - Uint n,mapval; - Eterm *head; - head = hashmap_val(wobj); - mapval = MAP_HEADER_VAL(*head); - switch (MAP_HEADER_TYPE(*head)) { - case MAP_HEADER_TAG_HAMT_HEAD_ARRAY: - case MAP_HEADER_TAG_HAMT_HEAD_BITMAP: - PRINT_STRING(res, fn, arg, "#<"); - PRINT_UWORD(res, fn, arg, 'x', 0, 1, mapval); - PRINT_STRING(res, fn, arg, ">{"); - WSTACK_PUSH(s,PRT_CLOSE_TUPLE); - n = hashmap_bitcount(mapval); - ASSERT(n < 17); - head += 2; - if (n > 0) { - n--; - WSTACK_PUSH(s, head[n]); - WSTACK_PUSH(s, PRT_TERM); - while (n--) { - WSTACK_PUSH(s, PRT_COMMA); - WSTACK_PUSH(s, head[n]); - WSTACK_PUSH(s, PRT_TERM); - } - } - break; - case MAP_HEADER_TAG_HAMT_NODE_BITMAP: - n = hashmap_bitcount(mapval); - head++; - PRINT_CHAR(res, fn, arg, '<'); - PRINT_UWORD(res, fn, arg, 'x', 0, 1, mapval); - PRINT_STRING(res, fn, arg, ">{"); - WSTACK_PUSH(s,PRT_CLOSE_TUPLE); - ASSERT(n < 17); - if (n > 0) { - n--; - WSTACK_PUSH(s, head[n]); - WSTACK_PUSH(s, PRT_TERM); - while (n--) { - WSTACK_PUSH(s, PRT_COMMA); - WSTACK_PUSH(s, head[n]); - WSTACK_PUSH(s, PRT_TERM); - } - } - break; - } - } - break; - default: + if (is_flatmap(wobj)) { + Uint n; + Eterm *ks, *vs; + flatmap_t *mp = (flatmap_t *)flatmap_val(wobj); + n = flatmap_get_size(mp); + ks = flatmap_get_keys(mp); + vs = flatmap_get_values(mp); + + PRINT_CHAR(res, fn, arg, '#'); + PRINT_CHAR(res, fn, arg, '{'); + WSTACK_PUSH(s, PRT_CLOSE_TUPLE); + if (n > 0) { + n--; + WSTACK_PUSH5(s, vs[n], PRT_TERM, PRT_ASSOC, ks[n], PRT_TERM); + while (n--) { + WSTACK_PUSH6(s, PRT_COMMA, vs[n], PRT_TERM, PRT_ASSOC, + ks[n], PRT_TERM); + } + } + } else { + Uint n, mapval; + Eterm *head; + head = hashmap_val(wobj); + mapval = MAP_HEADER_VAL(*head); + switch (MAP_HEADER_TYPE(*head)) { + case MAP_HEADER_TAG_HAMT_HEAD_ARRAY: + case MAP_HEADER_TAG_HAMT_HEAD_BITMAP: + PRINT_STRING(res, fn, arg, "#<"); + PRINT_UWORD(res, fn, arg, 'x', 0, 1, mapval); + PRINT_STRING(res, fn, arg, ">{"); + WSTACK_PUSH(s,PRT_CLOSE_TUPLE); + n = hashmap_bitcount(mapval); + ASSERT(n < 17); + head += 2; + if (n > 0) { + n--; + WSTACK_PUSH(s, head[n]); + WSTACK_PUSH(s, PRT_TERM); + while (n--) { + WSTACK_PUSH(s, PRT_COMMA); + WSTACK_PUSH(s, head[n]); + WSTACK_PUSH(s, PRT_TERM); + } + } + break; + case MAP_HEADER_TAG_HAMT_NODE_BITMAP: + n = hashmap_bitcount(mapval); + head++; + PRINT_CHAR(res, fn, arg, '<'); + PRINT_UWORD(res, fn, arg, 'x', 0, 1, mapval); + PRINT_STRING(res, fn, arg, ">{"); + WSTACK_PUSH(s,PRT_CLOSE_TUPLE); + ASSERT(n < 17); + if (n > 0) { + n--; + WSTACK_PUSH(s, head[n]); + WSTACK_PUSH(s, PRT_TERM); + while (n--) { + WSTACK_PUSH(s, PRT_COMMA); + WSTACK_PUSH(s, head[n]); + WSTACK_PUSH(s, PRT_TERM); + } + } + break; + } + } + break; + default: PRINT_STRING(res, fn, arg, "<unknown:"); PRINT_POINTER(res, fn, arg, wobj); PRINT_CHAR(res, fn, arg, '>'); diff --git a/erts/emulator/beam/erl_term.c b/erts/emulator/beam/erl_term.c index d6fb88ea61..bc04d7b78e 100644 --- a/erts/emulator/beam/erl_term.c +++ b/erts/emulator/beam/erl_term.c @@ -90,7 +90,6 @@ unsigned tag_val_def(Wterm x) case (_TAG_HEADER_REFC_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF; case (_TAG_HEADER_HEAP_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF; case (_TAG_HEADER_SUB_BIN >> _TAG_PRIMARY_SIZE): return BINARY_DEF; - case (_TAG_HEADER_HASHMAP >> _TAG_PRIMARY_SIZE): return HASHMAP_DEF; } break; diff --git a/erts/emulator/beam/erl_term.h b/erts/emulator/beam/erl_term.h index 1625a4ec15..095aa54ddd 100644 --- a/erts/emulator/beam/erl_term.h +++ b/erts/emulator/beam/erl_term.h @@ -141,29 +141,27 @@ struct erl_node_; /* Declared in erl_node_tables.h */ #define HEAP_BINARY_SUBTAG (0x9 << _TAG_PRIMARY_SIZE) /* BINARY */ #define SUB_BINARY_SUBTAG (0xA << _TAG_PRIMARY_SIZE) /* BINARY */ /* _BINARY_XXX_MASK depends on 0xB being unused */ -#define HASHMAP_SUBTAG (0xB << _TAG_PRIMARY_SIZE) /* HASHMAP */ #define EXTERNAL_PID_SUBTAG (0xC << _TAG_PRIMARY_SIZE) /* EXTERNAL_PID */ #define EXTERNAL_PORT_SUBTAG (0xD << _TAG_PRIMARY_SIZE) /* EXTERNAL_PORT */ #define EXTERNAL_REF_SUBTAG (0xE << _TAG_PRIMARY_SIZE) /* EXTERNAL_REF */ #define MAP_SUBTAG (0xF << _TAG_PRIMARY_SIZE) /* MAP */ -#define _TAG_HEADER_ARITYVAL (TAG_PRIMARY_HEADER|ARITYVAL_SUBTAG) -#define _TAG_HEADER_FUN (TAG_PRIMARY_HEADER|FUN_SUBTAG) -#define _TAG_HEADER_POS_BIG (TAG_PRIMARY_HEADER|POS_BIG_SUBTAG) -#define _TAG_HEADER_NEG_BIG (TAG_PRIMARY_HEADER|NEG_BIG_SUBTAG) -#define _TAG_HEADER_FLOAT (TAG_PRIMARY_HEADER|FLOAT_SUBTAG) -#define _TAG_HEADER_EXPORT (TAG_PRIMARY_HEADER|EXPORT_SUBTAG) -#define _TAG_HEADER_REF (TAG_PRIMARY_HEADER|REF_SUBTAG) -#define _TAG_HEADER_REFC_BIN (TAG_PRIMARY_HEADER|REFC_BINARY_SUBTAG) -#define _TAG_HEADER_HEAP_BIN (TAG_PRIMARY_HEADER|HEAP_BINARY_SUBTAG) -#define _TAG_HEADER_SUB_BIN (TAG_PRIMARY_HEADER|SUB_BINARY_SUBTAG) -#define _TAG_HEADER_EXTERNAL_PID (TAG_PRIMARY_HEADER|EXTERNAL_PID_SUBTAG) -#define _TAG_HEADER_EXTERNAL_PORT (TAG_PRIMARY_HEADER|EXTERNAL_PORT_SUBTAG) -#define _TAG_HEADER_EXTERNAL_REF (TAG_PRIMARY_HEADER|EXTERNAL_REF_SUBTAG) +#define _TAG_HEADER_ARITYVAL (TAG_PRIMARY_HEADER|ARITYVAL_SUBTAG) +#define _TAG_HEADER_FUN (TAG_PRIMARY_HEADER|FUN_SUBTAG) +#define _TAG_HEADER_POS_BIG (TAG_PRIMARY_HEADER|POS_BIG_SUBTAG) +#define _TAG_HEADER_NEG_BIG (TAG_PRIMARY_HEADER|NEG_BIG_SUBTAG) +#define _TAG_HEADER_FLOAT (TAG_PRIMARY_HEADER|FLOAT_SUBTAG) +#define _TAG_HEADER_EXPORT (TAG_PRIMARY_HEADER|EXPORT_SUBTAG) +#define _TAG_HEADER_REF (TAG_PRIMARY_HEADER|REF_SUBTAG) +#define _TAG_HEADER_REFC_BIN (TAG_PRIMARY_HEADER|REFC_BINARY_SUBTAG) +#define _TAG_HEADER_HEAP_BIN (TAG_PRIMARY_HEADER|HEAP_BINARY_SUBTAG) +#define _TAG_HEADER_SUB_BIN (TAG_PRIMARY_HEADER|SUB_BINARY_SUBTAG) +#define _TAG_HEADER_EXTERNAL_PID (TAG_PRIMARY_HEADER|EXTERNAL_PID_SUBTAG) +#define _TAG_HEADER_EXTERNAL_PORT (TAG_PRIMARY_HEADER|EXTERNAL_PORT_SUBTAG) +#define _TAG_HEADER_EXTERNAL_REF (TAG_PRIMARY_HEADER|EXTERNAL_REF_SUBTAG) #define _TAG_HEADER_BIN_MATCHSTATE (TAG_PRIMARY_HEADER|BIN_MATCHSTATE_SUBTAG) -#define _TAG_HEADER_MAP (TAG_PRIMARY_HEADER|MAP_SUBTAG) -#define _TAG_HEADER_HASHMAP (TAG_PRIMARY_HEADER|HASHMAP_SUBTAG) +#define _TAG_HEADER_MAP (TAG_PRIMARY_HEADER|MAP_SUBTAG) #define _TAG_HEADER_MASK 0x3F @@ -302,7 +300,7 @@ _ET_DECLARE_CHECKED(Uint,atom_val,Eterm) #define is_header(x) (((x) & _TAG_PRIMARY_MASK) == TAG_PRIMARY_HEADER) //#define _unchecked_header_arity(x) ((x) >> _HEADER_ARITY_OFFS) #define _unchecked_header_arity(x) \ - (is_hashmap_header(x) ? MAP_HEADER_ARITY(x) : ((x) >> _HEADER_ARITY_OFFS)) + (is_map_header(x) ? MAP_HEADER_ARITY(x) : ((x) >> _HEADER_ARITY_OFFS)) _ET_DECLARE_CHECKED(Uint,header_arity,Eterm) #define header_arity(x) _ET_APPLY(header_arity,(x)) @@ -1001,7 +999,7 @@ _ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm) #define MAP_HEADER_ARITY_SZ (8) #define MAP_HEADER_VAL_SZ (16) -#define MAP_HEADER_TAG_FLAT (0x0) +#define MAP_HEADER_TAG_FLATMAP_HEAD (0x0) #define MAP_HEADER_TAG_HAMT_NODE_BITMAP (0x1) #define MAP_HEADER_TAG_HAMT_HEAD_ARRAY (0x2) #define MAP_HEADER_TAG_HAMT_HEAD_BITMAP (0x3) @@ -1010,17 +1008,27 @@ _ET_DECLARE_CHECKED(struct erl_node_*,external_ref_node,Eterm) #define MAP_HEADER_ARITY(Hdr) (((Hdr) >> (_HEADER_ARITY_OFFS + MAP_HEADER_TAG_SZ)) & (0xff)) #define MAP_HEADER_VAL(Hdr) (((Hdr) >> (_HEADER_ARITY_OFFS + MAP_HEADER_TAG_SZ + MAP_HEADER_ARITY_SZ)) & (0xffff)) -#define make_hashmap(x) make_boxed((Eterm*)(x)) -#define make_hashmap_rel make_boxed_rel -#define is_hashmap(x) (is_boxed((x)) && is_hashmap_header(*boxed_val((x)))) -#define is_not_hashmap(x) (!is_hashmap(x)) -#define is_hashmap_rel(RTERM,BASE) is_hashmap(rterm2wterm(RTERM,BASE)) -#define is_hashmap_header(x) (((x) & (_TAG_HEADER_MASK)) == _TAG_HEADER_HASHMAP) -#define hashmap_val(x) _unchecked_boxed_val((x)) -#define hashmap_val_rel(RTERM, BASE) hashmap_val(rterm2wterm(RTERM, BASE)) - -#define is_map(x) (is_flatmap(x) || is_hashmap(x)) -#define is_map_rel(x,BASE) (is_flatmap_rel(x,BASE) || is_hashmap_rel(x,BASE)) +#define make_hashmap(x) make_boxed((Eterm*)(x)) +#define make_hashmap_rel make_boxed_rel +#define is_hashmap(x) (is_boxed((x)) && is_hashmap_header(*boxed_val((x)))) +#define is_not_hashmap(x) (!is_hashmap(x)) +#define is_hashmap_rel(RTERM,BASE) is_hashmap(rterm2wterm(RTERM,BASE)) +#define is_hashmap_header(x) (((x) & (_HEADER_MAP_HASHMAP_HEAD_MASK)) == HAMT_SUBTAG_HEAD_ARRAY) +#define hashmap_val(x) _unchecked_boxed_val((x)) +#define hashmap_val_rel(RTERM, BASE) hashmap_val(rterm2wterm(RTERM, BASE)) + +#define make_flatmap(x) make_boxed((Eterm*)(x)) +#define make_flatmap_rel(x, BASE) make_boxed_rel((Eterm*)(x),(BASE)) +#define is_flatmap(x) (is_boxed((x)) && is_flatmap_header(*boxed_val((x)))) +#define is_flatmap_rel(RTERM,BASE) is_flatmap(rterm2wterm(RTERM,BASE)) +#define is_not_flatmap(x) (!is_flatmap((x))) +#define is_flatmap_header(x) (((x) & (_HEADER_MAP_SUBTAG_MASK)) == HAMT_SUBTAG_HEAD_FLATMAP) +#define flatmap_val(x) (_unchecked_boxed_val((x))) +#define flatmap_val_rel(RTERM, BASE) flatmap_val(rterm2wterm(RTERM, BASE)) + +#define is_map_header(x) (((x) & (_TAG_HEADER_MASK)) == _TAG_HEADER_MAP) +#define is_map(x) (is_boxed((x)) && is_map_header(*boxed_val(x))) +#define is_map_rel(RTERM,BASE) is_map(rterm2wterm(RTERM,BASE)) /* number tests */ @@ -1113,23 +1121,22 @@ _ET_DECLARE_CHECKED(Uint,y_reg_index,Uint) #define BINARY_DEF 0x0 #define LIST_DEF 0x1 #define NIL_DEF 0x2 -#define HASHMAP_DEF 0x3 -#define MAP_DEF 0x4 -#define TUPLE_DEF 0x5 -#define PID_DEF 0x6 -#define EXTERNAL_PID_DEF 0x7 -#define PORT_DEF 0x8 -#define EXTERNAL_PORT_DEF 0x9 -#define EXPORT_DEF 0xa -#define FUN_DEF 0xb -#define REF_DEF 0xc -#define EXTERNAL_REF_DEF 0xd -#define ATOM_DEF 0xe -#define FLOAT_DEF 0xf -#define BIG_DEF 0x10 -#define SMALL_DEF 0x11 - -#define FIRST_VACANT_TAG_DEF 0x12 +#define MAP_DEF 0x3 +#define TUPLE_DEF 0x4 +#define PID_DEF 0x5 +#define EXTERNAL_PID_DEF 0x6 +#define PORT_DEF 0x7 +#define EXTERNAL_PORT_DEF 0x8 +#define EXPORT_DEF 0x9 +#define FUN_DEF 0xa +#define REF_DEF 0xb +#define EXTERNAL_REF_DEF 0xc +#define ATOM_DEF 0xd +#define FLOAT_DEF 0xe +#define BIG_DEF 0xf +#define SMALL_DEF 0x10 + +#define FIRST_VACANT_TAG_DEF 0x11 #if ET_DEBUG extern unsigned tag_val_def_debug(Wterm, const char*, unsigned); diff --git a/erts/emulator/beam/erl_time_sup.c b/erts/emulator/beam/erl_time_sup.c index ef39f4b5f4..bbdedcc128 100644 --- a/erts/emulator/beam/erl_time_sup.c +++ b/erts/emulator/beam/erl_time_sup.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2012. All Rights Reserved. + * Copyright Ericsson AB 1999-2015. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -139,12 +139,12 @@ struct time_sup_read_only__ { int os_monotonic_time_locked; Uint64 os_monotonic_time_resolution; Uint64 os_monotonic_time_extended; +#endif char *os_system_time_func; char *os_system_time_clock_id; int os_system_time_locked; Uint64 os_system_time_resolution; Uint64 os_system_time_extended; -#endif #if !ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT ErtsMonotonicTime start; struct { @@ -287,7 +287,7 @@ get_time_offset(void) #define ERTS_LONG_TIME_CORRECTION_CHECK ERTS_SEC_TO_MONOTONIC(60) #define ERTS_SHORT_TIME_CORRECTION_CHECK ERTS_SEC_TO_MONOTONIC(15) -#define ERTS_TIME_DRIFT_MAX_ADJ_DIFF ERTS_USEC_TO_MONOTONIC(100) +#define ERTS_TIME_DRIFT_MAX_ADJ_DIFF ERTS_USEC_TO_MONOTONIC(50) #define ERTS_TIME_DRIFT_MIN_ADJ_DIFF ERTS_USEC_TO_MONOTONIC(5) static ERTS_INLINE ErtsMonotonicTime @@ -353,21 +353,21 @@ print_correction(int change, if (!change) fprintf(stderr, - "sdiff = %lld usec : [ec=%lld ppm, dc=%lld ppm] : " + "sdiff = %lld usec : [ec=%lld ppm, dc=%lld ppb] : " "tmo = %lld msec\r\n", (long long) usec_sdiff, (long long) (1000000*old_ecorr) / ERTS_TCORR_ERR_UNIT, - (long long) (1000000*old_dcorr) / ERTS_MONOTONIC_TIME_UNIT, + (long long) (1000000000*old_dcorr) / ERTS_MONOTONIC_TIME_UNIT, (long long) tmo); else fprintf(stderr, - "sdiff = %lld usec : [ec=%lld ppm, dc=%lld ppm] " - "-> [ec=%lld ppm, dc=%lld ppm] : tmo = %lld msec\r\n", + "sdiff = %lld usec : [ec=%lld ppm, dc=%lld ppb] " + "-> [ec=%lld ppm, dc=%lld ppb] : tmo = %lld msec\r\n", (long long) usec_sdiff, (long long) (1000000*old_ecorr) / ERTS_TCORR_ERR_UNIT, - (long long) (1000000*old_dcorr) / ERTS_MONOTONIC_TIME_UNIT, + (long long) (1000000000*old_dcorr) / ERTS_MONOTONIC_TIME_UNIT, (long long) (1000000*new_ecorr) / ERTS_TCORR_ERR_UNIT, - (long long) (1000000*new_dcorr) / ERTS_MONOTONIC_TIME_UNIT, + (long long) (1000000000*new_dcorr) / ERTS_MONOTONIC_TIME_UNIT, (long long) tmo); } @@ -412,8 +412,7 @@ check_time_correction(void *unused) ASSERT(time_sup.inf.c.finalized_offset); - os_mtime = erts_os_monotonic_time(); - os_stime = erts_os_system_time(); + erts_os_times(&os_mtime, &os_stime); cdata = time_sup.inf.c.parmon.cdata; @@ -556,13 +555,6 @@ check_time_correction(void *unused) ddp->acc.mon = mtime_acc; ddp->acc.sys = stime_acc; - /* - * If calculated drift adjustment is if off by more than 20% - * from the average drift we interpret this as a discontinous - * leap in system time and ignore it. If it actually is a - * change in drift we will later detect this when the average - * drift change. - */ drift_adj_diff = avg_drift_adj - drift_adj; if (drift_adj_diff < -ERTS_TIME_DRIFT_MAX_ADJ_DIFF || ERTS_TIME_DRIFT_MAX_ADJ_DIFF < drift_adj_diff) { @@ -691,8 +683,7 @@ init_check_time_correction(void *unused) old_mtime = ddp->intervals[0].time.mon; old_stime = ddp->intervals[0].time.sys; - mtime = erts_os_monotonic_time(); - stime = erts_os_system_time(); + erts_os_times(&mtime, &stime); mtime_diff = mtime - old_mtime; stime_diff = stime - old_stime; @@ -732,8 +723,7 @@ finalize_corrected_time_offset(ErtsSystemTime *stimep) erts_smp_rwmtx_rlock(&time_sup.inf.c.parmon.rwmtx); - os_mtime = erts_os_monotonic_time(); - *stimep = erts_os_system_time(); + erts_os_times(&os_mtime, stimep); cdata = time_sup.inf.c.parmon.cdata; @@ -852,6 +842,7 @@ void erts_init_sys_time_sup(void) = sys_init_time_res.os_monotonic_time_info.resolution; time_sup.r.o.os_monotonic_time_extended = sys_init_time_res.os_monotonic_time_info.extended; +#endif time_sup.r.o.os_system_time_func = sys_init_time_res.os_system_time_info.func; time_sup.r.o.os_system_time_clock_id @@ -860,7 +851,6 @@ void erts_init_sys_time_sup(void) = sys_init_time_res.os_system_time_info.locked_use; time_sup.r.o.os_system_time_resolution = sys_init_time_res.os_system_time_info.resolution; -#endif } int @@ -935,9 +925,11 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode) #endif - resolution = time_sup.r.o.os_monotonic_time_resolution; - if (resolution > time_sup.r.o.os_system_time_resolution) - resolution = time_sup.r.o.os_system_time_resolution; + resolution = time_sup.r.o.os_system_time_resolution; +#ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT + if (resolution > time_sup.r.o.os_monotonic_time_resolution) + resolution = time_sup.r.o.os_monotonic_time_resolution; +#endif time_sup.r.o.adj.large_diff = erts_time_sup__.r.o.monotonic_time_unit; time_sup.r.o.adj.large_diff *= 50; @@ -972,8 +964,8 @@ erts_init_time_sup(int time_correction, ErtsTimeWarpMode time_warp_mode) ErtsMonotonicCorrectionData *cdatap; erts_smp_rwmtx_opt_t rwmtx_opts = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER; ErtsMonotonicTime offset; - time_sup.inf.c.minit = erts_os_monotonic_time(); - time_sup.inf.c.sinit = erts_os_system_time(); + erts_os_times(&time_sup.inf.c.minit, + &time_sup.inf.c.sinit); time_sup.r.o.moffset = -1*time_sup.inf.c.minit; offset = time_sup.inf.c.sinit; offset -= ERTS_MONOTONIC_TIME_UNIT; @@ -1701,7 +1693,7 @@ static void send_time_offset_changed_notifications(void *new_offsetp) { ErtsMonotonicTime new_offset; - ErtsTimeOffsetMonitorInfo *to_mon_info; + ErtsTimeOffsetMonitorInfo *to_mon_info = NULL; /* Shut up faulty warning */ Uint no_monitors; char *tmp = NULL; diff --git a/erts/emulator/beam/external.c b/erts/emulator/beam/external.c index 8f0e19d27d..2117dbec62 100644 --- a/erts/emulator/beam/external.c +++ b/erts/emulator/beam/external.c @@ -2604,7 +2604,7 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, break; case MAP_DEF: - { + if (is_flatmap(obj)) { flatmap_t *mp = (flatmap_t*)flatmap_val(obj); Uint size = flatmap_get_size(mp); @@ -2618,11 +2618,7 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, WSTACK_PUSH4(s, (UWord)kptr, (UWord)vptr, ENC_MAP_PAIR, size); } - } - break; - - case HASHMAP_DEF: - { + } else { Eterm hdr; Uint node_sz; ptr = boxed_val(obj); @@ -2656,7 +2652,6 @@ enc_term_int(TTBEncodeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, byte* ep, } } break; - case FLOAT_DEF: GET_DOUBLE(obj, f); if (dflags & DFLAG_NEW_FLOATS) { @@ -3607,7 +3602,7 @@ dec_term_atom_common: kptr = hp - 1; mp = (flatmap_t*)hp; - hp += MAP_HEADER_SIZE; + hp += MAP_HEADER_FLATMAP_SZ; hp += size; vptr = hp - 1; @@ -3893,7 +3888,7 @@ dec_term_atom_common: while (maps_list) { next = (Eterm *)(EXPAND_POINTER(*maps_list)); - *maps_list = MAP_HEADER; + *maps_list = MAP_HEADER_FLATMAP; if (!erts_validate_and_sort_flatmap((flatmap_t*)maps_list)) goto error; maps_list = next; @@ -4122,7 +4117,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, } break; case MAP_DEF: - { + if (is_flatmap(obj)) { flatmap_t *mp = (flatmap_t*)flatmap_val(obj); Uint size = flatmap_get_size(mp); Uint i; @@ -4157,11 +4152,7 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, ESTACK_PUSH(s,*ptr); } goto outer_loop; - } - break; - - case HASHMAP_DEF: - { + } else { Eterm *ptr; Eterm hdr; Uint node_sz; @@ -4220,7 +4211,6 @@ encode_size_struct_int(TTBSizeContext* ctx, ErtsAtomCacheMap *acmp, Eterm obj, ptr++; } } - break; case FLOAT_DEF: if (dflags & DFLAG_NEW_FLOATS) { diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 46f0eba5e0..1db3a9fba7 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -5354,7 +5354,7 @@ driver_deliver_term(Eterm to, ErlDrvTermData* data, int len) if (ptr[0] > MAP_SMALL_MAP_LIMIT) { need += hashmap_over_estimated_heap_size(ptr[0]); } else { - need += MAP_HEADER_SIZE + 1 + 2*ptr[0]; + need += MAP_HEADER_FLATMAP_SZ + 1 + 2*ptr[0]; } depth -= 2*ptr[0]; if (depth < 0) ERTS_DDT_FAIL; @@ -5627,12 +5627,12 @@ driver_deliver_term(Eterm to, ErlDrvTermData* data, int len) hp += 1 + size; mp = (flatmap_t*)hp; - mp->thing_word = MAP_HEADER; + mp->thing_word = MAP_HEADER_FLATMAP; mp->size = size; mp->keys = make_tuple(tp); mess = make_flatmap(mp); - hp += MAP_HEADER_SIZE + size; /* advance "heap" pointer */ + hp += MAP_HEADER_FLATMAP_SZ + size; tp += size; /* point at last key */ vp = hp - 1; /* point at last value */ diff --git a/erts/emulator/beam/time.c b/erts/emulator/beam/time.c index 3dfd3f79d4..2bdda6c8af 100644 --- a/erts/emulator/beam/time.c +++ b/erts/emulator/beam/time.c @@ -576,7 +576,7 @@ erts_cancel_timer(ErlTimer *p) { ErtsTimerWheel *tiw; ErlCancelProc cancel; - void *arg; + void *arg = NULL; /* Shut up faulty warning... */ tiw = get_timer_wheel(p); if (!tiw) diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index 6edb466a36..cb4ef2b376 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -1025,11 +1025,8 @@ tail_recur: break; } case MAP_DEF: - case HASHMAP_DEF: - { - hash = hash*FUNNY_NUMBER13 + FUNNY_NUMBER14 + make_hash2(term); - break; - } + hash = hash*FUNNY_NUMBER13 + FUNNY_NUMBER14 + make_hash2(term); + break; case TUPLE_DEF: { Eterm* ptr = tuple_val(term); @@ -1273,41 +1270,40 @@ make_hash2(Eterm term) } } break; - case MAP_SUBTAG: - { - flatmap_t *mp = (flatmap_t *)flatmap_val(term); - int i; - int size = flatmap_get_size(mp); - Eterm *ks = flatmap_get_keys(mp); - Eterm *vs = flatmap_get_values(mp); - UINT32_HASH(size, HCONST_16); - if (size == 0) { - goto hash2_common; - } - /* We want a portable hash function that is *independent* of - * the order in which keys and values are encountered. - * We therefore calculate context independent hashes for all . - * key-value pairs and then xor them together. - */ - ESTACK_PUSH(s, hash_xor_pairs); - ESTACK_PUSH(s, hash); - ESTACK_PUSH(s, HASH_MAP_TAIL); - hash = 0; - hash_xor_pairs = 0; - for (i = size - 1; i >= 0; i--) { - ESTACK_PUSH(s, HASH_MAP_PAIR); - ESTACK_PUSH(s, vs[i]); - ESTACK_PUSH(s, ks[i]); - } - goto hash2_common; - } - break; - case HASHMAP_SUBTAG: + case MAP_SUBTAG: { Eterm* ptr = boxed_val(term) + 1; Uint size; int i; switch (hdr & _HEADER_MAP_SUBTAG_MASK) { + case HAMT_SUBTAG_HEAD_FLATMAP: + { + flatmap_t *mp = (flatmap_t *)flatmap_val(term); + Eterm *ks = flatmap_get_keys(mp); + Eterm *vs = flatmap_get_values(mp); + size = flatmap_get_size(mp); + UINT32_HASH(size, HCONST_16); + if (size == 0) + goto hash2_common; + + /* We want a portable hash function that is *independent* of + * the order in which keys and values are encountered. + * We therefore calculate context independent hashes for all . + * key-value pairs and then xor them together. + */ + ESTACK_PUSH(s, hash_xor_pairs); + ESTACK_PUSH(s, hash); + ESTACK_PUSH(s, HASH_MAP_TAIL); + hash = 0; + hash_xor_pairs = 0; + for (i = size - 1; i >= 0; i--) { + ESTACK_PUSH(s, HASH_MAP_PAIR); + ESTACK_PUSH(s, vs[i]); + ESTACK_PUSH(s, ks[i]); + } + goto hash2_common; + } + case HAMT_SUBTAG_HEAD_ARRAY: case HAMT_SUBTAG_HEAD_BITMAP: size = *ptr++; @@ -1675,42 +1671,40 @@ make_internal_hash(Eterm term) } } break; - case MAP_SUBTAG: - { - flatmap_t *mp = (flatmap_t *)flatmap_val(term); - int i; - int size = flatmap_get_size(mp); - Eterm *ks = flatmap_get_keys(mp); - Eterm *vs = flatmap_get_values(mp); - UINT32_HASH(size, HCONST_16); - if (size == 0) { - goto pop_next; - } - /* We want a hash function that is *independent* of - * the order in which keys and values are encountered. - * We therefore calculate context independent hashes for all . - * key-value pairs and then xor them together. - */ - ESTACK_PUSH(s, hash_xor_pairs); - ESTACK_PUSH(s, hash); - ESTACK_PUSH(s, HASH_MAP_TAIL); - hash = 0; - hash_xor_pairs = 0; - for (i = size - 1; i >= 0; i--) { - ESTACK_PUSH(s, HASH_MAP_PAIR); - ESTACK_PUSH(s, vs[i]); - ESTACK_PUSH(s, ks[i]); - } - goto pop_next; - } - break; - case HASHMAP_SUBTAG: + + case MAP_SUBTAG: { Eterm* ptr = boxed_val(term) + 1; Uint size; int i; switch (hdr & _HEADER_MAP_SUBTAG_MASK) { - case HAMT_SUBTAG_HEAD_ARRAY: + case HAMT_SUBTAG_HEAD_FLATMAP: + { + flatmap_t *mp = (flatmap_t *)flatmap_val(term); + Eterm *ks = flatmap_get_keys(mp); + Eterm *vs = flatmap_get_values(mp); + size = flatmap_get_size(mp); + UINT32_HASH(size, HCONST_16); + if (size == 0) + goto pop_next; + + /* We want a hash function that is *independent* of + * the order in which keys and values are encountered. + * We therefore calculate context independent hashes for all . + * key-value pairs and then xor them together. + */ + ESTACK_PUSH(s, hash_xor_pairs); + ESTACK_PUSH(s, hash); + ESTACK_PUSH(s, HASH_MAP_TAIL); + hash = 0; + hash_xor_pairs = 0; + for (i = size - 1; i >= 0; i--) { + ESTACK_PUSH(s, HASH_MAP_PAIR); + ESTACK_PUSH(s, vs[i]); + ESTACK_PUSH(s, ks[i]); + } + goto pop_next; + } case HAMT_SUBTAG_HEAD_BITMAP: size = *ptr++; UINT32_HASH(size, HCONST_16); @@ -2170,11 +2164,8 @@ tail_recur: break; case MAP_DEF: - case HASHMAP_DEF: - { - hash = hash*FUNNY_NUMBER13 + FUNNY_NUMBER14 + make_hash2(term); - break; - } + hash = hash*FUNNY_NUMBER13 + FUNNY_NUMBER14 + make_hash2(term); + break; case TUPLE_DEF: { Eterm* ptr = tuple_val(term); @@ -2579,22 +2570,6 @@ tailrecur_ne: ++bb; goto term_array; } - case MAP_SUBTAG: - { - aa = flatmap_val_rel(a, a_base); - if (!is_boxed(b) || *boxed_val_rel(b,b_base) != *aa) - goto not_equal; - bb = flatmap_val_rel(b,b_base); - sz = flatmap_get_size((flatmap_t*)aa); - - if (sz != flatmap_get_size((flatmap_t*)bb)) goto not_equal; - if (sz == 0) goto pop_next; - - aa += 2; - bb += 2; - sz += 1; /* increment for tuple-keys */ - goto term_array; - } case REFC_BINARY_SUBTAG: case HEAP_BINARY_SUBTAG: case SUB_BINARY_SUBTAG: @@ -2786,8 +2761,23 @@ tailrecur_ne: } break; /* not equal */ } - case HASHMAP_SUBTAG: - { + case MAP_SUBTAG: + if (is_flatmap_rel(a, a_base)) { + aa = flatmap_val_rel(a, a_base); + if (!is_boxed(b) || *boxed_val_rel(b,b_base) != *aa) + goto not_equal; + bb = flatmap_val_rel(b,b_base); + sz = flatmap_get_size((flatmap_t*)aa); + + if (sz != flatmap_get_size((flatmap_t*)bb)) goto not_equal; + if (sz == 0) goto pop_next; + + aa += 2; + bb += 2; + sz += 1; /* increment for tuple-keys */ + goto term_array; + + } else { if (!is_boxed(b) || *boxed_val_rel(b,b_base) != hdr) goto not_equal; @@ -3124,44 +3114,56 @@ tailrecur_ne: ++aa; ++bb; goto term_array; - case (_TAG_HEADER_MAP >> _TAG_PRIMARY_SIZE) : - if (!is_flatmap_rel(b,b_base)) { - a_tag = MAP_DEF; - goto mixed_types; - } - aa = (Eterm *)flatmap_val_rel(a,a_base); - bb = (Eterm *)flatmap_val_rel(b,b_base); - - i = flatmap_get_size((flatmap_t*)aa); - if (i != flatmap_get_size((flatmap_t*)bb)) { - RETURN_NEQ((int)(i - flatmap_get_size((flatmap_t*)bb))); - } - if (i == 0) { - goto pop_next; - } - aa += 2; - bb += 2; - if (exact) { - i += 1; /* increment for tuple-keys */ - goto term_array; - } - else { - /* Value array */ - WSTACK_PUSH3(stack, (UWord)(bb+1), (UWord)(aa+1), TERM_ARRAY_OP_WORD(i)); - /* Switch back from 'exact' key compare */ - WSTACK_PUSH(stack, OP_WORD(SWITCH_EXACT_OFF_OP)); - /* Now do 'exact' compare of key tuples */ - a = *aa; - b = *bb; - exact = 1; - goto bodyrecur; - } - - case (_TAG_HEADER_HASHMAP >> _TAG_PRIMARY_SIZE) : + case (_TAG_HEADER_MAP >> _TAG_PRIMARY_SIZE) : { struct erts_cmp_hashmap_state* sp; + if (is_flatmap_header(ahdr)) { + if (!is_flatmap_rel(b,b_base)) { + if (is_hashmap_rel(b,b_base)) { + aa = (Eterm *)flatmap_val_rel(a,a_base); + i = flatmap_get_size((flatmap_t*)aa) - hashmap_size_rel(b,b_base); + ASSERT(i != 0); + RETURN_NEQ(i); + } + a_tag = MAP_DEF; + goto mixed_types; + } + aa = (Eterm *)flatmap_val_rel(a,a_base); + bb = (Eterm *)flatmap_val_rel(b,b_base); + + i = flatmap_get_size((flatmap_t*)aa); + if (i != flatmap_get_size((flatmap_t*)bb)) { + RETURN_NEQ((int)(i - flatmap_get_size((flatmap_t*)bb))); + } + if (i == 0) { + goto pop_next; + } + aa += 2; + bb += 2; + if (exact) { + i += 1; /* increment for tuple-keys */ + goto term_array; + } + else { + /* Value array */ + WSTACK_PUSH3(stack,(UWord)(bb+1),(UWord)(aa+1),TERM_ARRAY_OP_WORD(i)); + /* Switch back from 'exact' key compare */ + WSTACK_PUSH(stack,OP_WORD(SWITCH_EXACT_OFF_OP)); + /* Now do 'exact' compare of key tuples */ + a = *aa; + b = *bb; + exact = 1; + goto bodyrecur; + } + } if (!is_hashmap_rel(b,b_base)) { - a_tag = HASHMAP_DEF; + if (is_flatmap_rel(b,b_base)) { + bb = (Eterm *)flatmap_val_rel(b,b_base); + i = hashmap_size_rel(a,a_base) - flatmap_get_size((flatmap_t*)bb); + ASSERT(i != 0); + RETURN_NEQ(i); + } + a_tag = MAP_DEF; goto mixed_types; } i = hashmap_size_rel(a,a_base) - hashmap_size_rel(b,b_base); diff --git a/erts/emulator/sys/unix/erl_unix_sys.h b/erts/emulator/sys/unix/erl_unix_sys.h index aa158390d6..8fc5a3ca49 100644 --- a/erts/emulator/sys/unix/erl_unix_sys.h +++ b/erts/emulator/sys/unix/erl_unix_sys.h @@ -171,61 +171,47 @@ typedef long long ErtsSysHrTime; typedef ErtsMonotonicTime ErtsSystemTime; -ErtsSystemTime erts_os_system_time(void); - #define ERTS_MONOTONIC_TIME_MIN (((ErtsMonotonicTime) 1) << 63) #define ERTS_MONOTONIC_TIME_MAX (~ERTS_MONOTONIC_TIME_MIN) /* - * OS monotonic time + * OS monotonic time and OS system time */ -/* - * Most common with os monotonic time using nano second - * time unit. These defines are modified below if this - * isn't the case... - */ -#define ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT 1 -#define ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT (1000*1000*1000) +#undef ERTS_OS_TIMES_INLINE_FUNC_PTR_CALL__ + +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) +# if defined(__linux__) +# define ERTS_OS_TIMES_INLINE_FUNC_PTR_CALL__ 1 +# endif +#endif + +ErtsSystemTime erts_os_system_time(void); +#undef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT +#undef ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT #undef ERTS_OS_MONOTONIC_INLINE_FUNC_PTR_CALL__ #undef ERTS_HAVE_CORRECTED_OS_MONOTONIC #if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) - -#if defined(__linux__) - -#define ERTS_HAVE_CORRECTED_OS_MONOTONIC 1 -#define ERTS_OS_MONOTONIC_INLINE_FUNC_PTR_CALL__ 1 - -#else /* !defined(__linux__) */ - -ErtsMonotonicTime erts_os_monotonic_time(void); - -#endif /* !defined(__linux__) */ - +# define ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT 1 +# define ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT (1000*1000*1000) +# if defined(__linux__) +# define ERTS_HAVE_CORRECTED_OS_MONOTONIC 1 +# define ERTS_OS_MONOTONIC_INLINE_FUNC_PTR_CALL__ 1 +# endif +#elif defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) +# define ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT 1 +# define ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT (1000*1000*1000) #elif defined(OS_MONOTONIC_TIME_USING_GETHRTIME) - -#define erts_os_monotonic() ((ErtsMonotonicTime) gethrtime()) -#define erts_sys_hrtime() ((ErtsSysHrTime) gethrtime()) - -#elif defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) \ - || defined(OS_MONOTONIC_TIME_USING_TIMES) - -#if defined(OS_MONOTONIC_TIME_USING_TIMES) +# define ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT 1 +# define ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT (1000*1000*1000) +#elif defined(OS_MONOTONIC_TIME_USING_TIMES) +# define ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT 1 /* Time unit determined at runtime... */ -# undef ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT # define ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT 0 -#endif - -ErtsMonotonicTime erts_os_monotonic_time(void); - #else /* No OS monotonic available... */ - -#undef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT -#undef ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT -#define ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT (1000*1000) - +# define ERTS_COMPILE_TIME_MONOTONIC_TIME_UNIT (1000*1000) #endif /* @@ -233,14 +219,15 @@ ErtsMonotonicTime erts_os_monotonic_time(void); * time function found. Time unit is nano-seconds. * It may or may not be monotonic. */ -#ifndef erts_sys_hrtime -extern ErtsSysHrTime erts_sys_hrtime(void); -#endif +ErtsSysHrTime erts_sys_hrtime(void); struct erts_sys_time_read_only_data__ { #ifdef ERTS_OS_MONOTONIC_INLINE_FUNC_PTR_CALL__ ErtsMonotonicTime (*os_monotonic_time)(void); #endif +#ifdef ERTS_OS_TIMES_INLINE_FUNC_PTR_CALL__ + void (*os_times)(ErtsMonotonicTime *, ErtsSystemTime *); +#endif int ticks_per_sec; }; @@ -255,21 +242,43 @@ typedef struct { extern ErtsSysTimeData__ erts_sys_time_data__; +#ifdef ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT + #ifdef ERTS_OS_MONOTONIC_INLINE_FUNC_PTR_CALL__ +ERTS_GLB_INLINE +#endif +ErtsMonotonicTime erts_os_monotonic_time(void); -ERTS_GLB_INLINE ErtsMonotonicTime erts_os_monotonic_time(void); +#ifdef ERTS_OS_TIMES_INLINE_FUNC_PTR_CALL__ +ERTS_GLB_INLINE +#endif +void erts_os_times(ErtsMonotonicTime *, ErtsSystemTime *); #if ERTS_GLB_INLINE_INCL_FUNC_DEF +#ifdef ERTS_OS_MONOTONIC_INLINE_FUNC_PTR_CALL__ + ERTS_GLB_INLINE ErtsMonotonicTime erts_os_monotonic_time(void) { return (*erts_sys_time_data__.r.o.os_monotonic_time)(); } +#endif /* ERTS_OS_MONOTONIC_INLINE_FUNC_PTR_CALL__ */ + +#ifdef ERTS_OS_TIMES_INLINE_FUNC_PTR_CALL__ + +ERTS_GLB_INLINE void +erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep) +{ + return (*erts_sys_time_data__.r.o.os_times)(mtimep, stimep); +} + +#endif /* ERTS_OS_TIMES_INLINE_FUNC_PTR_CALL__ */ + #endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */ -#endif /* ERTS_OS_MONOTONIC_INLINE_FUNC_PTR_CALL__ */ +#endif /* ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT */ /* * diff --git a/erts/emulator/sys/unix/sys_time.c b/erts/emulator/sys/unix/sys_time.c index d6591a8296..d535457977 100644 --- a/erts/emulator/sys/unix/sys_time.c +++ b/erts/emulator/sys/unix/sys_time.c @@ -35,6 +35,20 @@ #include "global.h" #include "erl_os_monotonic_time_extender.h" +#undef ERTS_HAVE_ERTS_OS_TIMES_IMPL__ +#undef ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__ + +#if defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) \ + || defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) +# include <mach/clock.h> +# include <mach/mach.h> +# ifdef HAVE_CLOCK_GET_ATTRIBUTES +# define ERTS_HAVE_MACH_CLOCK_GETRES +static Sint64 +mach_clock_getres(clock_id_t clkid, char *clkid_str); +# endif +#endif + #ifdef NO_SYSCONF # define TICKS_PER_SEC() HZ #else @@ -87,6 +101,10 @@ ErtsSysTimeData__ erts_sys_time_data__ erts_align_attribute(ERTS_CACHE_LINE_SIZE static ErtsMonotonicTime clock_gettime_monotonic_raw(void); static ErtsMonotonicTime clock_gettime_monotonic_verified(void); +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) +static void clock_gettime_times_raw(ErtsMonotonicTime *, ErtsSystemTime *); +static void clock_gettime_times_verified(ErtsMonotonicTime *, ErtsSystemTime *); +#endif #endif /* defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) */ @@ -167,6 +185,9 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) init_resp->os_monotonic_time_info.resolution = 1; } } +#elif defined(ERTS_HAVE_MACH_CLOCK_GETRES) && defined(MONOTONIC_CLOCK_ID) + init_resp->os_monotonic_time_info.resolution + = mach_clock_getres(MONOTONIC_CLOCK_ID, MONOTONIC_CLOCK_ID_STR); #endif #ifdef MONOTONIC_CLOCK_ID_STR @@ -197,9 +218,14 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) #if defined(__linux__) && defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) - if (vsn >= ERTS_MK_VSN_INT(2, 6, 33)) + if (vsn >= ERTS_MK_VSN_INT(2, 6, 33)) { erts_sys_time_data__.r.o.os_monotonic_time = clock_gettime_monotonic_raw; +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) + erts_sys_time_data__.r.o.os_times = + clock_gettime_times_raw; +#endif + } else { /* * Linux versions prior to 2.6.33 have a @@ -208,6 +234,10 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) */ erts_sys_time_data__.r.o.os_monotonic_time = clock_gettime_monotonic_verified; +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) + erts_sys_time_data__.r.o.os_times = + clock_gettime_times_verified; +#endif erts_smp_mtx_init(&internal_state.w.f.mtx, "os_monotonic_time"); internal_state.w.f.last_delivered @@ -292,6 +322,9 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) init_resp->os_system_time_info.resolution = 1; } } +#elif defined(ERTS_HAVE_MACH_CLOCK_GETRES) && defined(WALL_CLOCK_ID) + init_resp->os_system_time_info.resolution + = mach_clock_getres(WALL_CLOCK_ID, WALL_CLOCK_ID_STR); #endif #if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) @@ -303,7 +336,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) init_resp->os_system_time_info.resolution = 1000*1000; init_resp->os_system_time_info.clock_id = NULL; #else -# error Missing erts_os_system_time() implmenentation +# error Missing erts_os_system_time() implementation #endif } @@ -333,117 +366,98 @@ adj_stime_time_unit(ErtsSystemTime stime, Uint32 res) (Uint32) ERTS_MONOTONIC_TIME_UNIT)); } -#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ + * POSIX clock_gettime() * +\* */ -ErtsSystemTime -erts_os_system_time(void) +#if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) \ + || defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) + +static ERTS_INLINE ErtsMonotonicTime +timespec2montime(struct timespec *ts) +{ + ErtsMonotonicTime time; + time = (ErtsMonotonicTime) ts->tv_sec; + time *= (ErtsMonotonicTime) 1000*1000*1000; + time += (ErtsMonotonicTime) ts->tv_nsec; + return time; +} + +static ERTS_INLINE ErtsMonotonicTime +posix_clock_gettime(clockid_t id, char *name) { - ErtsSystemTime stime; struct timespec ts; - if (clock_gettime(WALL_CLOCK_ID,&ts) != 0) { + if (clock_gettime(id, &ts) != 0) { int err = errno; char *errstr = err ? strerror(err) : "unknown"; erl_exit(ERTS_ABORT_EXIT, "clock_gettime(%s, _) failed: %s (%d)\n", - WALL_CLOCK_ID_STR, errstr, err); - + name, errstr, err); } - - stime = (ErtsSystemTime) ts.tv_sec; - stime *= (ErtsSystemTime) 1000*1000*1000; - stime += (ErtsSystemTime) ts.tv_nsec; - return adj_stime_time_unit(stime, (Uint32) 1000*1000*1000); + return timespec2montime(&ts); } -#elif defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) +#endif /* defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) \ + || defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */ + +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) ErtsSystemTime erts_os_system_time(void) { ErtsSystemTime stime; - kern_return_t res; - clock_serv_t clk_srv; - mach_timespec_t time_spec; - int err; - - host_get_clock_service(mach_host_self(), - WALL_CLOCK_ID, - &clk_srv); - errno = 0; - res = clock_get_time(clk_srv, &time_spec); - err = errno; - mach_port_deallocate(mach_task_self(), clk_srv); - if (res != KERN_SUCCESS) { - char *errstr = err ? strerror(err) : "unknown"; - erl_exit(ERTS_ABORT_EXIT, - "clock_get_time(%s, _) failed: %s (%d)\n", - MONOTONIC_CLOCK_ID_STR, errstr, err); - } - - stime = (ErtsSystemTime) time_spec.tv_sec; - stime *= (ErtsSystemTime) 1000*1000*1000; - stime += (ErtsSystemTime) time_spec.tv_nsec; + stime = (ErtsSystemTime) posix_clock_gettime(WALL_CLOCK_ID, + WALL_CLOCK_ID_STR); return adj_stime_time_unit(stime, (Uint32) 1000*1000*1000); } -#elif defined(OS_SYSTEM_TIME_GETTIMEOFDAY) - -ErtsSystemTime -erts_os_system_time(void) -{ - ErtsSystemTime stime; - struct timeval tv; - - if (gettimeofday(&tv, NULL) != 0) { - int err = errno; - char *errstr = err ? strerror(err) : "unknown"; - erl_exit(ERTS_ABORT_EXIT, - "gettimeofday(_, NULL) failed: %s (%d)\n", - errstr, err); - } - - stime = (ErtsSystemTime) tv.tv_sec; - stime *= (ErtsSystemTime) 1000*1000; - stime += (ErtsSystemTime) tv.tv_usec; +#endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */ - return adj_stime_time_unit(stime, (Uint32) 1000*1000); -} +#if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) -#else -# error Missing erts_os_system_time() implmenentation -#endif +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) -#if defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) +#define ERTS_HAVE_ERTS_OS_TIMES_IMPL__ -static ERTS_INLINE ErtsMonotonicTime -clock_gettime_monotonic(void) +static ERTS_INLINE void +posix_clock_gettime_times(ErtsMonotonicTime *mtimep, + ErtsSystemTime *stimep) { - ErtsMonotonicTime mtime; - struct timespec ts; + struct timespec mts, sts; + int mres, sres, merr, serr; - if (clock_gettime(MONOTONIC_CLOCK_ID,&ts) != 0) { - int err = errno; - char *errstr = err ? strerror(err) : "unknown"; + mres = clock_gettime(MONOTONIC_CLOCK_ID, &mts); + merr = errno; + sres = clock_gettime(WALL_CLOCK_ID, &sts); + serr = errno; + + if (mres != 0) { + char *errstr = merr ? strerror(merr) : "unknown"; erl_exit(ERTS_ABORT_EXIT, "clock_gettime(%s, _) failed: %s (%d)\n", - MONOTONIC_CLOCK_ID_STR, errstr, err); - + MONOTONIC_CLOCK_ID_STR, errstr, merr); } - mtime = (ErtsMonotonicTime) ts.tv_sec; - mtime *= (ErtsMonotonicTime) 1000*1000*1000; - mtime += (ErtsMonotonicTime) ts.tv_nsec; - return mtime; + if (sres != 0) { + char *errstr = serr ? strerror(serr) : "unknown"; + erl_exit(ERTS_ABORT_EXIT, + "clock_gettime(%s, _) failed: %s (%d)\n", + WALL_CLOCK_ID_STR, errstr, serr); + } + + *mtimep = timespec2montime(&mts); + *stimep = (ErtsSystemTime) timespec2montime(&sts); } +#endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */ + #if defined(__linux__) static ErtsMonotonicTime clock_gettime_monotonic_verified(void) { - ErtsMonotonicTime mtime; - - mtime = clock_gettime_monotonic(); + ErtsMonotonicTime mtime = posix_clock_gettime(MONOTONIC_CLOCK_ID, + MONOTONIC_CLOCK_ID_STR); erts_smp_mtx_lock(&internal_state.w.f.mtx); if (mtime < internal_state.w.f.last_delivered) @@ -455,66 +469,296 @@ static ErtsMonotonicTime clock_gettime_monotonic_verified(void) return mtime; } +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) + +static void clock_gettime_times_verified(ErtsMonotonicTime *mtimep, + ErtsSystemTime *stimep) +{ + posix_clock_gettime_times(mtimep, stimep); + + erts_smp_mtx_lock(&internal_state.w.f.mtx); + if (*mtimep < internal_state.w.f.last_delivered) + *mtimep = internal_state.w.f.last_delivered; + else + internal_state.w.f.last_delivered = *mtimep; + erts_smp_mtx_unlock(&internal_state.w.f.mtx); +} + +#endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */ + static ErtsMonotonicTime clock_gettime_monotonic_raw(void) { - return clock_gettime_monotonic(); + return posix_clock_gettime(MONOTONIC_CLOCK_ID, + MONOTONIC_CLOCK_ID_STR); +} + +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) + +static void clock_gettime_times_raw(ErtsMonotonicTime *mtimep, + ErtsSystemTime *stimep) +{ + posix_clock_gettime_times(mtimep, stimep); } +#endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */ + #else /* !defined(__linux__) */ ErtsMonotonicTime erts_os_monotonic_time(void) { - return clock_gettime_monotonic(); + return posix_clock_gettime(MONOTONIC_CLOCK_ID, + MONOTONIC_CLOCK_ID_STR); } +#if defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) + +void erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep) +{ + posix_clock_gettime_times(mtimep, stimep); +} + +#endif /* defined(OS_SYSTEM_TIME_USING_CLOCK_GETTIME) */ + #endif /* !defined(__linux__) */ +#define ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__ + ErtsSysHrTime erts_sys_hrtime(void) { - return (ErtsSysHrTime) clock_gettime_monotonic(); + return (ErtsSysHrTime) posix_clock_gettime(MONOTONIC_CLOCK_ID, + MONOTONIC_CLOCK_ID_STR); } -#elif defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) +#endif /* defined(OS_MONOTONIC_TIME_USING_CLOCK_GETTIME) */ -#include <mach/clock.h> -#include <mach/mach.h> +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ + * MACH clock_get_time() * +\* */ -ErtsMonotonicTime erts_os_monotonic_time(void) +#if defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) \ + || defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) + +#ifdef ERTS_HAVE_MACH_CLOCK_GETRES + +static Sint64 +mach_clock_getres(clock_id_t clkid, char *clkid_str) { - ErtsMonotonicTime mtime; - kern_return_t res; + mach_port_t task; + host_name_port_t host; + natural_t attr[1]; + kern_return_t kret; + clock_serv_t clk_srv; + mach_msg_type_number_t cnt; + + host = mach_host_self(); + kret = host_get_clock_service(host, clkid, &clk_srv); + if (kret != KERN_SUCCESS) { + erl_exit(ERTS_ABORT_EXIT, + "host_get_clock_service(_, %s, _) failed\n", + clkid_str); + } + + cnt = sizeof(attr); + kret = clock_get_attributes(clk_srv, CLOCK_GET_TIME_RES, (clock_attr_t) attr, &cnt); + if (kret != KERN_SUCCESS) { + erl_exit(ERTS_ABORT_EXIT, + "clock_get_attributes(%s, _) failed\n", + clkid_str); + } + task = mach_task_self(); + mach_port_deallocate(task, host); + mach_port_deallocate(task, clk_srv); + + return (Sint64) attr[0]; +} + +#endif /* ERTS_HAVE_MACH_CLOCK_GETRES */ + +static ERTS_INLINE Sint64 +mach_clock_gettime(clock_id_t clkid, char *clkid_str) +{ + Sint64 time; + mach_port_t task; + host_name_port_t host; + kern_return_t kret; clock_serv_t clk_srv; mach_timespec_t time_spec; - int err; - host_get_clock_service(mach_host_self(), - MONOTONIC_CLOCK_ID, - &clk_srv); + host = mach_host_self(); + kret = host_get_clock_service(host, clkid, &clk_srv); + if (kret != KERN_SUCCESS) { + erl_exit(ERTS_ABORT_EXIT, + "host_get_clock_service(_, %s, _) failed\n", + clkid_str); + } errno = 0; - res = clock_get_time(clk_srv, &time_spec); - err = errno; - mach_port_deallocate(mach_task_self(), clk_srv); - if (res != KERN_SUCCESS) { - char *errstr = err ? strerror(err) : "unknown"; + kret = clock_get_time(clk_srv, &time_spec); + if (kret != KERN_SUCCESS) { erl_exit(ERTS_ABORT_EXIT, - "clock_get_time(%s, _) failed: %s (%d)\n", - MONOTONIC_CLOCK_ID_STR, errstr, err); + "clock_get_time(%s, _) failed\n", + clkid_str); } + task = mach_task_self(); + mach_port_deallocate(task, host); + mach_port_deallocate(task, clk_srv); + + time = (Sint64) time_spec.tv_sec; + time *= (Sint64) 1000*1000*1000; + time += (Sint64) time_spec.tv_nsec; + return time; +} + +#endif /* defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) \ + || defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) */ + +#if defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) + +#define ERTS_HAVE_ERTS_OS_TIMES_IMPL__ + +ErtsSystemTime +erts_os_system_time(void) +{ + ErtsSystemTime stime; + stime = (ErtsSystemTime) mach_clock_gettime(WALL_CLOCK_ID, + WALL_CLOCK_ID_STR); + return adj_stime_time_unit(stime, (Uint32) 1000*1000*1000); +} - mtime = (ErtsMonotonicTime) time_spec.tv_sec; +#endif /* defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) */ + +#if defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) + +ErtsMonotonicTime +erts_os_monotonic_time(void) +{ + return (ErtsMonotonicTime) mach_clock_gettime(MONOTONIC_CLOCK_ID, + MONOTONIC_CLOCK_ID_STR); +} + +#define ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__ + +ErtsSysHrTime +erts_sys_hrtime(void) +{ + return (ErtsMonotonicTime) mach_clock_gettime(MONOTONIC_CLOCK_ID, + MONOTONIC_CLOCK_ID_STR); +} + +#if defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) + +#define ERTS_HAVE_ERTS_OS_TIMES_IMPL__ + +void +erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep) +{ + ErtsMonotonicTime mtime; + ErtsSystemTime stime; + mach_port_t task; + host_name_port_t host; + kern_return_t mkret, skret; + clock_serv_t mclk_srv, sclk_srv; + mach_timespec_t mon_time_spec, sys_time_spec; + + host = mach_host_self(); + mkret = host_get_clock_service(host, MONOTONIC_CLOCK_ID, &mclk_srv); + skret = host_get_clock_service(host, WALL_CLOCK_ID, &sclk_srv); + if (mkret != KERN_SUCCESS) { + erl_exit(ERTS_ABORT_EXIT, + "host_get_clock_service(_, %s, _) failed\n", + MONOTONIC_CLOCK_ID); + } + if (skret != KERN_SUCCESS) { + erl_exit(ERTS_ABORT_EXIT, + "host_get_clock_service(_, %s, _) failed\n", + WALL_CLOCK_ID); + } + mkret = clock_get_time(mclk_srv, &mon_time_spec); + skret = clock_get_time(sclk_srv, &sys_time_spec); + if (mkret != KERN_SUCCESS) { + erl_exit(ERTS_ABORT_EXIT, + "clock_get_time(%s, _) failed\n", + MONOTONIC_CLOCK_ID); + } + if (skret != KERN_SUCCESS) { + erl_exit(ERTS_ABORT_EXIT, + "clock_get_time(%s, _) failed\n", + WALL_CLOCK_ID); + } + task = mach_task_self(); + mach_port_deallocate(task, host); + mach_port_deallocate(task, mclk_srv); + mach_port_deallocate(task, sclk_srv); + + mtime = (ErtsMonotonicTime) mon_time_spec.tv_sec; mtime *= (ErtsMonotonicTime) 1000*1000*1000; - mtime += (ErtsMonotonicTime) time_spec.tv_nsec; - return mtime; + mtime += (ErtsMonotonicTime) mon_time_spec.tv_nsec; + stime = (ErtsSystemTime) sys_time_spec.tv_sec; + stime *= (ErtsSystemTime) 1000*1000*1000; + stime += (ErtsSystemTime) sys_time_spec.tv_nsec; + *mtimep = mtime; + *stimep = stime; } +#endif /* defined(OS_SYSTEM_TIME_USING_MACH_CLOCK_GET_TIME) */ + +#endif /* defined(OS_MONOTONIC_TIME_USING_MACH_CLOCK_GET_TIME) */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ + * Solaris gethrtime() - OS monotonic time * +\* */ + +#if defined(OS_MONOTONIC_TIME_USING_GETHRTIME) + +ErtsMonotonicTime erts_os_monotonic_time(void) +{ + return (ErtsMonotonicTime) gethrtime(); +} + +#define ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__ + ErtsSysHrTime erts_sys_hrtime(void) { - return (ErtsSysHrTime) erts_os_monotonic_time(); + return (ErtsSysHrTime) gethrtime(); } -#elif defined(OS_MONOTONIC_TIME_USING_TIMES) +#endif /* defined(OS_MONOTONIC_TIME_USING_GETHRTIME) */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ + * gettimeofday() - OS system time * +\* */ + +#if defined(OS_SYSTEM_TIME_GETTIMEOFDAY) + +ErtsSystemTime +erts_os_system_time(void) +{ + ErtsSystemTime stime; + struct timeval tv; + + if (gettimeofday(&tv, NULL) != 0) { + int err = errno; + char *errstr = err ? strerror(err) : "unknown"; + erl_exit(ERTS_ABORT_EXIT, + "gettimeofday(_, NULL) failed: %s (%d)\n", + errstr, err); + } + + stime = (ErtsSystemTime) tv.tv_sec; + stime *= (ErtsSystemTime) 1000*1000; + stime += (ErtsSystemTime) tv.tv_usec; + + return adj_stime_time_unit(stime, (Uint32) 1000*1000); +} + +#endif /* defined(OS_SYSTEM_TIME_GETTIMEOFDAY) */ + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ + * times() - OS monotonic time * +\* */ + +#if defined(OS_MONOTONIC_TIME_USING_TIMES) ErtsMonotonicTime erts_os_monotonic_time(void) @@ -526,29 +770,35 @@ erts_os_monotonic_time(void) ticks) << internal_state.r.o.times_shift; } -# define ERTS_NEED_ERTS_SYS_HRTIME_FALLBACK - -#else /* !defined(OS_MONOTONIC_TIME_USING_TIMES) */ -/* No os-monotonic-time */ -# define ERTS_NEED_ERTS_SYS_HRTIME_FALLBACK #endif -#ifdef ERTS_NEED_ERTS_SYS_HRTIME_FALLBACK +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\ + * Fallbacks * +\* */ + +#ifndef ERTS_HAVE_ERTS_SYS_HRTIME_IMPL__ ErtsSysHrTime erts_sys_hrtime(void) { - ErtsSysHrTime time; - struct timeval tv; - gettimeofday(&tv); - time = (ErtsSysHrTime) tv.tv_sec; - time *= (ErtsSysHrTime) 1000*1000*1000; - time += ((ErtsSysHrTime) tv.tv_usec)*1000; - return time; + return (ErtsSysHrTime) ERTS_MONOTONIC_TO_NSEC(erts_os_system_time()); +} + +#endif + +#if !defined(ERTS_HAVE_ERTS_OS_TIMES_IMPL__) \ + && defined(ERTS_HAVE_OS_MONOTONIC_TIME_SUPPORT) + +void +erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep) +{ + *mtimep = erts_os_monotonic_time(); + *stimep = erts_os_system_time(); } #endif +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #ifdef HAVE_GETHRVTIME_PROCFS_IOCTL diff --git a/erts/emulator/sys/win32/erl_win_sys.h b/erts/emulator/sys/win32/erl_win_sys.h index 9aeb460720..5181d6b584 100644 --- a/erts/emulator/sys/win32/erl_win_sys.h +++ b/erts/emulator/sys/win32/erl_win_sys.h @@ -193,6 +193,7 @@ ErtsSystemTime erts_os_system_time(void); struct erts_sys_time_read_only_data__ { ErtsMonotonicTime (*os_monotonic_time)(void); + void (*os_times)(ErtsMonotonicTime *, ErtsSystemTime*); ErtsSysHrTime (*sys_hrtime)(void); }; @@ -208,6 +209,8 @@ typedef struct { extern ErtsSysTimeData__ erts_sys_time_data__; ERTS_GLB_INLINE ErtsMonotonicTime erts_os_monotonic_time(void); +ERTS_GLB_INLINE void erts_os_times(ErtsMonotonicTime *, + ErtsSystemTime *); ERTS_GLB_INLINE ErtsSysHrTime erts_sys_hrtime(void); #if ERTS_GLB_INLINE_INCL_FUNC_DEF @@ -218,6 +221,12 @@ erts_os_monotonic_time(void) return (*erts_sys_time_data__.r.o.os_monotonic_time)(); } +ERTS_GLB_INLINE void +erts_os_times(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep) +{ + return (*erts_sys_time_data__.r.o.os_times)(mtimep, stimep); +} + ERTS_GLB_INLINE ErtsSysHrTime erts_sys_hrtime(void) { diff --git a/erts/emulator/sys/win32/sys_time.c b/erts/emulator/sys/win32/sys_time.c index da9c4d2e29..b292d9279e 100644 --- a/erts/emulator/sys/win32/sys_time.c +++ b/erts/emulator/sys/win32/sys_time.c @@ -119,6 +119,24 @@ __declspec(align(ASSUMED_CACHE_LINE_SIZE)) struct { __declspec(align(ASSUMED_CACHE_LINE_SIZE)) ErtsSysTimeData__ erts_sys_time_data__; + +static ERTS_INLINE ErtsSystemTime +SystemTime2MilliSec(SYSTEMTIME *stp) +{ + ErtsSystemTime stime; + FILETIME ft; + ULARGE_INTEGER ull; + + SystemTimeToFileTime(stp, &ft); + FILETIME_TO_ULI(ull,ft); + /* now in 100 ns units */ + stime = (ErtsSystemTime) ull.QuadPart; + stime -= (((ErtsSystemTime) EPOCH_JULIAN_DIFF) + * ((ErtsSystemTime) (10*1000*1000))); + stime /= (ErtsSystemTime) (10*1000); /* ms */ + return stime; +} + static ErtsMonotonicTime os_monotonic_time_qpc(void) { @@ -130,6 +148,30 @@ os_monotonic_time_qpc(void) return (ErtsMonotonicTime) pc.QuadPart; } +static void +os_times_qpc(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep) +{ + LARGE_INTEGER pc; + SYSTEMTIME st; + ErtsSystemTime stime; + BOOL qpcr; + + qpcr = (*internal_state.r.o.pQueryPerformanceCounter)(&pc); + GetSystemTime(&st); + + if (!qpcr) + erl_exit(ERTS_ABORT_EXIT, "QueryPerformanceCounter() failed\n"); + + *mtimep = (ErtsMonotonicTime) pc.QuadPart; + + stime = SystemTime2MilliSec(&st); + + *stimep = ((ErtsSystemTime) + erts_time_unit_conversion((Uint64) stime, + (Uint32) 1000, + internal_state.r.o.pcf)); +} + static Uint32 get_tick_count(void) { @@ -139,18 +181,64 @@ get_tick_count(void) static ErtsMonotonicTime os_monotonic_time_gtc32(void) { + ErtsMonotonicTime mtime; Uint32 ticks = (Uint32) GetTickCount(); ERTS_CHK_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd, - tick_count); - return ERTS_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd, - ticks) << 10; + ticks); + mtime = ERTS_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd, + ticks); + mtime <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; + return mtime; +} + +static void +os_times_gtc32(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep) +{ + SYSTEMTIME st; + ErtsSystemTime stime, mtime; + Uint32 ticks; + + ticks = (Uint32) GetTickCount(); + GetSystemTime(&st); + + ERTS_CHK_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd, + ticks); + mtime = ERTS_EXTEND_OS_MONOTONIC_TIME(&internal_state.wr.m.os_mtime_xtnd, + ticks); + mtime <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; + *mtimep = mtime; + + stime = SystemTime2MilliSec(&st); + stime <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; + *stimep = stime; + } static ErtsMonotonicTime os_monotonic_time_gtc64(void) { ULONGLONG ticks = (*internal_state.r.o.pGetTickCount64)(); - return (ErtsMonotonicTime) ticks << 10; + ErtsMonotonicTime mtime = (ErtsMonotonicTime) ticks; + return mtime << ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; +} + +static void +os_times_gtc64(ErtsMonotonicTime *mtimep, ErtsSystemTime *stimep) +{ + SYSTEMTIME st; + ErtsSystemTime stime, mtime; + ULONGLONG ticks; + + ticks = (*internal_state.r.o.pGetTickCount64)(); + GetSystemTime(&st); + + mtime = (ErtsMonotonicTime) ticks; + mtime <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; + *mtimep = mtime; + + stime = SystemTime2MilliSec(&st); + stime <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; + *stimep = stime; } static ErtsSysHrTime @@ -197,6 +285,7 @@ void sys_init_time(ErtsSysInitTimeResult *init_resp) { ErtsMonotonicTime (*os_mtime_func)(void); + void (*os_times_func)(ErtsMonotonicTime *, ErtsSystemTime *); ErtsSysHrTime (*sys_hrtime_func)(void) = NULL; ErtsMonotonicTime time_unit; char kernel_dll_name[] = "kernel32"; @@ -213,13 +302,14 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) internal_state.w.f.last_tick_count = 0; init_resp->os_monotonic_time_info.func = "GetTickCount"; - init_resp->os_monotonic_time_info.locked_use = 1; + init_resp->os_monotonic_time_info.locked_use = 0; /* 10-16 ms resolution according to MicroSoft documentation */ init_resp->os_monotonic_time_info.resolution = 100; /* 10 ms */ time_unit = (ErtsMonotonicTime) 1000; time_unit <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; internal_state.r.o.using_get_tick_count_time_unit = 1; os_mtime_func = os_monotonic_time_gtc32; + os_times_func = os_times_gtc32; init_resp->os_monotonic_time_info.extended = 1; erts_init_os_monotonic_time_extender(&internal_state.wr.m.os_mtime_xtnd, get_tick_count, @@ -250,6 +340,7 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) time_unit <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; internal_state.r.o.using_get_tick_count_time_unit = 1; os_mtime_func = os_monotonic_time_gtc64; + os_times_func = os_times_gtc64; if (!sys_hrtime_func) sys_hrtime_func = sys_hrtime_gtc64; } @@ -292,10 +383,12 @@ sys_init_time(ErtsSysInitTimeResult *init_resp) internal_state.r.o.using_get_tick_count_time_unit = 0; init_resp->os_monotonic_time_info.resolution = time_unit; os_mtime_func = os_monotonic_time_qpc; + os_times_func = os_times_qpc; } } erts_sys_time_data__.r.o.os_monotonic_time = os_mtime_func; + erts_sys_time_data__.r.o.os_times = os_times_func; init_resp->os_monotonic_time_unit = time_unit; init_resp->have_os_monotonic_time = 1; init_resp->sys_clock_resolution = 1; @@ -600,21 +693,11 @@ sys_gettimeofday(SysTimeval *tv) ErtsSystemTime erts_os_system_time(void) { - SYSTEMTIME t; - FILETIME ft; - ULARGE_INTEGER ull; + SYSTEMTIME st; ErtsSystemTime stime; - GetSystemTime(&t); - SystemTimeToFileTime(&t, &ft); - FILETIME_TO_ULI(ull,ft); - - /* now in 100 ns units */ - - stime = (ErtsSystemTime) ull.QuadPart; - stime -= (((ErtsSystemTime) EPOCH_JULIAN_DIFF) - * ((ErtsSystemTime) (10*1000*1000))); - stime /= (ErtsSystemTime) (10*1000); + GetSystemTime(&st); + stime = SystemTime2MilliSec(&st); if (internal_state.r.o.using_get_tick_count_time_unit) { stime <<= ERTS_GET_TICK_COUNT_TIME_UNIT_SHIFT; @@ -622,9 +705,9 @@ erts_os_system_time(void) } return ((ErtsSystemTime) - erts_time_unit_conversion(stime, + erts_time_unit_conversion((Uint64) stime, (Uint32) 1000, - (Uint32) ERTS_MONOTONIC_TIME_UNIT)); + internal_state.r.o.pcf)); } diff --git a/erts/emulator/test/node_container_SUITE.erl b/erts/emulator/test/node_container_SUITE.erl index 3f9b339ed2..9c1839811a 100644 --- a/erts/emulator/test/node_container_SUITE.erl +++ b/erts/emulator/test/node_container_SUITE.erl @@ -686,6 +686,9 @@ timer_refc(doc) -> "as they should for data stored in bif timers."]; timer_refc(suite) -> []; timer_refc(Config) when is_list(Config) -> + {skipped, "Test needs to be UPDATED for new timer implementation"}. + +timer_refc_test(Config) when is_list(Config) -> ?line RNode = {get_nodename(), 1}, ?line RPid = mk_pid(RNode, 4711, 2), ?line RPort = mk_port(RNode, 4711), diff --git a/erts/emulator/test/timer_bif_SUITE.erl b/erts/emulator/test/timer_bif_SUITE.erl index da19be3424..56a1cef761 100644 --- a/erts/emulator/test/timer_bif_SUITE.erl +++ b/erts/emulator/test/timer_bif_SUITE.erl @@ -232,6 +232,9 @@ read_timer(Config) when is_list(Config) -> cleanup(doc) -> []; cleanup(suite) -> []; cleanup(Config) when is_list(Config) -> + {skipped, "Test needs to be UPDATED for new timer implementation"}. + +cleanup_test(Config) when is_list(Config) -> ?line Mem = mem(), %% Timer on dead process ?line P1 = spawn(fun () -> ok end), @@ -420,6 +423,9 @@ evil_recv_timeouts(TOs, N, M) -> registered_process(doc) -> []; registered_process(suite) -> []; registered_process(Config) when is_list(Config) -> + {skipped, "Test needs to be UPDATED for new timer implementation"}. + +registered_process_test(Config) when is_list(Config) -> ?line Mem = mem(), %% Cancel ?line T1 = erlang:start_timer(500, ?MODULE, "hej"), diff --git a/erts/preloaded/ebin/erl_prim_loader.beam b/erts/preloaded/ebin/erl_prim_loader.beam Binary files differindex c8ec111e57..df768f9ed6 100644 --- a/erts/preloaded/ebin/erl_prim_loader.beam +++ b/erts/preloaded/ebin/erl_prim_loader.beam diff --git a/erts/preloaded/ebin/erlang.beam b/erts/preloaded/ebin/erlang.beam Binary files differindex 7e7ac99b1c..3478a80dd4 100644 --- a/erts/preloaded/ebin/erlang.beam +++ b/erts/preloaded/ebin/erlang.beam diff --git a/erts/preloaded/ebin/erts_internal.beam b/erts/preloaded/ebin/erts_internal.beam Binary files differindex ad43962b8b..9ed45b34bf 100644 --- a/erts/preloaded/ebin/erts_internal.beam +++ b/erts/preloaded/ebin/erts_internal.beam diff --git a/erts/preloaded/ebin/init.beam b/erts/preloaded/ebin/init.beam Binary files differindex f196952ef2..7361139cde 100644 --- a/erts/preloaded/ebin/init.beam +++ b/erts/preloaded/ebin/init.beam diff --git a/erts/preloaded/ebin/otp_ring0.beam b/erts/preloaded/ebin/otp_ring0.beam Binary files differindex 4d22d8bace..4af9d233b5 100644 --- a/erts/preloaded/ebin/otp_ring0.beam +++ b/erts/preloaded/ebin/otp_ring0.beam diff --git a/erts/preloaded/ebin/prim_eval.beam b/erts/preloaded/ebin/prim_eval.beam Binary files differindex efc8347b6e..7c0b49235e 100644 --- a/erts/preloaded/ebin/prim_eval.beam +++ b/erts/preloaded/ebin/prim_eval.beam diff --git a/erts/preloaded/ebin/prim_file.beam b/erts/preloaded/ebin/prim_file.beam Binary files differindex 6c49b5185e..00babefbb4 100644 --- a/erts/preloaded/ebin/prim_file.beam +++ b/erts/preloaded/ebin/prim_file.beam diff --git a/erts/preloaded/ebin/prim_inet.beam b/erts/preloaded/ebin/prim_inet.beam Binary files differindex f58ee4b4d5..6640a29c62 100644 --- a/erts/preloaded/ebin/prim_inet.beam +++ b/erts/preloaded/ebin/prim_inet.beam diff --git a/erts/preloaded/ebin/prim_zip.beam b/erts/preloaded/ebin/prim_zip.beam Binary files differindex 73be297bbb..3d6f1548d0 100644 --- a/erts/preloaded/ebin/prim_zip.beam +++ b/erts/preloaded/ebin/prim_zip.beam diff --git a/erts/preloaded/ebin/zlib.beam b/erts/preloaded/ebin/zlib.beam Binary files differindex 9eaf8b9e59..3224546179 100644 --- a/erts/preloaded/ebin/zlib.beam +++ b/erts/preloaded/ebin/zlib.beam diff --git a/erts/preloaded/src/erlang.erl b/erts/preloaded/src/erlang.erl index 4bbad4df99..fd11c101bc 100644 --- a/erts/preloaded/src/erlang.erl +++ b/erts/preloaded/src/erlang.erl @@ -1738,7 +1738,7 @@ start_timer(0, Dest, Msg) -> orelse (erlang:is_atom(Dest) andalso Dest /= undefined)), TimerRef = erlang:make_ref(), - try Dest ! {timeout, TimerRef, Msg} catch _:_ -> ok end, + _ = try Dest ! {timeout, TimerRef, Msg} catch _:_ -> ok end, TimerRef catch _:_ -> diff --git a/erts/preloaded/src/erts_internal.erl b/erts/preloaded/src/erts_internal.erl index e2c3d40f61..e489001532 100644 --- a/erts/preloaded/src/erts_internal.erl +++ b/erts/preloaded/src/erts_internal.erl @@ -249,7 +249,7 @@ create_bif_timer() -> -spec erts_internal:access_bif_timer(Ref) -> Res when Ref :: reference(), - Res :: {reference(), pid(), reference()}. + Res :: {reference(), pid()} | 'undefined'. access_bif_timer(_Ref) -> erlang:nif_error(undefined). @@ -369,7 +369,7 @@ tsrv_handle_msg({cancel_timeout, BTR, From, Reply, Req, TRef}, false -> ok; _ -> - try From ! {cancel_timer, Req, false} catch _:_ -> ok end + _ = try From ! {cancel_timer, Req, false} catch _:_ -> ok end end, Nxt; [{Time, TRef} = TKey] -> @@ -387,7 +387,7 @@ tsrv_handle_msg({cancel_timeout, BTR, From, Reply, Req, TRef}, false -> ((1000*(Time - RcvTime)) div Unit) end, - try From ! {cancel_timer, Req, RT} catch _:_ -> ok end + _ = try From ! {cancel_timer, Req, RT} catch _:_ -> ok end end, case Time =:= Nxt of false -> @@ -406,14 +406,14 @@ tsrv_handle_msg({read_timeout, BTR, From, Req, TRef}, Nxt) -> case ets:lookup(RTab, TRef) of [] -> - try From ! {read_timer, Req, false} catch _:_ -> ok end; + _ = try From ! {read_timer, Req, false} catch _:_ -> ok end; [{Time, TRef}] -> RcvTime = erlang:monotonic_time(), RT = case Time =< RcvTime of true -> 0; false -> (1000*(Time - RcvTime)) div Unit end, - try From ! {read_timer, Req, RT} catch _:_ -> ok end + _ = try From ! {read_timer, Req, RT} catch _:_ -> ok end end, Nxt; tsrv_handle_msg({'DOWN', TRef, process, _, _}, @@ -473,6 +473,6 @@ tsrv_handle_timeout(CallTime, #tsrv_state{rtab = RTab, end, ets:delete(TTab, TKey), ets:delete(RTab, TRef), - try Proc ! Msg catch _:_ -> ok end, + _ = try Proc ! Msg catch _:_ -> ok end, tsrv_handle_timeout(CallTime, S) end. diff --git a/lib/common_test/src/ct_telnet.erl b/lib/common_test/src/ct_telnet.erl index 4e03bf8630..d906a267a1 100644 --- a/lib/common_test/src/ct_telnet.erl +++ b/lib/common_test/src/ct_telnet.erl @@ -29,7 +29,9 @@ %% Command timeout = 10 sec (time to wait for a command to return) %% Max no of reconnection attempts = 3 %% Reconnection interval = 5 sek (time to wait in between reconnection attempts) -%% Keep alive = true (will send NOP to the server every 10 sec if connection is idle)</pre> +%% Keep alive = true (will send NOP to the server every 10 sec if connection is idle) +%% Polling limit = 0 (max number of times to poll to get a remaining string terminated) +%% Polling interval = 1 sec (sleep time between polls)</pre> %% <p>These parameters can be altered by the user with the following %% configuration term:</p> %% <pre> @@ -37,7 +39,9 @@ %% {command_timeout,Millisec}, %% {reconnection_attempts,N}, %% {reconnection_interval,Millisec}, -%% {keep_alive,Bool}]}.</pre> +%% {keep_alive,Bool}, +%% {poll_limit,N}, +%% {poll_interval,Millisec}]}.</pre> %% <p><code>Millisec = integer(), N = integer()</code></p> %% <p>Enter the <code>telnet_settings</code> term in a configuration %% file included in the test and ct_telnet will retrieve the information @@ -156,6 +160,8 @@ -define(RECONN_TIMEOUT,5000). -define(DEFAULT_TIMEOUT,10000). -define(DEFAULT_PORT,23). +-define(POLL_LIMIT,0). +-define(POLL_INTERVAL,1000). -include("ct_util.hrl"). @@ -169,6 +175,8 @@ type, target_mod, keep_alive, + poll_limit=?POLL_LIMIT, + poll_interval=?POLL_INTERVAL, extra, conn_to=?DEFAULT_TIMEOUT, com_to=?DEFAULT_TIMEOUT, @@ -379,8 +387,15 @@ cmdf(Connection,CmdFormat,Args,Opts) when is_list(Args) -> %%% Connection = ct_telnet:connection() %%% Data = [string()] %%% Reason = term() -%%% @doc Get all data which has been received by the telnet client -%%% since last command was sent. +%%% @doc Get all data that has been received by the telnet client +%%% since the last command was sent. Note that only newline terminated +%%% strings are returned. If the last string received has not yet +%%% been terminated, the connection may be polled automatically until +%%% the string is complete. The polling feature is controlled +%%% by the `poll_limit' and `poll_interval' config values and is +%%% by default disabled (meaning the function will immediately +%%% return all complete strings received and save a remaining +%%% non-terminated string for a later `get_data' call). get_data(Connection) -> case get_handle(Connection) of {ok,Pid} -> @@ -596,9 +611,12 @@ init(Name,{Ip,Port,Type},{TargetMod,KeepAlive,Extra}) -> "Reconnection attempts: ~p\n" "Reconnection interval: ~p\n" "Connection timeout: ~p\n" - "Keep alive: ~w", + "Keep alive: ~w\n" + "Poll limit: ~w\n" + "Poll interval: ~w", [Ip,Port,S1#state.com_to,S1#state.reconns, - S1#state.reconn_int,S1#state.conn_to,KeepAlive]), + S1#state.reconn_int,S1#state.conn_to,KeepAlive, + S1#state.poll_limit,S1#state.poll_interval]), {ok,TelnPid,S1}; {'EXIT',Reason} -> {error,Reason}; @@ -619,6 +637,10 @@ set_telnet_defaults([{reconnection_interval,RInt}|Ss],S) -> set_telnet_defaults(Ss,S#state{reconn_int=RInt}); set_telnet_defaults([{keep_alive,_}|Ss],S) -> set_telnet_defaults(Ss,S); +set_telnet_defaults([{poll_limit,PL}|Ss],S) -> + set_telnet_defaults(Ss,S#state{poll_limit=PL}); +set_telnet_defaults([{poll_interval,PI}|Ss],S) -> + set_telnet_defaults(Ss,S#state{poll_interval=PI}); set_telnet_defaults([Unknown|Ss],S) -> force_log(S,error, "Bad element in telnet_settings: ~p",[Unknown]), @@ -706,10 +728,8 @@ handle_msg({send,Cmd,Opts},State) -> handle_msg(get_data,State) -> start_gen_log(heading(get_data,State#state.name)), log(State,cmd,"Reading data...",[]), - {ok,Data,Buffer} = teln_get_all_data(State#state.teln_pid, - State#state.prx, - State#state.buffer, - [],[]), + {ok,Data,Buffer} = teln_get_all_data(State,State#state.buffer,[],[], + State#state.poll_limit), log(State,recv,"Return: ~p",[{ok,Data}]), end_gen_log(), {{ok,Data},State#state{buffer=Buffer}}; @@ -944,16 +964,25 @@ teln_cmd(Pid,Cmd,Prx,Newline,Timeout) -> ct_telnet_client:send_data(Pid,Cmd,Newline), teln_receive_until_prompt(Pid,Prx,Timeout). -teln_get_all_data(Pid,Prx,Data,Acc,LastLine) -> +teln_get_all_data(State=#state{teln_pid=Pid,prx=Prx},Data,Acc,LastLine,Polls) -> case check_for_prompt(Prx,LastLine++Data) of {prompt,Lines,_PromptType,Rest} -> - teln_get_all_data(Pid,Prx,Rest,[Lines|Acc],[]); + teln_get_all_data(State,Rest,[Lines|Acc],[],State#state.poll_limit); {noprompt,Lines,LastLine1} -> case ct_telnet_client:get_data(Pid) of + {ok,[]} when LastLine1 /= [], Polls > 0 -> + %% No more data from server but the last string is not + %% a complete line (maybe because of a slow connection), + timer:sleep(State#state.poll_interval), + NewPolls = if Polls == infinity -> infinity; + true -> Polls-1 + end, + teln_get_all_data(State,[],[Lines|Acc],LastLine1,NewPolls); {ok,[]} -> {ok,lists:reverse(lists:append([Lines|Acc])),LastLine1}; {ok,Data1} -> - teln_get_all_data(Pid,Prx,Data1,[Lines|Acc],LastLine1) + teln_get_all_data(State,Data1,[Lines|Acc],LastLine1, + State#state.poll_limit) end end. @@ -1106,12 +1135,18 @@ repeat_expect(Name,Pid,Data,Pattern,Acc,EO) -> teln_expect1(Name,Pid,Data,Pattern,Acc,EO=#eo{idle_timeout=IdleTO, total_timeout=TotalTO}) -> - ExpectFun = case EO#eo.seq of + %% TotalTO is a float value in this loop (unless it's 'infinity'), + %% but an integer value will be passed to the other functions + EOMod = if TotalTO /= infinity -> EO#eo{total_timeout=trunc(TotalTO)}; + true -> EO + end, + + ExpectFun = case EOMod#eo.seq of true -> fun() -> - seq_expect(Name,Pid,Data,Pattern,Acc,EO) + seq_expect(Name,Pid,Data,Pattern,Acc,EOMod) end; false -> fun() -> - one_expect(Name,Pid,Data,Pattern,EO) + one_expect(Name,Pid,Data,Pattern,EOMod) end end, case ExpectFun() of @@ -1121,9 +1156,14 @@ teln_expect1(Name,Pid,Data,Pattern,Acc,EO=#eo{idle_timeout=IdleTO, {halt,Why,Rest}; NotFinished -> %% Get more data - Fun = fun() -> get_data1(EO#eo.teln_pid) end, - BreakAfter = if TotalTO < IdleTO -> TotalTO; true -> IdleTO end, - case timer:tc(ct_gen_conn, do_within_time, [Fun, BreakAfter]) of + Fun = fun() -> get_data1(EOMod#eo.teln_pid) end, + BreakAfter = if TotalTO < IdleTO -> + %% use the integer value + EOMod#eo.total_timeout; + true -> + IdleTO + end, + case timer:tc(ct_gen_conn, do_within_time, [Fun,BreakAfter]) of {_,{error,Reason}} -> %% A timeout will occur when the telnet connection %% is idle for EO#eo.idle_timeout milliseconds. @@ -1132,13 +1172,15 @@ teln_expect1(Name,Pid,Data,Pattern,Acc,EO=#eo{idle_timeout=IdleTO, case NotFinished of {nomatch,Rest} -> %% One expect - teln_expect1(Name,Pid,Rest++Data1,Pattern,[],EO); + teln_expect1(Name,Pid,Rest++Data1, + Pattern,[],EOMod); {continue,Patterns1,Acc1,Rest} -> %% Sequence - teln_expect1(Name,Pid,Rest++Data1,Patterns1,Acc1,EO) + teln_expect1(Name,Pid,Rest++Data1, + Patterns1,Acc1,EOMod) end; {Elapsed,{ok,Data1}} -> - TVal = trunc(TotalTO - (Elapsed/1000)), + TVal = TotalTO - (Elapsed/1000), if TVal =< 0 -> {error,timeout}; true -> @@ -1146,10 +1188,12 @@ teln_expect1(Name,Pid,Data,Pattern,Acc,EO=#eo{idle_timeout=IdleTO, case NotFinished of {nomatch,Rest} -> %% One expect - teln_expect1(Name,Pid,Rest++Data1,Pattern,[],EO1); + teln_expect1(Name,Pid,Rest++Data1, + Pattern,[],EO1); {continue,Patterns1,Acc1,Rest} -> %% Sequence - teln_expect1(Name,Pid,Rest++Data1,Patterns1,Acc1,EO1) + teln_expect1(Name,Pid,Rest++Data1, + Patterns1,Acc1,EO1) end end end @@ -1430,8 +1474,10 @@ check_for_prompt(Prx,Data) -> split_lines(String) -> split_lines(String,[],[]). -split_lines([$\n|Rest],Line,Lines) -> +split_lines([$\n|Rest],Line,Lines) when Line /= [] -> split_lines(Rest,[],[lists:reverse(Line)|Lines]); +split_lines([$\n|Rest],[],Lines) -> + split_lines(Rest,[],Lines); split_lines([$\r|Rest],Line,Lines) -> split_lines(Rest,Line,Lines); split_lines([0|Rest],Line,Lines) -> diff --git a/lib/common_test/src/ct_telnet_client.erl b/lib/common_test/src/ct_telnet_client.erl index f39863824c..b0734d8d65 100644 --- a/lib/common_test/src/ct_telnet_client.erl +++ b/lib/common_test/src/ct_telnet_client.erl @@ -32,7 +32,7 @@ -module(ct_telnet_client). -%% -define(debug, true). +%%-define(debug, true). -export([open/2, open/3, open/4, open/5, close/1]). -export([send_data/2, send_data/3, get_data/1]). @@ -111,7 +111,6 @@ get_data(Pid) -> {ok,Data} end. - %%%----------------------------------------------------------------- %%% Internal functions init(Parent, Server, Port, Timeout, KeepAlive, ConnName) -> @@ -146,7 +145,7 @@ loop(State, Sock, Acc) -> ok end; {tcp,_,Msg0} -> - dbg("tcp msg: ~tp~n",[Msg0]), + dbg("rcv tcp msg: ~tp~n",[Msg0]), Msg = check_msg(Sock,Msg0,[]), loop(State, Sock, [Msg | Acc]); {send_data,Data} -> @@ -180,6 +179,7 @@ loop(State, Sock, Acc) -> NewState = case State of #state{keep_alive = true, get_data = 0} -> + dbg("sending NOP\n",[]), if Acc == [] -> send([?IAC,?NOP], Sock, State#state.conn_name); true -> ok @@ -225,15 +225,17 @@ loop(State, Sock, Acc) -> gen_tcp:close(Sock), Pid ! closed after wait(State#state.keep_alive,?IDLE_TIMEOUT) -> + dbg("idle timeout\n",[]), Data = lists:reverse(lists:append(Acc)), case Data of [] -> + dbg("sending NOP\n",[]), send([?IAC,?NOP], Sock, State#state.conn_name), loop(State, Sock, Acc); _ when State#state.log_pos == length(Data)+1 -> loop(State, Sock, Acc); _ -> - dbg("Idle timeout, printing ~tp\n",[Data]), + dbg("idle timeout, printing ~tp\n",[Data]), Len = length(Data), ct_telnet:log(State#state.conn_name, general_io, "~ts", diff --git a/lib/common_test/test/ct_telnet_SUITE.erl b/lib/common_test/test/ct_telnet_SUITE.erl index 84e69c2b54..62cb821ede 100644 --- a/lib/common_test/test/ct_telnet_SUITE.erl +++ b/lib/common_test/test/ct_telnet_SUITE.erl @@ -203,7 +203,9 @@ telnet_config(_, LogType) -> {command_timeout,10000}, {reconnection_attempts,0}, {reconnection_interval,0}, - {keep_alive,true}]} | + {keep_alive,true}, + {poll_limit,10}, + {poll_interval,1000}]} | if LogType == legacy -> [{ct_conn_log,[]}]; true -> diff --git a/lib/compiler/src/cerl.erl b/lib/compiler/src/cerl.erl index 8367a1e19e..ea960abc1a 100644 --- a/lib/compiler/src/cerl.erl +++ b/lib/compiler/src/cerl.erl @@ -256,7 +256,7 @@ %% @see c_primop/2 %% @see c_receive/1 %% @see c_seq/2 -%% @see c_try/3 +%% @see c_try/5 %% @see c_tuple/1 %% @see c_values/1 %% @see c_var/1 @@ -1456,7 +1456,7 @@ is_proper_list(_) -> %% X4]</code>. %% %% @see c_cons/2 -%% @see c_nil/1 +%% @see c_nil/0 %% @see is_c_list/1 %% @see list_length/1 %% @see make_list/2 @@ -1487,7 +1487,7 @@ abstract_list([]) -> %% efficient.</p> %% %% @see c_cons/2 -%% @see c_nil/1 +%% @see c_nil/0 %% @see is_c_list/1 %% @see list_elements/1 @@ -1992,7 +1992,7 @@ update_c_fname(Node, Atom, Arity) -> %% %% @see c_fname/2 %% @see c_var/1 -%% @see c_var_name/1 +%% @see var_name/1 -spec is_c_fname(cerl()) -> boolean(). @@ -3670,7 +3670,7 @@ c_try(Expr, Vs, Body, Evs, Handler) -> %% @spec ann_c_try(As::[term()], Expression::cerl(), %% Variables::[cerl()], Body::cerl(), %% EVars::[cerl()], Handler::cerl()) -> cerl() -%% @see c_try/3 +%% @see c_try/5 -spec ann_c_try([term()], cerl(), [cerl()], cerl(), [cerl()], cerl()) -> c_try(). @@ -3683,7 +3683,7 @@ ann_c_try(As, Expr, Vs, Body, Evs, Handler) -> %% @spec update_c_try(Old::cerl(), Expression::cerl(), %% Variables::[cerl()], Body::cerl(), %% EVars::[cerl()], Handler::cerl()) -> cerl() -%% @see c_try/3 +%% @see c_try/5 -spec update_c_try(c_try(), cerl(), [cerl()], cerl(), [cerl()], cerl()) -> c_try(). @@ -3698,7 +3698,7 @@ update_c_try(Node, Expr, Vs, Body, Evs, Handler) -> %% @doc Returns <code>true</code> if <code>Node</code> is an abstract %% try-expression, otherwise <code>false</code>. %% -%% @see c_try/3 +%% @see c_try/5 -spec is_c_try(cerl()) -> boolean(). @@ -3712,7 +3712,7 @@ is_c_try(_) -> %% %% @doc Returns the expression subtree of an abstract try-expression. %% -%% @see c_try/3 +%% @see c_try/5 -spec try_arg(c_try()) -> cerl(). @@ -3725,7 +3725,7 @@ try_arg(Node) -> %% @doc Returns the list of success variable subtrees of an abstract %% try-expression. %% -%% @see c_try/3 +%% @see c_try/5 -spec try_vars(c_try()) -> [cerl()]. @@ -3737,7 +3737,7 @@ try_vars(Node) -> %% %% @doc Returns the success body subtree of an abstract try-expression. %% -%% @see c_try/3 +%% @see c_try/5 -spec try_body(c_try()) -> cerl(). @@ -3750,7 +3750,7 @@ try_body(Node) -> %% @doc Returns the list of exception variable subtrees of an abstract %% try-expression. %% -%% @see c_try/3 +%% @see c_try/5 -spec try_evars(c_try()) -> [cerl()]. @@ -3763,7 +3763,7 @@ try_evars(Node) -> %% @doc Returns the exception body subtree of an abstract %% try-expression. %% -%% @see c_try/3 +%% @see c_try/5 -spec try_handler(c_try()) -> cerl(). @@ -3785,7 +3785,7 @@ try_handler(Node) -> %% @see update_c_catch/2 %% @see is_c_catch/1 %% @see catch_body/1 -%% @see c_try/3 +%% @see c_try/5 -spec c_catch(cerl()) -> c_catch(). diff --git a/lib/compiler/src/cerl_trees.erl b/lib/compiler/src/cerl_trees.erl index b93da8e97f..f1bf0e02e7 100644 --- a/lib/compiler/src/cerl_trees.erl +++ b/lib/compiler/src/cerl_trees.erl @@ -19,7 +19,7 @@ %% @doc Basic functions on Core Erlang abstract syntax trees. %% %% <p>Syntax trees are defined in the module <a -%% href=""><code>cerl</code></a>.</p> +%% href="cerl"><code>cerl</code></a>.</p> %% %% @type cerl() = cerl:cerl() diff --git a/lib/hipe/rtl/hipe_tagscheme.erl b/lib/hipe/rtl/hipe_tagscheme.erl index 990d01e190..c27c682915 100644 --- a/lib/hipe/rtl/hipe_tagscheme.erl +++ b/lib/hipe/rtl/hipe_tagscheme.erl @@ -109,7 +109,6 @@ -define(TAG_HEADER_REFC_BIN,((16#8 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_HEAP_BIN,((16#9 bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_SUB_BIN, ((16#A bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). --define(TAG_HEADER_HASHMAP, ((16#B bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_EXTERNAL_PID, ((16#C bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_EXTERNAL_PORT,((16#D bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). -define(TAG_HEADER_EXTERNAL_REF, ((16#E bsl ?TAG_PRIMARY_SIZE) bor ?TAG_PRIMARY_HEADER)). @@ -258,16 +257,11 @@ test_tuple_N(X, N, TrueLab, FalseLab, Pred) -> test_map(X, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg_gcsafe(), HalfTrueLab = hipe_rtl:mk_new_label(), - OrHashmapLab = hipe_rtl:mk_new_label(), MapMask = ?TAG_HEADER_MASK, [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred), HalfTrueLab, get_header(Tmp, X), - mask_and_compare(Tmp, MapMask, ?TAG_HEADER_MAP, - TrueLab, hipe_rtl:label_name(OrHashmapLab), Pred), - OrHashmapLab, - mask_and_compare(Tmp, MapMask, ?TAG_HEADER_HASHMAP, TrueLab, FalseLab, Pred) - ]. + mask_and_compare(Tmp, MapMask, ?TAG_HEADER_MAP, TrueLab, FalseLab, Pred)]. test_ref(X, TrueLab, FalseLab, Pred) -> Hdr = hipe_rtl:mk_new_reg_gcsafe(), @@ -366,22 +360,16 @@ test_matchstate(X, TrueLab, FalseLab, Pred) -> test_bitstr(X, TrueLab, FalseLab, Pred) -> Tmp = hipe_rtl:mk_new_reg_gcsafe(), HalfTrueLab = hipe_rtl:mk_new_label(), - AndNotHashmapLab = hipe_rtl:mk_new_label(), Mask = ?TAG_HEADER_MASK - ?BINARY_XXX_MASK, [test_is_boxed(X, hipe_rtl:label_name(HalfTrueLab), FalseLab, Pred), HalfTrueLab, get_header(Tmp, X), - mask_and_compare(Tmp, Mask, ?TAG_HEADER_REFC_BIN, - hipe_rtl:label_name(AndNotHashmapLab), FalseLab, Pred), - AndNotHashmapLab, - mask_and_compare(Tmp, ?TAG_HEADER_MASK, ?TAG_HEADER_HASHMAP, FalseLab, TrueLab, Pred) - ]. + mask_and_compare(Tmp, Mask, ?TAG_HEADER_REFC_BIN, TrueLab, FalseLab, Pred)]. test_binary(X, TrueLab, FalseLab, Pred) -> Tmp1 = hipe_rtl:mk_new_reg_gcsafe(), Tmp2 = hipe_rtl:mk_new_reg_gcsafe(), IsBoxedLab = hipe_rtl:mk_new_label(), - AndNotHashmapLab = hipe_rtl:mk_new_label(), IsBitStrLab = hipe_rtl:mk_new_label(), IsSubBinLab = hipe_rtl:mk_new_label(), Mask = ?TAG_HEADER_MASK - ?BINARY_XXX_MASK, @@ -389,10 +377,7 @@ test_binary(X, TrueLab, FalseLab, Pred) -> IsBoxedLab, get_header(Tmp1, X), mask_and_compare(Tmp1, Mask, ?TAG_HEADER_REFC_BIN, - hipe_rtl:label_name(AndNotHashmapLab), FalseLab, Pred), - AndNotHashmapLab, - mask_and_compare(Tmp1, ?TAG_HEADER_MASK, ?TAG_HEADER_HASHMAP, - FalseLab, hipe_rtl:label_name(IsBitStrLab), Pred), + hipe_rtl:label_name(IsBitStrLab), FalseLab, Pred), IsBitStrLab, mask_and_compare(Tmp1, ?TAG_HEADER_MASK, ?TAG_HEADER_SUB_BIN, hipe_rtl:label_name(IsSubBinLab), TrueLab, 0.5), diff --git a/lib/inets/examples/httpd_load_test/hdlt_random_html.erl b/lib/inets/examples/httpd_load_test/hdlt_random_html.erl index c55de628c1..59073a3d23 100644 --- a/lib/inets/examples/httpd_load_test/hdlt_random_html.erl +++ b/lib/inets/examples/httpd_load_test/hdlt_random_html.erl @@ -19,7 +19,6 @@ %% -module(hdlt_random_html). --compile([{nowarn_deprecated_function,{erlang,now,0}}]). -export([page/3]). page(SessionID, _Env, Input) -> @@ -49,15 +48,10 @@ stop() -> ". content(WorkSim, SzSim) -> - %% Adapt to OTP 18 erlang time API and be backwards compatible - {A, B, C} = try - {erlang:phash2([node()]), - erlang:monotonic_time(), - erlang:unique_integer()} - catch - error:undef -> - erlang:now() - end, + {A, B, C} = {erlang:phash2([node()]), + inets_time_compat:monotonic_time(), + inets_time_compat:unique_integer()}, + random:seed(A, B, C), lists:sort([random:uniform(X) || X <- lists:seq(1, WorkSim)]), lists:flatten(lists:duplicate(SzSim, "Dummy data ")). diff --git a/lib/inets/src/ftp/ftp.erl b/lib/inets/src/ftp/ftp.erl index 361a775024..7eebe8d5bf 100644 --- a/lib/inets/src/ftp/ftp.erl +++ b/lib/inets/src/ftp/ftp.erl @@ -21,7 +21,6 @@ %% It also supports ipv6 RFC 2428 and starttls RFC 4217. -module(ftp). --compile([{nowarn_deprecated_function,{erlang,now,0}}]). -behaviour(gen_server). -behaviour(inets_service). @@ -2177,14 +2176,7 @@ handle_caller(#state{caller = {transfer_data, {Cmd, Bin, RemoteFile}}} = %% Connect to FTP server at Host (default is TCP port 21) %% in order to establish a control connection. setup_ctrl_connection(Host, Port, Timeout, State) -> - %% Adapt to OTP 18 erlang time API and be backwards compatible - MsTime = try - erlang:monotonic_time() - catch - error:undef -> - %% Use Erlang system time as monotonic time - erlang:now() - end, + MsTime = inets_time_compat:monotonic_time(), case connect(Host, Port, Timeout, State) of {ok, IpFam, CSock} -> NewState = State#state{csock = {tcp, CSock}, ipfamily = IpFam}, diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl index 7f7328f1d9..8f2f11ce8e 100644 --- a/lib/inets/src/http_client/httpc_handler.erl +++ b/lib/inets/src/http_client/httpc_handler.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2002-2014. All Rights Reserved. +%% Copyright Ericsson AB 2002-2015. All Rights Reserved. %% %% The contents of this file are subject to the Erlang Public License, %% Version 1.1, (the "License"); you may not use this file except in @@ -1122,7 +1122,7 @@ handle_http_body(Body, #state{headers = Headers, handle_response(State#state{headers = NewHeaders, body = NewBody}); _ -> - {NewBody2, NewRequest} = + {NewBody2, _NewRequest} = stream(NewBody, Request, Code), handle_response(State#state{headers = NewHeaders, body = NewBody2}) diff --git a/lib/inets/src/inets_app/Makefile b/lib/inets/src/inets_app/Makefile index 5d3f652441..926585f198 100644 --- a/lib/inets/src/inets_app/Makefile +++ b/lib/inets/src/inets_app/Makefile @@ -48,7 +48,8 @@ MODULES = \ inets_sup \ inets_regexp \ inets_trace \ - inets_lib + inets_lib \ + inets_time_compat INTERNAL_HRL_FILES = inets_internal.hrl EXTERNAL_HRL_FILES = ../../include/httpd.hrl \ diff --git a/lib/inets/src/inets_app/inets.app.src b/lib/inets/src/inets_app/inets.app.src index 01d4cefc55..7207672b7f 100644 --- a/lib/inets/src/inets_app/inets.app.src +++ b/lib/inets/src/inets_app/inets.app.src @@ -28,6 +28,7 @@ inets_regexp, inets_trace, inets_lib, + inets_time_compat, %% FTP ftp, diff --git a/lib/inets/src/inets_app/inets_lib.erl b/lib/inets/src/inets_app/inets_lib.erl index 11d3bac6bb..e79959f678 100644 --- a/lib/inets/src/inets_app/inets_lib.erl +++ b/lib/inets/src/inets_app/inets_lib.erl @@ -18,7 +18,6 @@ %% -module(inets_lib). --compile([{nowarn_deprecated_function,{erlang,now,0}}]). -export([millisec_passed/1, formated_timestamp/0, format_timestamp/1]). @@ -27,7 +26,7 @@ %% Help function, elapsed milliseconds since T0 millisec_passed({_,_,_} = T0 ) -> %% OTP 17 and earlier - timer:now_diff(erlang:now(), T0) div 1000; + timer:now_diff(inets_time_compat:monotonic_time(), T0) div 1000; millisec_passed(T0) -> %% OTP 18 diff --git a/lib/inets/src/inets_app/inets_time_compat.erl b/lib/inets/src/inets_app/inets_time_compat.erl new file mode 100644 index 0000000000..d6297d9caf --- /dev/null +++ b/lib/inets/src/inets_app/inets_time_compat.erl @@ -0,0 +1,71 @@ +%% +%% %CopyrightBegin% +%% +%% Copyright Ericsson AB 2015-2015. All Rights Reserved. +%% +%% The contents of this file are subject to the Erlang Public License, +%% Version 1.1, (the "License"); you may not use this file except in +%% compliance with the License. You should have received a copy of the +%% Erlang Public License along with this software. If not, it can be +%% retrieved online at http://www.erlang.org/. +%% +%% Software distributed under the License is distributed on an "AS IS" +%% basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See +%% the License for the specific language governing rights and limitations +%% under the License. +%% +%% %CopyrightEnd% +%% + +%% This module is created to be able to execute on ERTS versions both +%% earlier and later than 7.0. + +-module(inets_time_compat). + +%% We don't want warnings about the use of erlang:now/0 in +%% this module. +-compile(nowarn_deprecated_function). + +-export([monotonic_time/0, + timestamp/0, + unique_integer/0, + unique_integer/1]). + +monotonic_time() -> + try + erlang:monotonic_time() + catch + error:undef -> + %% Use Erlang system time as monotonic time + erlang_system_time_fallback() + end. + +timestamp() -> + try + erlang:timestamp() + catch + error:undef -> + erlang:now() + end. + +unique_integer() -> + try + erlang:unique_integer() + catch + error:undef -> + erlang_system_time_fallback() + end. + +unique_integer(Modifiers) -> + try + erlang:unique_integer(Modifiers) + catch + error:badarg -> + erlang:error(badarg, [Modifiers]); + error:undef -> + erlang_system_time_fallback() + end. + +erlang_system_time_fallback() -> + {MS, S, US} = erlang:now(), + (MS*1000000+S)*1000000+US. diff --git a/lib/inets/src/tftp/tftp_logger.erl b/lib/inets/src/tftp/tftp_logger.erl index 104d6a91c6..231a705371 100644 --- a/lib/inets/src/tftp/tftp_logger.erl +++ b/lib/inets/src/tftp/tftp_logger.erl @@ -18,7 +18,6 @@ %% %% -module(tftp_logger). --compile([{nowarn_deprecated_function,{erlang,now,0}}]). %%------------------------------------------------------------------- %% Interface @@ -85,14 +84,8 @@ info_msg(Format, Data) -> %%------------------------------------------------------------------- add_timestamp(Format, Data) -> - %% Adapt to new OTP 18 erlang time API and be backwards compatible - Now = try - erlang:timestamp() - catch - error:undef -> - erlang:now() - end, - {{_Y, _Mo, _D}, {H, Mi, S}} = calendar:now_to_universal_time(Now), + Time = inets_time_compat:timestamp(), + {{_Y, _Mo, _D}, {H, Mi, S}} = calendar:now_to_universal_time(Time), %% {"~p-~s-~sT~s:~s:~sZ,~6.6.0w tftp: " ++ Format ++ "\n", %% [Y, t(Mo), t(D), t(H), t(Mi), t(S), MicroSecs | Data]}. {"~s:~s:~s tftp: " ++ Format, [t(H), t(Mi), t(S) | Data]}. diff --git a/lib/inets/src/tftp/tftp_sup.erl b/lib/inets/src/tftp/tftp_sup.erl index 3065279515..7a0dcffc90 100644 --- a/lib/inets/src/tftp/tftp_sup.erl +++ b/lib/inets/src/tftp/tftp_sup.erl @@ -22,7 +22,6 @@ %%---------------------------------------------------------------------- -module(tftp_sup). --compile([{nowarn_deprecated_function,{erlang,now,0}}]). -behaviour(supervisor). @@ -94,17 +93,7 @@ unique_name(Options) -> {value, {_, Port}} when is_integer(Port), Port > 0 -> {tftpd, Port}; _ -> - {tftpd, unique_integer()} - end. - -unique_integer() -> - %% Adapt to OTP 18 erlang time API and be backwards compatible - try - erlang:unique_integer([positive]) - catch - error:undef -> - {MS, S, US} = erlang:now(), - (MS*1000000+S)*1000000+US + {tftpd, inets_time_compat:unique_integer([positive])} end. default_kill_after() -> diff --git a/lib/inets/test/ftp_suite_lib.erl b/lib/inets/test/ftp_suite_lib.erl index 5ae9eb736e..b637832101 100644 --- a/lib/inets/test/ftp_suite_lib.erl +++ b/lib/inets/test/ftp_suite_lib.erl @@ -29,7 +29,6 @@ % -export([init_per_testcase/2, end_per_testcase/2]). -compile(export_all). --compile([{nowarn_deprecated_function,{erlang,now,0}}]). -record(progress, { @@ -1353,15 +1352,9 @@ do_delete(Pid, Config) -> ok. do_mkdir(Pid) -> - %% Adapt to OTP 18 erlang time API and be backwards compatible - NewDir = try - "earl_" ++ integer_to_list(erlang:unique_integer([positive])) - catch - error:undef -> - {A, B, C} = erlang:now(), - "nisse_" ++ integer_to_list(A) ++ "_" ++ - integer_to_list(B) ++ "_" ++ integer_to_list(C) - end, + NewDir = "earl_" ++ + integer_to_list(inets_time_compat:unique_integer([positive])), + ok = ftp:cd(Pid, "incoming"), {ok, CurrDir} = ftp:pwd(Pid), {error, efnamena} = ftp:mkdir(Pid, NewDir++"\r\nCWD ."), diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl index 2193588031..0dfc65e8f7 100644 --- a/lib/inets/test/httpc_SUITE.erl +++ b/lib/inets/test/httpc_SUITE.erl @@ -31,7 +31,6 @@ -include("httpc_internal.hrl"). %% Note: This directive should only be used in test suites. -compile(export_all). --compile([{nowarn_deprecated_function,{erlang,now,0}}]). -define(URL_START, "http://"). -define(TLS_URL_START, "https://"). @@ -1934,14 +1933,8 @@ run_clients(NumClients, ServerPort, SeqNumServer) -> wait4clients([], _Timeout) -> ok; wait4clients(Clients, Timeout) when Timeout > 0 -> - %% Adapt to OTP 18 erlang time API and be backwards compatible - Time = try - erlang:monotonic_time() - catch - error:undef -> - %% Use Erlang system time as monotonic time - erlang:now() - end, + Time = inets_time_compat:monotonic_time(), + receive {'DOWN', _MRef, process, Pid, normal} -> {value, {Id, _, _}} = lists:keysearch(Pid, 2, Clients), @@ -2040,14 +2033,8 @@ parse_connection_type(Request) -> end. set_random_seed() -> - %% Adapt to OTP 18 erlang time API and be backwards compatible - Unique = try - erlang:unique_integer() - catch - error:undef -> - {MS, S, US} = erlang:now(), - (MS*1000000+S)*1000000+US - end, + Unique = inets_time_compat:unique_integer(), + A = erlang:phash2([make_ref(), self(), Unique]), random:seed(A, A, A). diff --git a/lib/inets/test/httpd_time_test.erl b/lib/inets/test/httpd_time_test.erl index b3e6746a01..7dd61a5517 100644 --- a/lib/inets/test/httpd_time_test.erl +++ b/lib/inets/test/httpd_time_test.erl @@ -18,7 +18,6 @@ %% %% -module(httpd_time_test). --compile([{nowarn_deprecated_function,{erlang,now,0}}]). -export([t/3, t1/2, t2/2, t4/2]). @@ -117,15 +116,7 @@ main(N, SocketType, Host, Port, Time) loop(Pollers, Timeout) -> d("loop -> entry when" "~n Timeout: ~p", [Timeout]), - %% Adapt to OTP 18 erlang time API and be backwards compatible - Start = try - erlang:monotonic_time(1000) - catch - error:undef -> - %% Use Erlang system time as monotonic time - {A,B,C} = erlang:now(), - A*1000000000+B*1000+(C div 1000) - end, + Start = inets_time_compat:monotonic_time(), receive {'EXIT', Pid, {poller_stat_failure, SocketType, Host, Port, Time, Reason}} -> diff --git a/lib/ssh/src/ssh_info.erl b/lib/ssh/src/ssh_info.erl index 9a91875894..eae9ded5c6 100644 --- a/lib/ssh/src/ssh_info.erl +++ b/lib/ssh/src/ssh_info.erl @@ -179,7 +179,7 @@ line(Len, Char) -> datetime() -> - {{YYYY,MM,DD}, {H,M,S}} = calendar:now_to_universal_time(now()), + {{YYYY,MM,DD}, {H,M,S}} = calendar:now_to_universal_time(erlang:timestamp()), lists:flatten(io_lib:format('~4w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w UTC',[YYYY,MM,DD, H,M,S])). diff --git a/lib/ssh/test/ssh_basic_SUITE.erl b/lib/ssh/test/ssh_basic_SUITE.erl index 48a6627e0f..4c5498dc0e 100644 --- a/lib/ssh/test/ssh_basic_SUITE.erl +++ b/lib/ssh/test/ssh_basic_SUITE.erl @@ -715,7 +715,7 @@ ssh_connect_arg4_timeout(_Config) -> %% try to connect with a timeout, but "supervise" it Client = spawn(fun() -> - T0 = now(), + T0 = erlang:monotonic_time(), Rc = ssh:connect("localhost",Port,[],Timeout), ct:log("Client ssh:connect got ~p",[Rc]), Parent ! {done,self(),Rc,T0} @@ -724,7 +724,7 @@ ssh_connect_arg4_timeout(_Config) -> %% Wait for client reaction on the connection try: receive {done, Client, {error,timeout}, T0} -> - Msp = ms_passed(T0, now()), + Msp = ms_passed(T0), exit(Server,hasta_la_vista___baby), Low = 0.9*Timeout, High = 1.1*Timeout, @@ -748,12 +748,12 @@ ssh_connect_arg4_timeout(_Config) -> {fail, "Didn't timeout"} end. -%% Help function -%% N2-N1 -ms_passed(N1={_,_,M1}, N2={_,_,M2}) -> - {0,{0,Min,Sec}} = calendar:time_difference(calendar:now_to_local_time(N1), - calendar:now_to_local_time(N2)), - 1000 * (Min*60 + Sec + (M2-M1)/1000000). +%% Help function, elapsed milliseconds since T0 +ms_passed(T0) -> + %% OTP 18 + erlang:convert_time_unit(erlang:monotonic_time() - T0, + native, + micro_seconds) / 1000. %%-------------------------------------------------------------------- ssh_connect_negtimeout_parallel(Config) -> ssh_connect_negtimeout(Config,true). |