diff options
Diffstat (limited to 'erts/emulator')
68 files changed, 2283 insertions, 844 deletions
diff --git a/erts/emulator/Makefile.in b/erts/emulator/Makefile.in index 7033ea0a3d..133ecd69e4 100644 --- a/erts/emulator/Makefile.in +++ b/erts/emulator/Makefile.in @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1996-2012. All Rights Reserved. +# Copyright Ericsson AB 1996-2013. 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 @@ -20,7 +20,7 @@ include $(ERL_TOP)/make/target.mk include ../vsn.mk include $(ERL_TOP)/make/$(TARGET)/otp.mk -include $(TARGET)/gen_git_version.mk +-include $(TARGET)/gen_git_version.mk ENABLE_ALLOC_TYPE_VARS = @ENABLE_ALLOC_TYPE_VARS@ diff --git a/erts/emulator/beam/atom.c b/erts/emulator/beam/atom.c index b69f979397..84d2d5e3ed 100644 --- a/erts/emulator/beam/atom.c +++ b/erts/emulator/beam/atom.c @@ -132,9 +132,17 @@ atom_hash(Atom* obj) byte* p = obj->name; int len = obj->len; HashValue h = 0, g; + byte v; while(len--) { - h = (h << 4) + *p++; + v = *p++; + /* latin1 clutch for r16 */ + if ((v & 0xFE) == 0xC2 && (*p & 0xC0) == 0x80) { + v = (v << 6) | (*p & 0x3F); + p++; len--; + } + /* normal hashpjw follows for v */ + h = (h << 4) + v; if ((g = h & 0xf0000000)) { h ^= (g >> 24); h ^= g; diff --git a/erts/emulator/beam/beam_bif_load.c b/erts/emulator/beam/beam_bif_load.c index 73264214ce..649594a334 100644 --- a/erts/emulator/beam/beam_bif_load.c +++ b/erts/emulator/beam/beam_bif_load.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2012. All Rights Reserved. + * Copyright Ericsson AB 1999-2013. 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 @@ -1081,7 +1081,21 @@ beam_make_current_old(Process *c_p, ErtsProcLocks c_p_locks, Eterm module) static int is_native(BeamInstr* code) { - return ((Eterm *)code[MI_FUNCTIONS])[1] != 0; + Uint i, num_functions = code[MI_NUM_FUNCTIONS]; + + /* Check NativeAdress of first real function in module + */ + for (i=0; i<num_functions; i++) { + BeamInstr* func_info = (BeamInstr *) code[MI_FUNCTIONS+i]; + Eterm name = (Eterm) func_info[3]; + + if (is_atom(name)) { + return func_info[1] != 0; + } + else ASSERT(is_nil(name)); /* ignore BIF stubs */ + } + /* Not a single non-BIF function? */ + return 0; } diff --git a/erts/emulator/beam/beam_catches.c b/erts/emulator/beam/beam_catches.c index 7c92408eea..d374d0469e 100644 --- a/erts/emulator/beam/beam_catches.c +++ b/erts/emulator/beam/beam_catches.c @@ -160,10 +160,9 @@ void beam_catches_delmod(unsigned head, BeamInstr *code, unsigned code_bytes, } if( (char*)p->beam_catches[i].cp - (char*)code >= code_bytes ) { erl_exit(1, - "beam_catches_delmod: item %#x has cp %#lx which is not " - "in module's range [%#lx,%#lx[\r\n", - i, (long)p->beam_catches[i].cp, - (long)code, (long)((char*)code + code_bytes)); + "beam_catches_delmod: item %#x has cp %p which is not " + "in module's range [%p,%p[\r\n", + i, p->beam_catches[i].cp, code, ((char*)code + code_bytes)); } p->beam_catches[i].cp = 0; cdr = p->beam_catches[i].cdr; diff --git a/erts/emulator/beam/beam_emu.c b/erts/emulator/beam/beam_emu.c index 0e9d140908..944ed6da81 100644 --- a/erts/emulator/beam/beam_emu.c +++ b/erts/emulator/beam/beam_emu.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2012. All Rights Reserved. + * Copyright Ericsson AB 1996-2013. 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 @@ -1070,17 +1070,6 @@ init_emulator(void) #endif /* USE_VM_PROBES */ -#ifdef USE_VM_PROBES -void -dtrace_drvport_str(ErlDrvPort drvport, char *port_buf) -{ - Port *port = erts_drvport2port(drvport, NULL); - - erts_snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>", - port_channel_no(port->common.id), - port_number(port->common.id)); -} -#endif /* * process_main() is called twice: * The first call performs some initialisation, including exporting diff --git a/erts/emulator/beam/beam_load.c b/erts/emulator/beam/beam_load.c index 81c1ea749a..bd4e5a52d0 100644 --- a/erts/emulator/beam/beam_load.c +++ b/erts/emulator/beam/beam_load.c @@ -205,7 +205,7 @@ typedef struct { typedef struct { Eterm term; /* The tagged term (in the heap). */ Uint heap_size; /* (Exact) size on the heap. */ - Uint offset; /* Offset from temporary location to final. */ + SWord offset; /* Offset from temporary location to final. */ ErlOffHeap off_heap; /* Start of linked list of ProcBins. */ Eterm* heap; /* Heap for term. */ } Literal; @@ -4045,7 +4045,7 @@ freeze_code(LoaderState* stp) code[MI_LITERALS_END] = (BeamInstr) high; ptr = low; for (i = 0; i < stp->num_literals; i++) { - Uint offset; + SWord offset; struct erl_off_heap_header* t_off_heap; sys_memcpy(ptr, stp->literals[i].heap, diff --git a/erts/emulator/beam/bif.c b/erts/emulator/beam/bif.c index df084e1185..9c438679ea 100644 --- a/erts/emulator/beam/bif.c +++ b/erts/emulator/beam/bif.c @@ -39,6 +39,7 @@ #include "erl_thr_progress.h" #define ERTS_PTAB_WANT_BIF_IMPL__ #include "erl_ptab.h" +#include "erl_bits.h" static Export* flush_monitor_message_trap = NULL; static Export* set_cpu_topology_trap = NULL; @@ -2069,11 +2070,16 @@ BIF_RETTYPE send_3(BIF_ALIST_3) result = do_send(p, to, msg, suspend, &ref); if (result > 0) { ERTS_VBUMP_REDS(p, result); + if (ERTS_IS_PROC_OUT_OF_REDS(p)) + goto yield_return; BIF_RET(am_ok); } switch (result) { case 0: + /* May need to yield even though we do not bump reds here... */ + if (ERTS_IS_PROC_OUT_OF_REDS(p)) + goto yield_return; BIF_RET(am_ok); break; case SEND_TRAP: @@ -2091,10 +2097,10 @@ BIF_RETTYPE send_3(BIF_ALIST_3) } break; case SEND_YIELD_RETURN: - if (suspend) - ERTS_BIF_YIELD_RETURN(p, am_ok); - else + if (!suspend) BIF_RET(am_nosuspend); + yield_return: + ERTS_BIF_YIELD_RETURN(p, am_ok); case SEND_AWAIT_RESULT: ASSERT(is_internal_ref(ref)); BIF_TRAP3(await_port_send_result_trap, p, ref, am_nosuspend, am_ok); @@ -2133,11 +2139,16 @@ Eterm erl_send(Process *p, Eterm to, Eterm msg) if (result > 0) { ERTS_VBUMP_REDS(p, result); + if (ERTS_IS_PROC_OUT_OF_REDS(p)) + goto yield_return; BIF_RET(msg); } switch (result) { case 0: + /* May need to yield even though we do not bump reds here... */ + if (ERTS_IS_PROC_OUT_OF_REDS(p)) + goto yield_return; BIF_RET(msg); break; case SEND_TRAP: @@ -2147,6 +2158,7 @@ Eterm erl_send(Process *p, Eterm to, Eterm msg) ERTS_BIF_YIELD2(bif_export[BIF_send_2], p, to, msg); break; case SEND_YIELD_RETURN: + yield_return: ERTS_BIF_YIELD_RETURN(p, msg); case SEND_AWAIT_RESULT: ASSERT(is_internal_ref(ref)); @@ -2895,45 +2907,69 @@ BIF_RETTYPE string_to_integer_1(BIF_ALIST_1) BIF_RET(TUPLE2(hp, res, tail)); } } - BIF_RETTYPE list_to_integer_1(BIF_ALIST_1) -{ + { + /* Using do_list_to_integer is about twice as fast as using + erts_chars_to_integer because we do not have to copy the + entire list */ Eterm res; Eterm dummy; /* must be a list */ - if (do_list_to_integer(BIF_P,BIF_ARG_1,&res,&dummy) != LTI_ALL_INTEGER) { BIF_ERROR(BIF_P,BADARG); } BIF_RET(res); } -/**********************************************************************/ +BIF_RETTYPE list_to_integer_2(BIF_ALIST_2) +{ -/* convert a float to a list of ascii characters */ + /* Bif implementation is about 50% faster than pure erlang, + and since we have erts_chars_to_integer now it is simpler + as well. This could be optmized further if we did not have to + copy the list to buf. */ + int i; + Eterm res; + char *buf = NULL; + int base; -BIF_RETTYPE float_to_list_1(BIF_ALIST_1) -{ - int i; - Uint need; - Eterm* hp; - FloatDef f; - char fbuf[30]; + i = list_length(BIF_ARG_1); + if (i < 0) + BIF_ERROR(BIF_P, BADARG); + + base = signed_val(BIF_ARG_2); + + if (base < 2 || base > 36) + BIF_ERROR(BIF_P, BADARG); + + /* Take fast path if base it 10 */ + if (base == 10) + return list_to_integer_1(BIF_P,&BIF_ARG_1); + + buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1); + + if (intlist_to_buf(BIF_ARG_1, buf, i) < 0) + goto list_to_integer_1_error; + buf[i] = '\0'; /* null terminal */ + + if ((res = erts_chars_to_integer(BIF_P,buf,i,base)) == THE_NON_VALUE) + goto list_to_integer_1_error; + + erts_free(ERTS_ALC_T_TMP, (void *) buf); + BIF_RET(res); + + list_to_integer_1_error: + erts_free(ERTS_ALC_T_TMP, (void *) buf); + BIF_ERROR(BIF_P, BADARG); - /* check the arguments */ - if (is_not_float(BIF_ARG_1)) - BIF_ERROR(BIF_P, BADARG); - GET_DOUBLE(BIF_ARG_1, f); - if ((i = sys_double_to_chars(f.fd, fbuf, sizeof(fbuf))) <= 0) - BIF_ERROR(BIF_P, EXC_INTERNAL_ERROR); - need = i*2; - hp = HAlloc(BIF_P, need); - BIF_RET(buf_to_intlist(&hp, fbuf, i, NIL)); -} + } + +/**********************************************************************/ + +static int do_float_to_charbuf(Process *p, Eterm efloat, Eterm list, + char *fbuf, int sizeof_fbuf) { -BIF_RETTYPE float_to_list_2(BIF_ALIST_2) -{ const static int arity_two = make_arityval(2); int decimals = SYS_DEFAULT_FLOAT_DECIMALS; int compact = 0; @@ -2942,16 +2978,11 @@ BIF_RETTYPE float_to_list_2(BIF_ALIST_2) FMT_FIXED, FMT_SCIENTIFIC } fmt_type = FMT_LEGACY; - Eterm list = BIF_ARG_2; Eterm arg; - int i; - Uint need; - Eterm* hp; FloatDef f; - char fbuf[256]; /* check the arguments */ - if (is_not_float(BIF_ARG_1)) + if (is_not_float(efloat)) goto badarg; for(; is_list(list); list = CDR(list_val(list))) { @@ -2979,22 +3010,64 @@ BIF_RETTYPE float_to_list_2(BIF_ALIST_2) goto badarg; } - GET_DOUBLE(BIF_ARG_1, f); + GET_DOUBLE(efloat, f); if (fmt_type == FMT_FIXED) { - if ((i = sys_double_to_chars_fast(f.fd, fbuf, sizeof(fbuf), - decimals, compact)) <= 0) - goto badarg; + return sys_double_to_chars_fast(f.fd, fbuf, sizeof_fbuf, + decimals, compact); } else { - if ((i = sys_double_to_chars_ext(f.fd, fbuf, sizeof(fbuf), decimals)) <= 0) - goto badarg; + return sys_double_to_chars_ext(f.fd, fbuf, sizeof_fbuf, decimals); } - need = i*2; - hp = HAlloc(BIF_P, need); - BIF_RET(buf_to_intlist(&hp, fbuf, i, NIL)); badarg: + return -1; +} + +/* convert a float to a list of ascii characters */ + +static BIF_RETTYPE do_float_to_list(Process *BIF_P, Eterm arg, Eterm opts) { + int used; + Eterm* hp; + char fbuf[256]; + + if ((used = do_float_to_charbuf(BIF_P,arg,opts,fbuf,sizeof(fbuf))) <= 0) { BIF_ERROR(BIF_P, BADARG); + } + hp = HAlloc(BIF_P, (Uint)used*2); + BIF_RET(buf_to_intlist(&hp, fbuf, (Uint)used, NIL)); +} + + +BIF_RETTYPE float_to_list_1(BIF_ALIST_1) +{ + return do_float_to_list(BIF_P,BIF_ARG_1,NIL); +} + +BIF_RETTYPE float_to_list_2(BIF_ALIST_2) +{ + return do_float_to_list(BIF_P,BIF_ARG_1,BIF_ARG_2); +} + +/* convert a float to a binary of ascii characters */ + +static BIF_RETTYPE do_float_to_binary(Process *BIF_P, Eterm arg, Eterm opts) { + int used; + char fbuf[256]; + + if ((used = do_float_to_charbuf(BIF_P,arg,opts,fbuf,sizeof(fbuf))) <= 0) { + BIF_ERROR(BIF_P, BADARG); + } + BIF_RET(new_binary(BIF_P, (byte*)fbuf, (Uint)used)); +} + +BIF_RETTYPE float_to_binary_1(BIF_ALIST_1) +{ + return do_float_to_binary(BIF_P,BIF_ARG_1,NIL); +} + +BIF_RETTYPE float_to_binary_2(BIF_ALIST_2) +{ + return do_float_to_binary(BIF_P,BIF_ARG_1,BIF_ARG_2); } /**********************************************************************/ @@ -3179,36 +3252,101 @@ BIF_RETTYPE string_to_float_1(BIF_ALIST_1) BIF_RET(tup); } +static BIF_RETTYPE do_charbuf_to_float(Process *BIF_P,char *buf) { + FloatDef f; + Eterm res; + Eterm* hp; + + if (sys_chars_to_double(buf, &f.fd) != 0) + BIF_ERROR(BIF_P, BADARG); + + hp = HAlloc(BIF_P, FLOAT_SIZE_OBJECT); + res = make_float(hp); + PUT_DOUBLE(f, hp); + BIF_RET(res); + +} BIF_RETTYPE list_to_float_1(BIF_ALIST_1) { int i; - FloatDef f; Eterm res; - Eterm* hp; char *buf = NULL; i = list_length(BIF_ARG_1); - if (i < 0) { - badarg: - if (buf) - erts_free(ERTS_ALC_T_TMP, (void *) buf); - BIF_ERROR(BIF_P, BADARG); - } - + if (i < 0) + BIF_ERROR(BIF_P, BADARG); + buf = (char *) erts_alloc(ERTS_ALC_T_TMP, i + 1); if (intlist_to_buf(BIF_ARG_1, buf, i) < 0) - goto badarg; + goto list_to_float_1_error; buf[i] = '\0'; /* null terminal */ + + if ((res = do_charbuf_to_float(BIF_P,buf)) == THE_NON_VALUE) + goto list_to_float_1_error; + + erts_free(ERTS_ALC_T_TMP, (void *) buf); + BIF_RET(res); + + list_to_float_1_error: + erts_free(ERTS_ALC_T_TMP, (void *) buf); + BIF_ERROR(BIF_P, BADARG); + +} + +BIF_RETTYPE binary_to_float_1(BIF_ALIST_1) +{ + Eterm res; + Eterm binary = BIF_ARG_1; + Sint size; + byte* bytes, *buf; + Eterm* real_bin; + Uint offs = 0; + Uint bit_offs = 0; + + if (is_not_binary(binary) || (size = binary_size(binary)) == 0) + BIF_ERROR(BIF_P, BADARG); + + /* + * Unfortunately we have to copy the binary because we have to insert + * the '\0' at the end of the binary for strtod to work + * (there is no nstrtod :( ) + */ + + buf = erts_alloc(ERTS_ALC_T_TMP, size + 1); + + real_bin = binary_val(binary); + if (*real_bin == HEADER_SUB_BIN) { + ErlSubBin* sb = (ErlSubBin *) real_bin; + if (sb->bitsize) { + goto binary_to_float_1_error; + } + offs = sb->offs; + bit_offs = sb->bitoffs; + real_bin = binary_val(sb->orig); + } + if (*real_bin == HEADER_PROC_BIN) { + bytes = ((ProcBin *) real_bin)->bytes + offs; + } else { + bytes = (byte *)(&(((ErlHeapBin *) real_bin)->data)) + offs; + } + if (bit_offs) + erts_copy_bits(bytes, bit_offs, 1, buf, 0, 1, size*8); + else + memcpy(buf, bytes, size); + + buf[size] = '\0'; + + if ((res = do_charbuf_to_float(BIF_P,(char*)buf)) == THE_NON_VALUE) + goto binary_to_float_1_error; - if (sys_chars_to_double(buf, &f.fd) != 0) - goto badarg; - hp = HAlloc(BIF_P, FLOAT_SIZE_OBJECT); - res = make_float(hp); - PUT_DOUBLE(f, hp); erts_free(ERTS_ALC_T_TMP, (void *) buf); BIF_RET(res); + + binary_to_float_1_error: + erts_free(ERTS_ALC_T_TMP, (void *) buf); + BIF_ERROR(BIF_P, BADARG); } /**********************************************************************/ diff --git a/erts/emulator/beam/bif.h b/erts/emulator/beam/bif.h index ceaf747875..51b77a95ed 100644 --- a/erts/emulator/beam/bif.h +++ b/erts/emulator/beam/bif.h @@ -35,6 +35,13 @@ extern Export* erts_format_cpu_topology_trap; #define BIF_ARG_2 (BIF__ARGS[1]) #define BIF_ARG_3 (BIF__ARGS[2]) +#define ERTS_IS_PROC_OUT_OF_REDS(p) \ + ((p)->fcalls > 0 \ + ? 0 \ + : (!ERTS_PROC_GET_SAVED_CALLS_BUF((p)) \ + ? (p)->fcalls == 0 \ + : ((p)->fcalls == -CONTEXT_REDS))) + #define BUMP_ALL_REDS(p) do { \ if (!ERTS_PROC_GET_SAVED_CALLS_BUF((p))) \ (p)->fcalls = 0; \ diff --git a/erts/emulator/beam/bif.tab b/erts/emulator/beam/bif.tab index e313188901..8bc994c8c3 100644 --- a/erts/emulator/beam/bif.tab +++ b/erts/emulator/beam/bif.tab @@ -561,6 +561,15 @@ bif erlang:prepare_loading/2 bif erlang:finish_loading/1 bif erlang:insert_element/3 bif erlang:delete_element/2 +bif erlang:binary_to_integer/1 +bif erlang:binary_to_integer/2 +bif erlang:integer_to_binary/1 +bif erlang:list_to_integer/2 +bif erlang:float_to_binary/1 +bif erlang:float_to_binary/2 +bif erlang:binary_to_float/1 + +bif io:printable_range/0 # # Obsolete diff --git a/erts/emulator/beam/big.c b/erts/emulator/beam/big.c index 5a5b162b9c..9260c0c4b8 100644 --- a/erts/emulator/beam/big.c +++ b/erts/emulator/beam/big.c @@ -150,14 +150,14 @@ #define D2GTE(a1,a0,b1,b0) (!D2LT(a1,a0,b1,b0)) #define D2LTE(a1,a0,b1,b0) (!D2GT(a1,a0,b1,b0)) -// Add (A+B), A=(a1B+a0) B=(b1B+b0) +/* Add (A+B), A=(a1B+a0) B=(b1B+b0) */ #define D2ADD(a1,a0,b1,b0,c1,c0) do { \ ErtsDigit __ci = 0; \ DSUM(a0,b0,__ci,c0); \ DSUMc(a1,b1,__ci,c1); \ } while(0) -// Subtract (A-B), A=(a1B+a0), B=(b1B+b0) (A>=B) +/* Subtract (A-B), A=(a1B+a0), B=(b1B+b0) (A>=B) */ #define D2SUB(a1,a0,b1,b0,c1,c0) do { \ ErtsDigit __bi; \ DSUB(a0,b0,__bi,c0); \ @@ -1337,7 +1337,7 @@ static dsize_t I_lshift(ErtsDigit* x, dsize_t xl, Sint y, while(bw--) *r++ = 0; - if (sw) { // NOTE! x >> 32 is not = 0! + if (sw) { /* NOTE! x >> 32 is not = 0! */ while(xl--) { a0 = (*x << sw) | a1; a1 = (*x >> (D_EXP - sw)); @@ -1384,7 +1384,7 @@ static dsize_t I_lshift(ErtsDigit* x, dsize_t xl, Sint y, x += (xl-1); r += (rl-1); xl -= bw; - if (sw) { // NOTE! x >> 32 is not = 0! + if (sw) { /* NOTE! x >> 32 is not = 0! */ while(xl--) { a1 = (*x >> sw) | a0; a0 = (*x << (D_EXP-sw)); @@ -1674,26 +1674,26 @@ int big_decimal_estimate(Wterm x) ** Convert a bignum into a string of decimal numbers */ -static void write_big(Wterm x, void (*write_func)(void *, char), void *arg) +static Uint write_big(Wterm x, void (*write_func)(void *, char), void *arg) { Eterm* xp = big_val(x); ErtsDigit* dx = BIG_V(xp); dsize_t xl = BIG_SIZE(xp); short sign = BIG_SIGN(xp); ErtsDigit rem; + Uint n = 0; if (xl == 1 && *dx < D_DECIMAL_BASE) { rem = *dx; - if (rem == 0) - (*write_func)(arg, '0'); - else { + if (rem == 0) { + (*write_func)(arg, '0'); n++; + } else { while(rem) { - (*write_func)(arg, (rem % 10) + '0'); + (*write_func)(arg, (rem % 10) + '0'); n++; rem /= 10; } } - } - else { + } else { ErtsDigit* tmp = (ErtsDigit*) erts_alloc(ERTS_ALC_T_TMP, sizeof(ErtsDigit)*xl); dsize_t tmpl = xl; @@ -1704,15 +1704,14 @@ static void write_big(Wterm x, void (*write_func)(void *, char), void *arg) tmpl = D_div(tmp, tmpl, D_DECIMAL_BASE, tmp, &rem); if (tmpl == 1 && *tmp == 0) { while(rem) { - (*write_func)(arg, (rem % 10)+'0'); + (*write_func)(arg, (rem % 10)+'0'); n++; rem /= 10; } break; - } - else { + } else { int i = D_DECIMAL_EXP; while(i--) { - (*write_func)(arg, (rem % 10)+'0'); + (*write_func)(arg, (rem % 10)+'0'); n++; rem /= 10; } } @@ -1720,8 +1719,10 @@ static void write_big(Wterm x, void (*write_func)(void *, char), void *arg) erts_free(ERTS_ALC_T_TMP, (void *) tmp); } - if (sign) - (*write_func)(arg, '-'); + if (sign) { + (*write_func)(arg, '-'); n++; + } + return n; } struct big_list__ { @@ -1762,6 +1763,20 @@ char *erts_big_to_string(Wterm x, char *buf, Uint buf_sz) return big_str; } +/* Bignum to binary bytes + * e.g. 1 bsl 64 -> "18446744073709551616" + */ + +Uint erts_big_to_binary_bytes(Eterm x, char *buf, Uint buf_sz) +{ + char *big_str = buf + buf_sz; + Uint n; + n = write_big(x, write_string, (void *) &big_str); + ASSERT(buf <= big_str && big_str <= buf + buf_sz); + return n; +} + + /* ** Normalize a bignum given thing pointer length in digits and a sign ** patch zero if odd length @@ -2453,7 +2468,7 @@ int term_equals_2pow32(Eterm x) if (!is_big(x)) return 0; bp = big_val(x); -#if D_EXP == 16 // 16 bit platfrom not really supported!!! +#if D_EXP == 16 /* 16 bit platfrom not really supported!!! */ return (BIG_SIZE(bp) == 3) && !BIG_DIGIT(bp,0) && !BIG_DIGIT(bp,1) && BIG_DIGIT(bp,2) == 1; #elif D_EXP == 32 @@ -2467,3 +2482,209 @@ int term_equals_2pow32(Eterm x) return 0; } } + + +#define IS_VALID_CHARACTER(CHAR,BASE) \ + (CHAR < '0' \ + || (CHAR > ('0' + BASE - 1) \ + && !(BASE > 10 \ + && ((CHAR >= 'a' && CHAR < ('a' + BASE - 10)) \ + || (CHAR >= 'A' && CHAR < ('A' + BASE - 10)))))) +#define CHARACTER_FROM_BASE(CHAR) \ + ((CHAR <= '9') ? CHAR - '0' : 10 + ((CHAR <= 'Z') ? CHAR - 'A' : CHAR - 'a')) +#define D_BASE_EXP(BASE) (d_base_exp_lookup[BASE-2]) +#define D_BASE_BASE(BASE) (d_base_base_lookup[BASE-2]) +#define LG2_LOOKUP(BASE) (lg2_lookup[base-2]) + +/* + * for i in 2..64 do + * lg2_lookup[i-2] = log2(i) + * end + * How many bits are needed to store string of size n + */ +const double lg2_lookup[] = { 1.0, 1.58496, 2, 2.32193, 2.58496, 2.80735, 3.0, + 3.16993, 3.32193, 3.45943, 3.58496, 3.70044, 3.80735, 3.90689, 4.0, + 4.08746, 4.16993, 4.24793, 4.32193, 4.39232, 4.45943, 4.52356, 4.58496, + 4.64386, 4.70044, 4.75489, 4.80735, 4.85798, 4.90689, 4.9542, 5.0, + 5.04439, 5.08746, 5.12928, 5.16993, 5.20945, 5.24793, 5.2854, 5.32193, + 5.35755, 5.39232, 5.42626, 5.45943, 5.49185, 5.52356, 5.55459, 5.58496, + 5.61471, 5.64386, 5.67243, 5.70044, 5.72792, 5.75489, 5.78136, 5.80735, + 5.83289, 5.85798, 5.88264, 5.90689, 5.93074, 5.9542, 5.97728, 6.0 }; + +/* + * for i in 2..64 do + * d_base_exp_lookup[i-2] = 31 / lg2_lookup[i-2]; + * end + * How many characters can fit in 31 bits + */ +const byte d_base_exp_lookup[] = { 31, 19, 15, 13, 11, 11, 10, 9, 9, 8, 8, 8, 8, + 7, 7, 7, 7, 7, 7, 7, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5 }; + +/* + * for i in 2..64 do + * d_base_base_lookup[i-2] = pow(i,d_base_exp_lookup[i-2]); + * end + * How much can the characters which fit in 31 bit represent + */ +const Uint d_base_base_lookup[] = { 2147483648, 1162261467, 1073741824, + 1220703125, 362797056, 1977326743, 1073741824, 387420489, 1000000000, + 214358881, 429981696, 815730721, 1475789056, 170859375, 268435456, + 410338673, 612220032, 893871739, 1280000000, 1801088541, 113379904, + 148035889, 191102976, 244140625, 308915776, 387420489, 481890304, + 594823321, 729000000, 887503681, 1073741824, 1291467969, 1544804416, + 1838265625, 60466176, 69343957, 79235168, 90224199, 102400000, + 115856201, 130691232, 147008443, 164916224, 184528125, 205962976, + 229345007, 254803968, 282475249, 312500000, 345025251, 380204032, + 418195493, 459165024, 503284375, 550731776, 601692057, 656356768, + 714924299, 777600000, 844596301, 916132832, 992436543, 1073741824 }; + +Eterm erts_chars_to_integer(Process *BIF_P, char *bytes, + Uint size, const int base) { + Eterm res; + Sint i = 0; + int n = 0; + int neg = 0; + byte b; + Eterm *hp, *hp_end; + int m; + int lg2; + + if (size == 0) + goto bytebuf_to_integer_1_error; + + if (bytes[0] == '-') { + neg = 1; + bytes++; + size--; + + } else if (bytes[0] == '+') { + bytes++; + size--; + } + + if (size < SMALL_DIGITS && base <= 10) { + /* * + * Take shortcut if we know that all chars are '0' < b < '9' and + * fit in a small. This improves speed by about 10% over the generic + * small case. + * */ + while (size--) { + b = *bytes++; + + if (b < '0' || b > ('0'+base-1)) + goto bytebuf_to_integer_1_error; + + i = i * base + b - '0'; + } + + if (neg) + i = -i; + res = make_small(i); + goto bytebuf_to_integer_1_done; + } + + /* + * Calculate the maximum number of bits which will + * be needed to represent the binary + */ + lg2 = ((size+2)*LG2_LOOKUP(base)+1); + + if (lg2 < SMALL_BITS) { + /* Take shortcut if we know it will fit in a small. + * This improves speed by about 30%. + */ + while (size) { + b = *bytes++; + size--; + + if (IS_VALID_CHARACTER(b,base)) + goto bytebuf_to_integer_1_error; + + i = i * base + CHARACTER_FROM_BASE(b); + + } + + if (neg) + i = -i; + res = make_small(i); + goto bytebuf_to_integer_1_done; + + } + + /* Start calculating bignum */ + m = (lg2 + D_EXP-1)/D_EXP; + m = BIG_NEED_SIZE(m); + + hp = HAlloc(BIF_P, m); + hp_end = hp + m; + + if ((i = (size % D_BASE_EXP(base))) == 0) + i = D_BASE_EXP(base); + + n = size - i; + m = 0; + + while (i--) { + b = *bytes++; + + if (IS_VALID_CHARACTER(b,base)) { + HRelease(BIF_P, hp_end, hp); + goto bytebuf_to_integer_1_error; + } + + m = base * m + CHARACTER_FROM_BASE(b); + } + + res = small_to_big(m, hp); + + while (n) { + i = D_BASE_EXP(base); + n -= D_BASE_EXP(base); + m = 0; + while (i--) { + b = *bytes++; + + if (IS_VALID_CHARACTER(b,base)) { + HRelease(BIF_P, hp_end, hp); + goto bytebuf_to_integer_1_error; + } + + m = base * m + CHARACTER_FROM_BASE(b); + } + if (is_small(res)) { + res = small_to_big(signed_val(res), hp); + } + res = big_times_small(res, D_BASE_BASE(base), hp); + if (is_small(res)) { + res = small_to_big(signed_val(res), hp); + } + res = big_plus_small(res, m, hp); + } + + if (is_big(res)) /* check if small */ + res = big_plus_small(res, 0, hp); /* includes conversion to small */ + + if (neg) { + if (is_small(res)) + res = make_small(-signed_val(res)); + else { + Uint *big = big_val(res); /* point to thing */ + *big = bignum_header_neg(*big); + } + } + + if (is_big(res)) { + hp += (big_arity(res) + 1); + } + HRelease(BIF_P, hp_end, hp); + goto bytebuf_to_integer_1_done; + +bytebuf_to_integer_1_error: + return THE_NON_VALUE; + +bytebuf_to_integer_1_done: + return res; + +} diff --git a/erts/emulator/beam/big.h b/erts/emulator/beam/big.h index 7eb1e5afe2..1a7b14170f 100644 --- a/erts/emulator/beam/big.h +++ b/erts/emulator/beam/big.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2011. All Rights Reserved. + * Copyright Ericsson AB 1996-2013. 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 @@ -117,6 +117,7 @@ typedef Uint dsize_t; /* Vector size type */ int big_decimal_estimate(Wterm); Eterm erts_big_to_list(Eterm, Eterm**); char *erts_big_to_string(Wterm x, char *buf, Uint buf_sz); +Uint erts_big_to_binary_bytes(Eterm x, char *buf, Uint buf_sz); Eterm small_times(Sint, Sint, Eterm*); @@ -165,5 +166,7 @@ int term_equals_2pow32(Eterm); Eterm erts_uint64_to_big(Uint64, Eterm **); Eterm erts_sint64_to_big(Sint64, Eterm **); +Eterm erts_chars_to_integer(Process *, char*, Uint, const int); + #endif diff --git a/erts/emulator/beam/binary.c b/erts/emulator/beam/binary.c index dad13f1067..33abac2f3d 100644 --- a/erts/emulator/beam/binary.c +++ b/erts/emulator/beam/binary.c @@ -240,6 +240,98 @@ erts_bin_bytes_to_list(Eterm previous, Eterm* hp, byte* bytes, Uint size, Uint b return previous; } +BIF_RETTYPE binary_to_integer_1(BIF_ALIST_1) +{ + byte *temp_alloc = NULL; + char *bytes; + Uint size; + Eterm res; + + if ((bytes = (char*)erts_get_aligned_binary_bytes(BIF_ARG_1, &temp_alloc)) + == NULL ) + goto binary_to_integer_1_error; + + size = binary_size(BIF_ARG_1); + + if ((res = erts_chars_to_integer(BIF_P,bytes,size,10)) != THE_NON_VALUE) { + erts_free_aligned_binary_bytes(temp_alloc); + return res; + } + + binary_to_integer_1_error: + erts_free_aligned_binary_bytes(temp_alloc); + BIF_ERROR(BIF_P, BADARG); +} + +BIF_RETTYPE binary_to_integer_2(BIF_ALIST_2) +{ + byte *temp_alloc = NULL; + char *bytes; + Uint size; + int base; + Eterm res; + + if (!is_small(BIF_ARG_2)) + BIF_ERROR(BIF_P, BADARG); + + base = signed_val(BIF_ARG_2); + + if (base < 2 || base > 36) + BIF_ERROR(BIF_P, BADARG); + + if ((bytes = (char*)erts_get_aligned_binary_bytes(BIF_ARG_1, &temp_alloc)) + == NULL ) + goto binary_to_integer_2_error; + + size = binary_size(BIF_ARG_1); + + if ((res = erts_chars_to_integer(BIF_P,bytes,size,base)) != THE_NON_VALUE) { + erts_free_aligned_binary_bytes(temp_alloc); + return res; + } + + binary_to_integer_2_error: + + erts_free_aligned_binary_bytes(temp_alloc); + BIF_ERROR(BIF_P, BADARG); + +} + +BIF_RETTYPE integer_to_binary_1(BIF_ALIST_1) +{ + Uint size; + Eterm res; + + if (is_not_integer(BIF_ARG_1)) { + BIF_ERROR(BIF_P, BADARG); + } + + if (is_small(BIF_ARG_1)) { + char *c; + struct Sint_buf ibuf; + + /* Enhancement: If we can calculate the buffer size exactly + * we could avoid an unnecessary copy of buffers. + * Useful if size determination is faster than a copy. + */ + c = Sint_to_buf(signed_val(BIF_ARG_1), &ibuf); + size = sys_strlen(c); + res = new_binary(BIF_P, (byte *)c, size); + } else { + byte* bytes; + Uint n = 0; + + /* Here we also have multiple copies of buffers + * due to new_binary interface + */ + size = big_decimal_estimate(BIF_ARG_1) - 1; /* remove null */ + bytes = (byte*) erts_alloc(ERTS_ALC_T_TMP, sizeof(byte)*size); + n = erts_big_to_binary_bytes(BIF_ARG_1, (char *)bytes, size); + res = new_binary(BIF_P, bytes + size - n, n); + erts_free(ERTS_ALC_T_TMP, (void *) bytes); + } + BIF_RET(res); +} BIF_RETTYPE binary_to_list_1(BIF_ALIST_1) { diff --git a/erts/emulator/beam/code_ix.h b/erts/emulator/beam/code_ix.h index 3f4f9776a4..16ad900228 100644 --- a/erts/emulator/beam/code_ix.h +++ b/erts/emulator/beam/code_ix.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2012. All Rights Reserved. + * Copyright Ericsson AB 2012-2013. 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 diff --git a/erts/emulator/beam/dist.c b/erts/emulator/beam/dist.c index 59fe7ea418..0781665f05 100644 --- a/erts/emulator/beam/dist.c +++ b/erts/emulator/beam/dist.c @@ -2698,7 +2698,7 @@ BIF_RETTYPE setnode_3(BIF_ALIST_3) */ { ErlDrvSizeT disable = ERL_DRV_BUSY_MSGQ_DISABLED; - erl_drv_busy_msgq_limits((ErlDrvPort) pp, &disable, NULL); + erl_drv_busy_msgq_limits(ERTS_Port2ErlDrvPort(pp), &disable, NULL); } pp->dist_entry = dep; diff --git a/erts/emulator/beam/erl_async.c b/erts/emulator/beam/erl_async.c index f2ca193ace..054d1a48f6 100644 --- a/erts/emulator/beam/erl_async.c +++ b/erts/emulator/beam/erl_async.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2000-2012. All Rights Reserved. + * Copyright Ericsson AB 2000-2013. 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 @@ -612,8 +612,8 @@ long driver_async(ErlDrvPort ix, unsigned int* key, sched_id = 1; #endif - prt = erts_drvport2port(ix, NULL); - if (!prt) + prt = erts_drvport2port(ix); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); diff --git a/erts/emulator/beam/erl_bif_ddll.c b/erts/emulator/beam/erl_bif_ddll.c index 7cea0bc2eb..1c3e955f47 100644 --- a/erts/emulator/beam/erl_bif_ddll.c +++ b/erts/emulator/beam/erl_bif_ddll.c @@ -141,7 +141,7 @@ kill_ports_driver_unloaded(DE_Handle *dh) state = erts_atomic32_read_nob(&prt->state); if (!(state & ERTS_PORT_SFLGS_DEAD) && prt->drv_ptr->handle == dh) - driver_failure_atom((ErlDrvPort) prt, "driver_unloaded"); + driver_failure_atom(ERTS_Port2ErlDrvPort(prt), "driver_unloaded"); erts_port_release(prt); } diff --git a/erts/emulator/beam/erl_bif_trace.c b/erts/emulator/beam/erl_bif_trace.c index 69105b8f27..41c98bbffb 100644 --- a/erts/emulator/beam/erl_bif_trace.c +++ b/erts/emulator/beam/erl_bif_trace.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1999-2012. All Rights Reserved. + * Copyright Ericsson AB 1999-2013. 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 diff --git a/erts/emulator/beam/erl_db_hash.h b/erts/emulator/beam/erl_db_hash.h index 73c4078fc5..d17bd9f693 100644 --- a/erts/emulator/beam/erl_db_hash.h +++ b/erts/emulator/beam/erl_db_hash.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1998-2011. All Rights Reserved. + * Copyright Ericsson AB 1998-2013. 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 diff --git a/erts/emulator/beam/erl_db_util.c b/erts/emulator/beam/erl_db_util.c index fc1c946c7d..713ac0ba18 100644 --- a/erts/emulator/beam/erl_db_util.c +++ b/erts/emulator/beam/erl_db_util.c @@ -3415,8 +3415,7 @@ static DMCRet dmc_one_term(DMCContext *context, } default: erl_exit(1, "db_match_compile: " - "Bad object on heap: 0x%08lx\n", - (unsigned long) c); + "Bad object on heap: 0x%bex\n", c); } return retOk; } @@ -4861,7 +4860,7 @@ static Eterm my_copy_struct(Eterm t, Eterm **hp, ErlOffHeap* off_heap) ret = copy_struct(b,sz,hp,off_heap); } else { erl_exit(1, "Trying to constant-copy non constant expression " - "0x%08x in (d)ets:match compilation.", (unsigned long) t); + "0x%bex in (d)ets:match compilation.", t); } } else { sz = size_object(t); @@ -5395,7 +5394,7 @@ void db_match_dis(Binary *bp) erts_printf("Caller\n"); break; default: - erts_printf("??? (0x%08x)\n", *t); + erts_printf("??? (0x%bpx)\n", *t); ++t; break; } @@ -5407,13 +5406,13 @@ void db_match_dis(Binary *bp) first = 0; else erts_printf(", "); - erts_printf("0x%08x", (unsigned long) tmp); + erts_printf("%p", tmp); } erts_printf("}\n"); erts_printf("num_bindings: %d\n", prog->num_bindings); erts_printf("heap_size: %beu\n", prog->heap_size); erts_printf("stack_offset: %beu\n", prog->stack_offset); - erts_printf("text: 0x%08x\n", (unsigned long) prog->text); + erts_printf("text: %p\n", prog->text); erts_printf("stack_size: %d (words)\n", prog->heap_size-prog->stack_offset); } diff --git a/erts/emulator/beam/erl_driver.h b/erts/emulator/beam/erl_driver.h index a9a50a10bf..e280563de1 100644 --- a/erts/emulator/beam/erl_driver.h +++ b/erts/emulator/beam/erl_driver.h @@ -408,6 +408,11 @@ EXTERN int driver_cancel_timer(ErlDrvPort port); EXTERN int driver_read_timer(ErlDrvPort port, unsigned long *time_left); /* + * Inform runtime system about lengthy work. + */ +EXTERN int erl_drv_consume_timeslice(ErlDrvPort port, int percent); + +/* * Get plain-text error message from within a driver */ EXTERN char* erl_errno_id(int error); diff --git a/erts/emulator/beam/erl_gc.c b/erts/emulator/beam/erl_gc.c index a33085315a..298909c921 100644 --- a/erts/emulator/beam/erl_gc.c +++ b/erts/emulator/beam/erl_gc.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2002-2012. All Rights Reserved. + * Copyright Ericsson AB 2002-2013. 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 @@ -231,7 +231,7 @@ erts_next_heap_size(Uint size, Uint offset) low = mid + 1; } } - erl_exit(1, "no next heap size found: %lu, offset %lu\n", (unsigned long)size, (unsigned long)offset); + erl_exit(1, "no next heap size found: %beu, offset %beu\n", size, offset); } return 0; } diff --git a/erts/emulator/beam/erl_init.c b/erts/emulator/beam/erl_init.c index ec3e0d54cb..e7e4030900 100644 --- a/erts/emulator/beam/erl_init.c +++ b/erts/emulator/beam/erl_init.c @@ -496,7 +496,7 @@ void erts_usage(void) erts_fprintf(stderr, "-d don't write a crash dump for internally detected errors\n"); erts_fprintf(stderr, " (halt(String) will still produce a crash dump)\n"); - + erts_fprintf(stderr, "-fn[u|a|l] Control how filenames are interpreted\n"); erts_fprintf(stderr, "-hms size set minimum heap size in words (default %d)\n", H_DEFAULT_SIZE); erts_fprintf(stderr, "-hmbs size set minimum binary virtual heap size in words (default %d)\n", @@ -509,7 +509,7 @@ void erts_usage(void) erts_fprintf(stderr, " Note that this flag is deprecated!\n"); erts_fprintf(stderr, "-M<X> <Y> memory allocator switches,\n"); erts_fprintf(stderr, " see the erts_alloc(3) documentation for more info.\n"); - + erts_fprintf(stderr, "-pc <set> Control what characters are considered printable (default latin1)\n"); erts_fprintf(stderr, "-P number set maximum number of processes on this node,\n"); erts_fprintf(stderr, " valid range is [%d-%d]\n", ERTS_MIN_PROCESSES, ERTS_MAX_PROCESSES); @@ -935,6 +935,12 @@ erl_start(int argc, char **argv) (erts_aint32_t) max_gen_gcs); } + envbufsz = sizeof(envbuf); + if (erts_sys_getenv_raw("ERL_MAX_PORTS", envbuf, &envbufsz) == 0) { + port_tab_sz = atoi(envbuf); + port_tab_sz_ignore_files = 1; + } + #if (defined(__APPLE__) && defined(__MACH__)) || defined(__DARWIN__) /* * The default stack size on MacOS X is too small for pcre. @@ -979,13 +985,30 @@ erl_start(int argc, char **argv) VERBOSE(DEBUG_SYSTEM, ("using display items %d\n",display_items)); break; + case 'p': + if (!strncmp(argv[i],"-pc",3)) { + int printable_chars = ERL_PRINTABLE_CHARACTERS_LATIN1; + arg = get_arg(argv[i]+3, argv[i+1], &i); + if (!strcmp(arg,"unicode")) { + printable_chars = ERL_PRINTABLE_CHARACTERS_UNICODE; + } else if (strcmp(arg,"latin1")) { + erts_fprintf(stderr, "bad range of printable " + "characters: %s\n", arg); + erts_usage(); + } + erts_set_printable_characters(printable_chars); + break; + } else { + erts_fprintf(stderr, "%s unknown flag %s\n", argv[0], argv[i]); + erts_usage(); + } case 'f': if (!strncmp(argv[i],"-fn",3)) { int warning_type = ERL_FILENAME_WARNING_WARNING; arg = get_arg(argv[i]+3, argv[i+1], &i); switch (*arg) { case 'u': - switch (*(argv[i]+4)) { + switch (*(arg+1)) { case 'w': case 0: break; @@ -997,7 +1020,7 @@ erl_start(int argc, char **argv) break; default: erts_fprintf(stderr, "bad type of warnings for " - "wrongly coded filename: %s\n", argv[i]+4); + "wrongly coded filename: %s\n", arg+1); erts_usage(); } erts_set_user_requested_filename_encoding @@ -1014,7 +1037,7 @@ erl_start(int argc, char **argv) ); break; case 'a': - switch (*(argv[i]+4)) { + switch (*(arg+1)) { case 'w': case 0: break; @@ -1026,7 +1049,7 @@ erl_start(int argc, char **argv) break; default: erts_fprintf(stderr, "bad type of warnings for " - "wrongly coded filename: %s\n", argv[i]+4); + "wrongly coded filename: %s\n", arg+1); erts_usage(); } erts_set_user_requested_filename_encoding diff --git a/erts/emulator/beam/erl_instrument.c b/erts/emulator/beam/erl_instrument.c index 7f4349556c..b5b245288b 100644 --- a/erts/emulator/beam/erl_instrument.c +++ b/erts/emulator/beam/erl_instrument.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2003-2011. All Rights Reserved. + * Copyright Ericsson AB 2003-2013. 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 diff --git a/erts/emulator/beam/erl_nif.h b/erts/emulator/beam/erl_nif.h index 62aebcab6c..8006741a63 100644 --- a/erts/emulator/beam/erl_nif.h +++ b/erts/emulator/beam/erl_nif.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2009-2012. All Rights Reserved. + * Copyright Ericsson AB 2009-2013. 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 diff --git a/erts/emulator/beam/erl_port.h b/erts/emulator/beam/erl_port.h index 65b4cd0bfe..377aa72ed5 100644 --- a/erts/emulator/beam/erl_port.h +++ b/erts/emulator/beam/erl_port.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2012. All Rights Reserved. + * Copyright Ericsson AB 2012-2013. 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 @@ -31,7 +31,18 @@ typedef struct ErtsProc2PortSigData_ ErtsProc2PortSigData; #include "erl_thr_progress.h" #include "erl_trace.h" +#ifndef __WIN32__ #define ERTS_DEFAULT_MAX_PORTS (1 << 16) +#else +/* + * Do not default to as many max ports on Windows + * as there are no os limits to stop system + * from running amok. If allowed to go too high + * windows rarely recovers from the errors and + * other OS processes can be effected. + */ +#define ERTS_DEFAULT_MAX_PORTS (1 << 13) +#endif /* __WIN32__ */ #define ERTS_MIN_PORTS 1024 extern int erts_port_synchronous_ops; @@ -40,7 +51,29 @@ extern int erts_port_parallelism; typedef struct erts_driver_t_ erts_driver_t; -#define ERTS_INVALID_ERL_DRV_PORT ((ErlDrvPort) (SWord) -1) +/* + * It would have been preferred to use NULL as value of + * ERTS_INVALID_ERL_DRV_PORT. That would, however, not be + * backward compatible. In pre-R16 systems, 0 was a valid + * port handle and -1 was used as invalid handle, so we + * are stuck with it. + */ +#define ERTS_INVALID_ERL_DRV_PORT ((struct _erl_drv_port *) ((SWord) -1)) +#ifdef DEBUG +/* Make sure we use this api, and do not cast directly */ +#define ERTS_ErlDrvPort2Port(PH) \ + ((PH) == ERTS_INVALID_ERL_DRV_PORT \ + ? ERTS_INVALID_ERL_DRV_PORT \ + : ((Port *) ((PH) - 4711))) +#define ERTS_Port2ErlDrvPort(PH) \ + ((PH) == ERTS_INVALID_ERL_DRV_PORT \ + ? ERTS_INVALID_ERL_DRV_PORT \ + : ((ErlDrvPort) ((PH) + 4711))) +#else +#define ERTS_ErlDrvPort2Port(PH) ((Port *) (PH)) +#define ERTS_Port2ErlDrvPort(PH) ((ErlDrvPort) (PH)) +#endif + #define SMALL_IO_QUEUE 5 /* Number of fixed elements */ typedef struct { @@ -153,6 +186,7 @@ struct _erl_drv_port { ErlDrvPDL port_data_lock; ErtsPrtSD *psd; /* Port specific data */ + int reds; /* Only used while executing driver callbacks */ }; #define ERTS_PORT_GET_CONNECTED(PRT) \ @@ -429,16 +463,16 @@ ERTS_GLB_INLINE void erts_port_release(Port *); ERTS_GLB_INLINE Port *erts_thr_id2port_sflgs(Eterm id, Uint32 invalid_sflgs); ERTS_GLB_INLINE void erts_thr_port_release(Port *prt); #endif -ERTS_GLB_INLINE Port *erts_thr_drvport2port_raw(ErlDrvPort, int); -ERTS_GLB_INLINE Port *erts_drvport2port_raw(ErlDrvPort drvport); -ERTS_GLB_INLINE Port *erts_drvport2port(ErlDrvPort, erts_aint32_t *); -ERTS_GLB_INLINE Port *erts_drvportid2port(Eterm); +ERTS_GLB_INLINE Port *erts_thr_drvport2port(ErlDrvPort, int); +ERTS_GLB_INLINE Port *erts_drvport2port_state(ErlDrvPort, erts_aint32_t *); ERTS_GLB_INLINE Eterm erts_drvport2id(ErlDrvPort); ERTS_GLB_INLINE Uint32 erts_portid2status(Eterm); ERTS_GLB_INLINE int erts_is_port_alive(Eterm); ERTS_GLB_INLINE int erts_is_valid_tracer_port(Eterm); ERTS_GLB_INLINE int erts_port_driver_callback_epilogue(Port *, erts_aint32_t *); +#define erts_drvport2port(Prt) erts_drvport2port_state((Prt), NULL) + #if ERTS_GLB_INLINE_INCL_FUNC_DEF ERTS_GLB_INLINE Port *erts_pix2port(int ix) @@ -620,90 +654,72 @@ erts_thr_port_release(Port *prt) #endif -ERTS_GLB_INLINE Port* -erts_thr_drvport2port_raw(ErlDrvPort drvport, int lock_pdl) +ERTS_GLB_INLINE Port * +erts_thr_drvport2port(ErlDrvPort drvport, int lock_pdl) { + Port *prt = ERTS_ErlDrvPort2Port(drvport); + ASSERT(prt != NULL); + if (prt == ERTS_INVALID_ERL_DRV_PORT) + return ERTS_INVALID_ERL_DRV_PORT; + + if (lock_pdl && prt->port_data_lock) + driver_pdl_lock(prt->port_data_lock); + #if ERTS_ENABLE_LOCK_CHECK - int emu_thread = erts_lc_is_emu_thr(); -#endif - if (drvport == ERTS_INVALID_ERL_DRV_PORT) - return NULL; - else { - Port *prt = (Port *) drvport; - if (lock_pdl && prt->port_data_lock) - driver_pdl_lock(prt->port_data_lock); -#if ERTS_ENABLE_LOCK_CHECK - if (!ERTS_IS_CRASH_DUMPING) { - if (emu_thread) { - ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); - ERTS_LC_ASSERT(!prt->port_data_lock - || erts_lc_mtx_is_locked(&prt->port_data_lock->mtx)); - } - else { - ERTS_LC_ASSERT(prt->port_data_lock); - ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&prt->port_data_lock->mtx)); - } + if (!ERTS_IS_CRASH_DUMPING) { + if (erts_lc_is_emu_thr()) { + ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); + ERTS_LC_ASSERT(!prt->port_data_lock + || erts_lc_mtx_is_locked(&prt->port_data_lock->mtx)); + } + else { + ERTS_LC_ASSERT(prt->port_data_lock); + ERTS_LC_ASSERT(erts_lc_mtx_is_locked(&prt->port_data_lock->mtx)); } -#endif - return prt; } -} +#endif -ERTS_GLB_INLINE Port* -erts_drvport2port_raw(ErlDrvPort drvport) -{ - ERTS_LC_ASSERT(erts_lc_is_emu_thr()); - if (drvport == ERTS_INVALID_ERL_DRV_PORT) - return NULL; - else { - Port *prt = (Port *) drvport; - ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt) - || ERTS_IS_CRASH_DUMPING); - return prt; + if (erts_atomic32_read_nob(&prt->state) + & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) { + if (lock_pdl && prt->port_data_lock) + driver_pdl_unlock(prt->port_data_lock); + return ERTS_INVALID_ERL_DRV_PORT; } -} - -ERTS_GLB_INLINE Port* -erts_drvport2port(ErlDrvPort drvport, erts_aint32_t *statep) -{ - Port *prt = erts_drvport2port_raw(drvport); - erts_aint32_t state; - if (!prt) - return NULL; - state = erts_atomic32_read_nob(&prt->state); - if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) - return NULL; - if (statep) - *statep = state; return prt; } -ERTS_GLB_INLINE Port* -erts_drvportid2port(Eterm id) +ERTS_GLB_INLINE Port * +erts_drvport2port_state(ErlDrvPort drvport, erts_aint32_t *statep) { - Port *prt; + Port *prt = ERTS_ErlDrvPort2Port(drvport); erts_aint32_t state; - if (is_not_internal_port(id)) - return NULL; - prt = (Port *) erts_ptab_pix2intptr_nob(&erts_port, - internal_port_index(id)); - if (!prt) - return NULL; + ASSERT(prt); + ERTS_LC_ASSERT(erts_lc_is_emu_thr()); + if (prt == ERTS_INVALID_ERL_DRV_PORT) + return ERTS_INVALID_ERL_DRV_PORT; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt) || ERTS_IS_CRASH_DUMPING); - if (prt->common.id != id) - return NULL; + /* + * This state check is only needed since a driver callback + * might terminate the port, and then call back into the + * emulator. Drivers should preferably have been forbidden + * to call into the emulator after terminating the port, + * but it has been like this for ages. Perhaps forbid this + * in some future major release? + */ state = erts_atomic32_read_nob(&prt->state); if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) - return NULL; + return ERTS_INVALID_ERL_DRV_PORT; + if (statep) + *statep = state; return prt; } ERTS_GLB_INLINE Eterm erts_drvport2id(ErlDrvPort drvport) { - Port *prt = erts_drvport2port_raw(drvport); - if (!prt) + Port *prt = erts_drvport2port(drvport); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return am_undefined; else return prt->common.id; diff --git a/erts/emulator/beam/erl_port_task.c b/erts/emulator/beam/erl_port_task.c index dbc4a06c2d..ce045ec94e 100644 --- a/erts/emulator/beam/erl_port_task.c +++ b/erts/emulator/beam/erl_port_task.c @@ -685,12 +685,12 @@ enqueue_proc2port_data(Port *pp, void erl_drv_busy_msgq_limits(ErlDrvPort dport, ErlDrvSizeT *lowp, ErlDrvSizeT *highp) { - Port *pp = erts_drvport2port(dport, NULL); - ErtsPortTaskBusyPortQ *bpq = pp->sched.taskq.bpq; + Port *pp = erts_drvport2port(dport); + ErtsPortTaskBusyPortQ *bpq; int written = 0, resume_procs = 0; ErlDrvSizeT low, high; - if (!pp || !bpq) { + if (pp == ERTS_INVALID_ERL_DRV_PORT || !(bpq = pp->sched.taskq.bpq)) { if (lowp) *lowp = ERL_DRV_BUSY_MSGQ_DISABLED; if (highp) @@ -1160,6 +1160,27 @@ select_task_for_exec(Port *pp, } /* + * Cut time slice + */ + +int +erl_drv_consume_timeslice(ErlDrvPort dprt, int percent) +{ + Port *pp = erts_drvport2port(dprt); + if (pp == ERTS_INVALID_ERL_DRV_PORT) + return -1; + if (percent < 1) + percent = 1; + else if (100 < percent) + percent = 100; + pp->reds += percent*((CONTEXT_REDS+99)/100); + if (pp->reds < CONTEXT_REDS) + return 0; + pp->reds = CONTEXT_REDS; + return 1; +} + +/* * Abort a scheduled task. */ @@ -1509,7 +1530,6 @@ fail: void erts_port_task_free_port(Port *pp) { - ErtsProcList *suspended; erts_aint32_t flags; ErtsRunQueue *runq; @@ -1522,19 +1542,16 @@ erts_port_task_free_port(Port *pp) erts_port_task_sched_lock(&pp->sched); flags = erts_smp_atomic32_read_bor_relb(&pp->sched.flags, ERTS_PTS_FLG_EXIT); - suspended = pp->suspended; - pp->suspended = NULL; erts_port_task_sched_unlock(&pp->sched); erts_atomic32_read_bset_relb(&pp->state, - (ERTS_PORT_SFLG_CLOSING + (ERTS_PORT_SFLG_CONNECTED + | ERTS_PORT_SFLG_EXITING + | ERTS_PORT_SFLG_CLOSING | ERTS_PORT_SFLG_FREE), ERTS_PORT_SFLG_FREE); erts_smp_runq_unlock(runq); - if (erts_proclist_fetch(&suspended, NULL)) - erts_resume_processes(suspended); - if (!(flags & (ERTS_PTS_FLG_IN_RUNQ|ERTS_PTS_FLG_EXEC))) begin_port_cleanup(pp, NULL, NULL); } @@ -1554,7 +1571,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) int processing_busy_q; int res = 0; int vreds = 0; - int reds = ERTS_PORT_REDS_EXECUTE; + int reds = 0; erts_aint_t io_tasks_executed = 0; int fpe_was_unmasked; erts_aint32_t state; @@ -1599,6 +1616,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) fpe_was_unmasked = erts_block_fpe(); state = erts_atomic32_read_nob(&pp->state); + pp->reds = ERTS_PORT_REDS_EXECUTE; goto begin_handle_tasks; while (1) { @@ -1625,14 +1643,14 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) switch (ptp->type) { case ERTS_PORT_TASK_TIMEOUT: - reds += ERTS_PORT_REDS_TIMEOUT; + reds = ERTS_PORT_REDS_TIMEOUT; if (!(state & ERTS_PORT_SFLGS_DEAD)) { DTRACE_DRIVER(driver_timeout, pp); (*pp->drv_ptr->timeout)((ErlDrvData) pp->drv_data); } break; case ERTS_PORT_TASK_INPUT: - reds += ERTS_PORT_REDS_INPUT; + reds = ERTS_PORT_REDS_INPUT; ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0); DTRACE_DRIVER(driver_ready_input, pp); /* NOTE some windows drivers use ->ready_input for input and output */ @@ -1641,7 +1659,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) io_tasks_executed++; break; case ERTS_PORT_TASK_OUTPUT: - reds += ERTS_PORT_REDS_OUTPUT; + reds = ERTS_PORT_REDS_OUTPUT; ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0); DTRACE_DRIVER(driver_ready_output, pp); (*pp->drv_ptr->ready_output)((ErlDrvData) pp->drv_data, @@ -1649,7 +1667,7 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) io_tasks_executed++; break; case ERTS_PORT_TASK_EVENT: - reds += ERTS_PORT_REDS_EVENT; + reds = ERTS_PORT_REDS_EVENT; ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0); DTRACE_DRIVER(driver_event, pp); (*pp->drv_ptr->event)((ErlDrvData) pp->drv_data, @@ -1661,22 +1679,22 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) ErtsProc2PortSigData *sigdp = &ptp->u.alive.td.psig.data; ASSERT((state & ERTS_PORT_SFLGS_DEAD) == 0); if (!pp->sched.taskq.bpq) - reds += ptp->u.alive.td.psig.callback(pp, - state, - ERTS_PROC2PORT_SIG_EXEC, - sigdp); + reds = ptp->u.alive.td.psig.callback(pp, + state, + ERTS_PROC2PORT_SIG_EXEC, + sigdp); else { ErlDrvSizeT size = erts_proc2port_sig_command_data_size(sigdp); - reds += ptp->u.alive.td.psig.callback(pp, - state, - ERTS_PROC2PORT_SIG_EXEC, - sigdp); + reds = ptp->u.alive.td.psig.callback(pp, + state, + ERTS_PROC2PORT_SIG_EXEC, + sigdp); dequeued_proc2port_data(pp, size); } break; } case ERTS_PORT_TASK_DIST_CMD: - reds += erts_dist_command(pp, CONTEXT_REDS-reds); + reds = erts_dist_command(pp, CONTEXT_REDS - pp->reds); break; default: erl_exit(ERTS_ABORT_EXIT, @@ -1701,7 +1719,10 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) vreds += ERTS_PORT_CALLBACK_VREDS; reds += ERTS_PORT_CALLBACK_VREDS; - if (reds >= CONTEXT_REDS) + pp->reds += reds; + reds = 0; + + if (pp->reds >= CONTEXT_REDS) break; } @@ -1725,6 +1746,8 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) active = finalize_exec(pp, &execq, processing_busy_q); + reds = pp->reds - vreds; + erts_port_release(pp); *curr_port_pp = NULL; @@ -1770,7 +1793,6 @@ erts_port_task_execute(ErtsRunQueue *runq, Port **curr_port_pp) res = (erts_smp_atomic_read_nob(&erts_port_task_outstanding_io_tasks) != (erts_aint_t) 0); - reds -= vreds; runq->scheduler->reductions += reds; ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq)); @@ -1793,10 +1815,11 @@ begin_port_cleanup(Port *pp, ErtsPortTask **execqp, int *processing_busy_q_p) int i, max; ErtsPortTaskBusyCallerTable *tabp; ErtsPortTask *qs[3]; + ErtsPortTaskHandleList *free_nshp = NULL; + ErtsProcList *plp; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(pp)); - /* * Abort remaining tasks... * @@ -1935,7 +1958,42 @@ begin_port_cleanup(Port *pp, ErtsPortTask **execqp, int *processing_busy_q_p) erts_smp_atomic32_read_band_nob(&pp->sched.flags, ~(ERTS_PTS_FLG_HAVE_BUSY_TASKS - |ERTS_PTS_FLG_HAVE_TASKS)); + |ERTS_PTS_FLG_HAVE_TASKS + |ERTS_PTS_FLGS_BUSY)); + + erts_port_task_sched_lock(&pp->sched); + + /* Cleanup nosuspend handles... */ + free_nshp = (pp->sched.taskq.local.busy.nosuspend + ? get_free_nosuspend_handles(pp) + : NULL); + ASSERT(!pp->sched.taskq.local.busy.nosuspend); + + /* Make sure not to leave any processes suspended on the port... */ + plp = pp->suspended; + pp->suspended = NULL; + + erts_port_task_sched_unlock(&pp->sched); + + if (free_nshp) + free_nosuspend_handles(free_nshp); + + if (erts_proclist_fetch(&plp, NULL)) { +#ifdef USE_VM_PROBES + if (DTRACE_ENABLED(process_port_unblocked)) { + DTRACE_CHARBUF(port_str, 16); + DTRACE_CHARBUF(pid_str, 16); + ErtsProcList* plp2 = plp; + + erts_snprintf(port_str, sizeof(port_str), "%T", pp->common.id); + while (plp2 != NULL) { + erts_snprintf(pid_str, sizeof(pid_str), "%T", plp2->pid); + DTRACE2(process_port_unblocked, pid_str, port_str); + } + } +#endif + erts_resume_processes(plp); + } /* * Schedule cleanup of port structure... diff --git a/erts/emulator/beam/erl_printf_term.c b/erts/emulator/beam/erl_printf_term.c index 2320b64295..436147749e 100644 --- a/erts/emulator/beam/erl_printf_term.c +++ b/erts/emulator/beam/erl_printf_term.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2005-2011. All Rights Reserved. + * Copyright Ericsson AB 2005-2013. 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 @@ -57,17 +57,17 @@ do { \ (CNT) += res__; \ } while (0) -#define PRINT_ULONG(CNT, FN, ARG, C, P, W, I) \ +#define PRINT_UWORD(CNT, FN, ARG, C, P, W, I) \ do { \ - int res__ = erts_printf_ulong((FN), (ARG), (C), (P), (W), (I)); \ + int res__ = erts_printf_uword((FN), (ARG), (C), (P), (W), (I)); \ if (res__ < 0) \ return res__; \ (CNT) += res__; \ } while (0) -#define PRINT_SLONG(CNT, FN, ARG, C, P, W, I) \ +#define PRINT_SWORD(CNT, FN, ARG, C, P, W, I) \ do { \ - int res__ = erts_printf_slong((FN), (ARG), (C), (P), (W), (I)); \ + int res__ = erts_printf_sword((FN), (ARG), (C), (P), (W), (I)); \ if (res__ < 0) \ return res__; \ (CNT) += res__; \ @@ -153,7 +153,7 @@ static int print_atom_name(fmtfn_t fn, void* arg, Eterm atom, long *dcount) if ((i < 0) || (i >= atom_table_size()) || (atom_tab(i) == NULL)) { PRINT_STRING(res, fn, arg, "<bad atom index: "); - PRINT_SLONG(res, fn, arg, 'd', 0, 1, (signed long) i); + PRINT_SWORD(res, fn, arg, 'd', 0, 1, (ErlPfSWord) i); PRINT_CHAR(res, fn, arg, '>'); return res; } @@ -203,7 +203,7 @@ static int print_atom_name(fmtfn_t fn, void* arg, Eterm atom, long *dcount) default: if (IS_CNTRL(c)) { PRINT_CHAR(res, fn, arg, '\\'); - PRINT_ULONG(res, fn, arg, 'o', 1, 3, (unsigned long) c); + PRINT_UWORD(res, fn, arg, 'o', 1, 3, (ErlPfUWord) c); } else PRINT_CHAR(res, fn, arg, (char) c); @@ -334,7 +334,7 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, break; } case SMALL_DEF: - PRINT_SLONG(res, fn, arg, 'd', 0, 1, (signed long) signed_val(obj)); + PRINT_SWORD(res, fn, arg, 'd', 0, 1, (ErlPfSWord) signed_val(obj)); break; case BIG_DEF: { int print_res; @@ -360,36 +360,36 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, case REF_DEF: case EXTERNAL_REF_DEF: PRINT_STRING(res, fn, arg, "#Ref<"); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) ref_channel_no(wobj)); + PRINT_UWORD(res, fn, arg, 'u', 0, 1, + (ErlPfUWord) ref_channel_no(wobj)); ref_num = ref_numbers(wobj); for (i = ref_no_of_numbers(wobj)-1; i >= 0; i--) { PRINT_CHAR(res, fn, arg, '.'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, (unsigned long) ref_num[i]); + PRINT_UWORD(res, fn, arg, 'u', 0, 1, (ErlPfUWord) ref_num[i]); } PRINT_CHAR(res, fn, arg, '>'); break; case PID_DEF: case EXTERNAL_PID_DEF: PRINT_CHAR(res, fn, arg, '<'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) pid_channel_no(wobj)); + PRINT_UWORD(res, fn, arg, 'u', 0, 1, + (ErlPfUWord) pid_channel_no(wobj)); PRINT_CHAR(res, fn, arg, '.'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) pid_number(wobj)); + PRINT_UWORD(res, fn, arg, 'u', 0, 1, + (ErlPfUWord) pid_number(wobj)); PRINT_CHAR(res, fn, arg, '.'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) pid_serial(wobj)); + PRINT_UWORD(res, fn, arg, 'u', 0, 1, + (ErlPfUWord) pid_serial(wobj)); PRINT_CHAR(res, fn, arg, '>'); break; case PORT_DEF: case EXTERNAL_PORT_DEF: PRINT_STRING(res, fn, arg, "#Port<"); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) port_channel_no(wobj)); + PRINT_UWORD(res, fn, arg, 'u', 0, 1, + (ErlPfUWord) port_channel_no(wobj)); PRINT_CHAR(res, fn, arg, '.'); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, - (unsigned long) port_number(wobj)); + PRINT_UWORD(res, fn, arg, 'u', 0, 1, + (ErlPfUWord) port_number(wobj)); PRINT_CHAR(res, fn, arg, '>'); break; case LIST_DEF: @@ -446,7 +446,7 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, PRINT_STRING(res, fn, arg, "<<1 byte>>"); else { PRINT_STRING(res, fn, arg, "<<"); - PRINT_ULONG(res, fn, arg, 'u', 0, 1, (unsigned long) pb->size); + PRINT_UWORD(res, fn, arg, 'u', 0, 1, (ErlPfUWord) pb->size); PRINT_STRING(res, fn, arg, " bytes>>"); } } @@ -462,8 +462,8 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, PRINT_CHAR(res, fn, arg, '.'); PRINT_BUF(res, fn, arg, name->name, name->len); PRINT_CHAR(res, fn, arg, '.'); - PRINT_SLONG(res, fn, arg, 'd', 0, 1, - (signed long) ep->code[2]); + PRINT_SWORD(res, fn, arg, 'd', 0, 1, + (ErlPfSWord) ep->code[2]); PRINT_CHAR(res, fn, arg, '>'); } break; @@ -475,11 +475,11 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, PRINT_STRING(res, fn, arg, "#Fun<"); PRINT_BUF(res, fn, arg, ap->name, ap->len); PRINT_CHAR(res, fn, arg, '.'); - PRINT_SLONG(res, fn, arg, 'd', 0, 1, - (signed long) funp->fe->old_index); + PRINT_SWORD(res, fn, arg, 'd', 0, 1, + (ErlPfSWord) funp->fe->old_index); PRINT_CHAR(res, fn, arg, '.'); - PRINT_SLONG(res, fn, arg, 'd', 0, 1, - (signed long) funp->fe->old_uniq); + PRINT_SWORD(res, fn, arg, 'd', 0, 1, + (ErlPfSWord) funp->fe->old_uniq); PRINT_CHAR(res, fn, arg, '>'); } break; @@ -498,10 +498,13 @@ print_term(fmtfn_t fn, void* arg, Eterm obj, long *dcount, } int -erts_printf_term(fmtfn_t fn, void* arg, unsigned long term, long precision, - unsigned long* term_base) +erts_printf_term(fmtfn_t fn, void* arg, ErlPfEterm term, long precision, + ErlPfEterm* term_base) { - int res = print_term(fn, arg, (Eterm)term, &precision, (Eterm*)term_base); + int res; + ASSERT(sizeof(ErlPfEterm) == sizeof(Eterm)); + + res = print_term(fn, arg, (Eterm)term, &precision, (Eterm*)term_base); if (res < 0) return res; if (precision <= 0) diff --git a/erts/emulator/beam/erl_printf_term.h b/erts/emulator/beam/erl_printf_term.h index a48a3de34c..f92c99d713 100644 --- a/erts/emulator/beam/erl_printf_term.h +++ b/erts/emulator/beam/erl_printf_term.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2005-2011. All Rights Reserved. + * Copyright Ericsson AB 2005-2013. 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 @@ -21,6 +21,6 @@ #define ERL_PRINTF_TERM_H__ #include "erl_printf_format.h" -int erts_printf_term(fmtfn_t fn, void* arg, unsigned long term, long precision, - unsigned long* term_base); +int erts_printf_term(fmtfn_t fn, void* arg, ErlPfEterm term, long precision, + ErlPfEterm* term_base); #endif diff --git a/erts/emulator/beam/erl_process.c b/erts/emulator/beam/erl_process.c index 96af19fb83..16b6b1c79d 100644 --- a/erts/emulator/beam/erl_process.c +++ b/erts/emulator/beam/erl_process.c @@ -1811,7 +1811,7 @@ erts_set_aux_work_timeout(int ix, erts_aint32_t type, int enable) ERTS_DBG_CHK_AUX_WORK_VAL(type); ERTS_DBG_CHK_AUX_WORK_VAL(erts_atomic32_read_nob(&aux_work_tmo->type[ix])); -// erts_fprintf(stderr, "t(%d, 0x%x, %d)\n", ix, type, enable); + /* erts_fprintf(stderr, "t(%d, 0x%x, %d)\n", ix, type, enable); */ if (!enable) { old = erts_atomic32_read_band_mb(&aux_work_tmo->type[ix], ~type); @@ -4311,8 +4311,7 @@ erts_sched_set_wakeup_other_type(char *str) wakeup_other.type = type; return 0; #else - if (sys_strcmp(str, "proposal") == 0 || sys_strcmp(str, "default") == 0 || - sys_strcmp(str, "legacy") == 0) { + if (sys_strcmp(str, "default") == 0 || sys_strcmp(str, "legacy") == 0) { return 0; } return EINVAL; diff --git a/erts/emulator/beam/erl_smp.h b/erts/emulator/beam/erl_smp.h index 34c90c0bda..ecb5525022 100644 --- a/erts/emulator/beam/erl_smp.h +++ b/erts/emulator/beam/erl_smp.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2005-2012. All Rights Reserved. + * Copyright Ericsson AB 2005-2013. 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 @@ -259,6 +259,9 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #define erts_smp_dw_atomic_read_wb erts_dw_atomic_read_wb #define erts_smp_dw_atomic_cmpxchg_wb erts_dw_atomic_cmpxchg_wb +#define erts_smp_dw_atomic_set_dirty erts_dw_atomic_set_dirty +#define erts_smp_dw_atomic_read_dirty erts_dw_atomic_read_dirty + /* Word size atomics */ #define erts_smp_atomic_init_nob erts_atomic_init_nob @@ -366,6 +369,9 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #define erts_smp_atomic_cmpxchg_wb erts_atomic_cmpxchg_wb #define erts_smp_atomic_read_bset_wb erts_atomic_read_bset_wb +#define erts_smp_atomic_set_dirty erts_atomic_set_dirty +#define erts_smp_atomic_read_dirty erts_atomic_read_dirty + /* 32-bit atomics */ #define erts_smp_atomic32_init_nob erts_atomic32_init_nob @@ -473,6 +479,9 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #define erts_smp_atomic32_cmpxchg_wb erts_atomic32_cmpxchg_wb #define erts_smp_atomic32_read_bset_wb erts_atomic32_read_bset_wb +#define erts_smp_atomic32_set_dirty erts_atomic32_set_dirty +#define erts_smp_atomic32_read_dirty erts_atomic32_read_dirty + #else /* !ERTS_SMP */ /* Double word size atomics */ @@ -512,6 +521,9 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #define erts_smp_dw_atomic_read_wb erts_no_dw_atomic_read #define erts_smp_dw_atomic_cmpxchg_wb erts_no_dw_atomic_cmpxchg +#define erts_smp_dw_atomic_set_dirty erts_no_dw_atomic_set +#define erts_smp_dw_atomic_read_dirty erts_no_dw_atomic_read + /* Word size atomics */ #define erts_smp_atomic_init_nob erts_no_atomic_set @@ -619,6 +631,9 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #define erts_smp_atomic_cmpxchg_wb erts_no_atomic_cmpxchg #define erts_smp_atomic_read_bset_wb erts_no_atomic_read_bset +#define erts_smp_atomic_set_dirty erts_no_atomic_set +#define erts_smp_atomic_read_dirty erts_no_atomic_read + /* 32-bit atomics */ #define erts_smp_atomic32_init_nob erts_no_atomic32_set @@ -726,6 +741,9 @@ ERTS_GLB_INLINE void erts_smp_thr_sigwait(const sigset_t *set, int *sig); #define erts_smp_atomic32_cmpxchg_wb erts_no_atomic32_cmpxchg #define erts_smp_atomic32_read_bset_wb erts_no_atomic32_read_bset +#define erts_smp_atomic32_set_dirty erts_no_atomic32_set +#define erts_smp_atomic32_read_dirty erts_no_atomic32_read + #endif /* !ERTS_SMP */ #if ERTS_GLB_INLINE_INCL_FUNC_DEF diff --git a/erts/emulator/beam/erl_thr_progress.c b/erts/emulator/beam/erl_thr_progress.c index 9effdae98e..1292cb0678 100644 --- a/erts/emulator/beam/erl_thr_progress.c +++ b/erts/emulator/beam/erl_thr_progress.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011-2012. All Rights Reserved. + * Copyright Ericsson AB 2011-2013. 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 diff --git a/erts/emulator/beam/erl_thr_queue.c b/erts/emulator/beam/erl_thr_queue.c index f07964a265..f8ca87ddcc 100644 --- a/erts/emulator/beam/erl_thr_queue.c +++ b/erts/emulator/beam/erl_thr_queue.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011-2012. All Rights Reserved. + * Copyright Ericsson AB 2011-2013. 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 @@ -113,6 +113,11 @@ sl_element_free(ErtsThrQElement_t *p) #endif +#define ErtsThrQDirtyReadEl(A) \ + ((ErtsThrQElement_t *) erts_atomic_read_dirty((A))) +#define ErtsThrQDirtySetEl(A, V) \ + erts_atomic_set_dirty((A), (erts_aint_t) (V)) + typedef union { ErtsThrQ_t q; char align__[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsThrQ_t))]; @@ -137,7 +142,7 @@ erts_thr_q_initialize(ErtsThrQ_t *q, ErtsThrQInit_t *qi) q->last = NULL; q->q.blk = NULL; #else - erts_atomic_init_nob(&q->tail.data.marker.next.atmc, ERTS_AINT_NULL); + erts_atomic_init_nob(&q->tail.data.marker.next, ERTS_AINT_NULL); q->tail.data.marker.data.ptr = NULL; erts_atomic_init_nob(&q->tail.data.last, (erts_aint_t) &q->tail.data.marker); @@ -150,7 +155,7 @@ erts_thr_q_initialize(ErtsThrQ_t *q, ErtsThrQInit_t *qi) if (!q->tail.data.notify) q->tail.data.notify = noop_callback; - q->head.head.ptr = &q->tail.data.marker; + erts_atomic_init_nob(&q->head.head, (erts_aint_t) &q->tail.data.marker); q->head.live = qi->live.objects; q->head.first = &q->tail.data.marker; q->head.unref_end = &q->tail.data.marker; @@ -296,17 +301,17 @@ element_free(ErtsThrQ_t *q, ErtsThrQElement_t *el) #ifdef USE_THREADS static ERTS_INLINE ErtsThrQElement_t * -enqueue_managed(ErtsThrQ_t *q, ErtsThrQElement_t *this, int want_last) +enqueue_managed(ErtsThrQ_t *q, ErtsThrQElement_t *this) { erts_aint_t ilast, itmp; - erts_atomic_init_nob(&this->next.atmc, ERTS_AINT_NULL); + erts_atomic_init_nob(&this->next, ERTS_AINT_NULL); /* Enqueue at end of list... */ ilast = erts_atomic_read_nob(&q->tail.data.last); while (1) { ErtsThrQElement_t *last = (ErtsThrQElement_t *) ilast; - itmp = erts_atomic_cmpxchg_mb(&last->next.atmc, + itmp = erts_atomic_cmpxchg_mb(&last->next, (erts_aint_t) this, ERTS_AINT_NULL); if (itmp == ERTS_AINT_NULL) @@ -316,31 +321,57 @@ enqueue_managed(ErtsThrQ_t *q, ErtsThrQElement_t *this, int want_last) /* Move last pointer forward... */ while (1) { - if (want_last) { - if (erts_atomic_read_rb(&this->next.atmc) != ERTS_AINT_NULL) { - /* Someone else will move it forward */ - ilast = erts_atomic_read_rb(&q->tail.data.last); - return (ErtsThrQElement_t *) ilast; - } - } - else { - if (erts_atomic_read_nob(&this->next.atmc) != ERTS_AINT_NULL) { - /* Someone else will move it forward */ - return NULL; - } + if (erts_atomic_read_rb(&this->next) != ERTS_AINT_NULL) { + /* Someone else will move it forward */ + ilast = erts_atomic_read_rb(&q->tail.data.last); + return (ErtsThrQElement_t *) ilast; } itmp = erts_atomic_cmpxchg_mb(&q->tail.data.last, (erts_aint_t) this, ilast); if (ilast == itmp) - return want_last ? this : NULL; + return this; ilast = itmp; } } +static ERTS_INLINE ErtsThrQElement_t * +enqueue_marker(ErtsThrQ_t *q, ErtsThrQElement_t **headp) +{ + int maybe_notify; + erts_aint_t inext; + ErtsThrQElement_t *last, *head; + + if (headp) + head = *headp; + else + head = ErtsThrQDirtyReadEl(&q->head.head); + + ASSERT(!q->head.used_marker); + q->head.used_marker = 1; + last = enqueue_managed(q, &q->tail.data.marker); + maybe_notify = &q->tail.data.marker == last; + inext = erts_atomic_read_acqb(&head->next); + if (inext == (erts_aint_t) &q->tail.data.marker) { + ErtsThrQDirtySetEl(&q->head.head, &q->tail.data.marker); + if (headp) + *headp = &q->tail.data.marker; + } + else if (maybe_notify) { + /* + * We need to notify; otherwise, we might loose a notification + * for a concurrently inserted element. + */ + q->head.notify(q->head.arg); + } + return last; +} + + static ErtsThrQCleanState_t clean(ErtsThrQ_t *q, int max_ops, int do_notify) { + ErtsThrQElement_t *head; erts_aint_t ilast; int um_refc_ix; int ops; @@ -349,7 +380,8 @@ clean(ErtsThrQ_t *q, int max_ops, int do_notify) ErtsThrQElement_t *tmp; restart: ASSERT(q->head.first); - if (q->head.first == q->head.head.ptr) { + head = ErtsThrQDirtyReadEl(&q->head.head); + if (q->head.first == head) { q->head.clean_reached_head_count++; if (q->head.clean_reached_head_count >= ERTS_THR_Q_MAX_CLEAN_REACHED_HEAD_COUNT) { @@ -362,19 +394,20 @@ clean(ErtsThrQ_t *q, int max_ops, int do_notify) break; if (q->head.first == &q->tail.data.marker) { q->head.used_marker = 0; - q->head.first = q->head.first->next.ptr; + q->head.first = ErtsThrQDirtyReadEl(&q->head.first->next); goto restart; } tmp = q->head.first; - q->head.first = q->head.first->next.ptr; + q->head.first = ErtsThrQDirtyReadEl(&q->head.first->next); if (q->head.deq_fini.automatic) element_free(q, tmp); else { tmp->data.ptr = (void *) (UWord) q->head.live; if (!q->head.deq_fini.start) q->head.deq_fini.start = tmp; - else if (q->head.deq_fini.end->next.ptr == &q->tail.data.marker) - q->head.deq_fini.end->next.ptr = tmp; + else if (ErtsThrQDirtyReadEl(&q->head.deq_fini.end->next) + == &q->tail.data.marker) + ErtsThrQDirtySetEl(&q->head.deq_fini.end->next, tmp); q->head.deq_fini.end = tmp; } } @@ -401,21 +434,8 @@ clean(ErtsThrQ_t *q, int max_ops, int do_notify) q->head.unref_end = q->head.next.unref_end; if (!q->head.used_marker - && q->head.unref_end == (ErtsThrQElement_t *) ilast) { - q->head.used_marker = 1; - ilast = (erts_aint_t) enqueue_managed(q, - &q->tail.data.marker, - 1); - if (q->head.head.ptr == q->head.unref_end) { - ErtsThrQElement_t *next; - next = ((ErtsThrQElement_t *) - erts_atomic_read_acqb(&q->head.head.ptr->next.atmc)); - if (next == &q->tail.data.marker) { - q->head.head.ptr->next.ptr = &q->tail.data.marker; - q->head.head.ptr = &q->tail.data.marker; - } - } - } + && q->head.unref_end == (ErtsThrQElement_t *) ilast) + ilast = (erts_aint_t) enqueue_marker(q, NULL); if (q->head.unref_end == (ErtsThrQElement_t *) ilast) ERTS_SMP_MEMORY_BARRIER; @@ -436,20 +456,16 @@ clean(ErtsThrQ_t *q, int max_ops, int do_notify) } #endif - if (q->head.first == q->head.head.ptr) { + head = ErtsThrQDirtyReadEl(&q->head.head); + if (q->head.first == head) { inspect_head: if (!q->head.used_marker) { erts_aint_t inext; - inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc); + inext = erts_atomic_read_acqb(&head->next); if (inext == ERTS_AINT_NULL) { - q->head.used_marker = 1; - (void) enqueue_managed(q, &q->tail.data.marker, 0); - inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc); - if (inext == (erts_aint_t) &q->tail.data.marker) { - q->head.head.ptr->next.ptr = &q->tail.data.marker; - q->head.head.ptr = &q->tail.data.marker; + enqueue_marker(q, &head); + if (head == &q->tail.data.marker) goto check_thr_progress; - } } } @@ -506,26 +522,27 @@ erts_thr_q_inspect(ErtsThrQ_t *q, int ensure_empty) #ifndef USE_THREADS return ERTS_THR_Q_CLEAN; #else + ErtsThrQElement_t *head = ErtsThrQDirtyReadEl(&q->head.head); if (ensure_empty) { erts_aint_t inext; - inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc); + inext = erts_atomic_read_acqb(&head->next); if (inext != ERTS_AINT_NULL) { if (&q->tail.data.marker != (ErtsThrQElement_t *) inext) return ERTS_THR_Q_DIRTY; else { - q->head.head.ptr->next.ptr = (ErtsThrQElement_t *) inext; - q->head.head.ptr = (ErtsThrQElement_t *) inext; - inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc); + head = (ErtsThrQElement_t *) inext; + ErtsThrQDirtySetEl(&q->head.head, head); + inext = erts_atomic_read_acqb(&head->next); if (inext != ERTS_AINT_NULL) return ERTS_THR_Q_DIRTY; } } } - if (q->head.first == q->head.head.ptr) { + if (q->head.first == head) { if (!q->head.used_marker) { erts_aint_t inext; - inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc); + inext = erts_atomic_read_acqb(&head->next); if (inext == ERTS_AINT_NULL) return ERTS_THR_Q_DIRTY; } @@ -553,11 +570,11 @@ enqueue(ErtsThrQ_t *q, void *data, ErtsThrQElement_t *this) #ifndef USE_THREADS ASSERT(data); - this->next.ptr = NULL; + this->next = NULL; this->data.ptr = data; if (q->last) - q->last->next.ptr = this; + q->last->next = this; else { q->first = q->last = this; q->init.notify(q->init.arg); @@ -595,7 +612,7 @@ enqueue(ErtsThrQ_t *q, void *data, ErtsThrQElement_t *this) } } - notify = this == enqueue_managed(q, this, 1); + notify = this == enqueue_managed(q, this); #ifdef ERTS_SMP @@ -638,17 +655,17 @@ erts_thr_q_get_finalize_dequeue_data(ErtsThrQ_t *q, ErtsThrQFinDeQ_t *fdp) ErtsThrQElement_t *e = q->head.deq_fini.start; ErtsThrQElement_t *end = q->head.deq_fini.end; while (e != end) { - ASSERT(q->head.head.ptr != e); + ASSERT(ErtsThrQDirtyReadEl(&q->head.head) != e); ASSERT(q->head.first != e); ASSERT(q->head.unref_end != e); - e = e->next.ptr; + e = ErtsThrQDirtyReadEl(&e->next); } } #endif fdp->start = q->head.deq_fini.start; fdp->end = q->head.deq_fini.end; if (fdp->end) - fdp->end->next.ptr = NULL; + ErtsThrQDirtySetEl(&fdp->end->next, NULL); q->head.deq_fini.start = NULL; q->head.deq_fini.end = NULL; return fdp->start != NULL; @@ -662,7 +679,7 @@ erts_thr_q_append_finalize_dequeue_data(ErtsThrQFinDeQ_t *fdp0, #ifdef USE_THREADS if (fdp1->start) { if (fdp0->end) - fdp0->end->next.ptr = fdp1->start; + ErtsThrQDirtySetEl(&fdp0->end->next, fdp1->start); else fdp0->start = fdp1->start; fdp0->end = fdp1->end; @@ -683,7 +700,7 @@ int erts_thr_q_finalize_dequeue(ErtsThrQFinDeQ_t *state) if (!start) break; tmp = start; - start = start->next.ptr; + start = ErtsThrQDirtyReadEl(&start->next); live = (ErtsThrQLive_t) (UWord) tmp->data.ptr; element_live_free(live, tmp); } @@ -724,7 +741,7 @@ erts_thr_q_dequeue(ErtsThrQ_t *q) return NULL; tmp = q->first; res = tmp->data.ptr; - q->first = tmp->next.ptr; + q->first = tmp->next; if (!q->first) q->last = NULL; @@ -732,24 +749,26 @@ erts_thr_q_dequeue(ErtsThrQ_t *q) return res; #else + ErtsThrQElement_t *head; erts_aint_t inext; void *res; - inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc); + head = ErtsThrQDirtyReadEl(&q->head.head); + inext = erts_atomic_read_acqb(&head->next); if (inext == ERTS_AINT_NULL) return NULL; - q->head.head.ptr->next.ptr = (ErtsThrQElement_t *) inext; - q->head.head.ptr = (ErtsThrQElement_t *) inext; - if (q->head.head.ptr == &q->tail.data.marker) { - inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc); + head = (ErtsThrQElement_t *) inext; + ErtsThrQDirtySetEl(&q->head.head, head); + if (head == &q->tail.data.marker) { + inext = erts_atomic_read_acqb(&head->next); if (inext == ERTS_AINT_NULL) return NULL; - q->head.head.ptr->next.ptr = (ErtsThrQElement_t *) inext; - q->head.head.ptr = (ErtsThrQElement_t *) inext; + head = (ErtsThrQElement_t *) inext; + ErtsThrQDirtySetEl(&q->head.head, head); } - res = q->head.head.ptr->data.ptr; + res = head->data.ptr; #if ERTS_THR_Q_DBG_CHK_DATA - q->head.head.ptr->data.ptr = NULL; + head->data.ptr = NULL; if (!res) erl_exit(ERTS_ABORT_EXIT, "Missing data in dequeue\n"); #endif diff --git a/erts/emulator/beam/erl_thr_queue.h b/erts/emulator/beam/erl_thr_queue.h index edcf2c3823..13af758b3f 100644 --- a/erts/emulator/beam/erl_thr_queue.h +++ b/erts/emulator/beam/erl_thr_queue.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2011. All Rights Reserved. + * Copyright Ericsson AB 2011-2013. 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 @@ -76,13 +76,12 @@ typedef struct { typedef struct ErtsThrQElement_t_ ErtsThrQElement_t; typedef struct ErtsThrQElement_t ErtsThrQPrepEnQ_t; -typedef union { - erts_atomic_t atmc; - ErtsThrQElement_t *ptr; -} ErtsThrQPtr_t; - struct ErtsThrQElement_t_ { - ErtsThrQPtr_t next; +#ifdef USE_THREADS + erts_atomic_t next; +#else + ErtsThrQElement_t *next; +#endif union { erts_atomic_t atmc; void *ptr; @@ -130,7 +129,7 @@ struct ErtsThrQ_t_ { * thread dequeuing. */ struct { - ErtsThrQPtr_t head; + erts_atomic_t head; ErtsThrQLive_t live; ErtsThrQElement_t *first; ErtsThrQElement_t *unref_end; diff --git a/erts/emulator/beam/erl_threads.h b/erts/emulator/beam/erl_threads.h index 1dc3ffeb3c..759c8f4c33 100644 --- a/erts/emulator/beam/erl_threads.h +++ b/erts/emulator/beam/erl_threads.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2001-2012. All Rights Reserved. + * Copyright Ericsson AB 2001-2013. 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 @@ -690,6 +690,19 @@ do { \ } while (0) #endif +ERTS_GLB_INLINE void +erts_dw_atomic_set_dirty(erts_dw_atomic_t *var, erts_dw_aint_t *val); +ERTS_GLB_INLINE void +erts_dw_atomic_read_dirty(erts_dw_atomic_t *var, erts_dw_aint_t *val); +ERTS_GLB_INLINE void +erts_atomic_set_dirty(erts_atomic_t *var, erts_aint_t val); +ERTS_GLB_INLINE erts_aint_t +erts_atomic_read_dirty(erts_atomic_t *var); +ERTS_GLB_INLINE void +erts_atomic32_set_dirty(erts_atomic32_t *var, erts_aint32_t val); +ERTS_GLB_INLINE erts_aint32_t +erts_atomic32_read_dirty(erts_atomic32_t *var); + /* * See "Documentation of atomics and memory barriers" at the top * of this file for info on atomics. @@ -732,6 +745,26 @@ do { \ #define erts_dw_atomic_read_wb ethr_dw_atomic_read_wb #define erts_dw_atomic_cmpxchg_wb ethr_dw_atomic_cmpxchg_wb +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE void +erts_dw_atomic_set_dirty(erts_dw_atomic_t *var, erts_dw_aint_t *val) +{ + ethr_sint_t *sint = ethr_dw_atomic_addr(var); + sint[0] = val->sint[0]; + sint[1] = val->sint[1]; +} + +ERTS_GLB_INLINE void +erts_dw_atomic_read_dirty(erts_dw_atomic_t *var, erts_dw_aint_t *val) +{ + ethr_sint_t *sint = ethr_dw_atomic_addr(var); + val->sint[0] = sint[0]; + val->sint[1] = sint[1]; +} + +#endif + /* Word size atomics */ #define erts_atomic_init_nob ethr_atomic_init @@ -911,6 +944,7 @@ erts_atomic_read_bset_rb(erts_atomic_t *var, #define erts_atomic_cmpxchg_wb ethr_atomic_cmpxchg_wb #if ERTS_GLB_INLINE_INCL_FUNC_DEF + ERTS_GLB_INLINE erts_aint_t erts_atomic_read_bset_wb(erts_atomic_t *var, erts_aint_t mask, @@ -921,6 +955,25 @@ erts_atomic_read_bset_wb(erts_atomic_t *var, ethr_atomic_cmpxchg_wb, var, mask, set); } + +#endif + +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE void +erts_atomic_set_dirty(erts_atomic_t *var, erts_aint_t val) +{ + ethr_sint_t *sint = ethr_atomic_addr(var); + *sint = val; +} + +ERTS_GLB_INLINE erts_aint_t +erts_atomic_read_dirty(erts_atomic_t *var) +{ + ethr_sint_t *sint = ethr_atomic_addr(var); + return *sint; +} + #endif /* 32-bit atomics */ @@ -1102,6 +1155,7 @@ erts_atomic32_read_bset_rb(erts_atomic32_t *var, #define erts_atomic32_cmpxchg_wb ethr_atomic32_cmpxchg_wb #if ERTS_GLB_INLINE_INCL_FUNC_DEF + ERTS_GLB_INLINE erts_aint32_t erts_atomic32_read_bset_wb(erts_atomic32_t *var, erts_aint32_t mask, @@ -1112,10 +1166,29 @@ erts_atomic32_read_bset_wb(erts_atomic32_t *var, ethr_atomic32_cmpxchg_wb, var, mask, set); } + #endif #undef ERTS_ATOMIC_BSET_IMPL__ +#if ERTS_GLB_INLINE_INCL_FUNC_DEF + +ERTS_GLB_INLINE void +erts_atomic32_set_dirty(erts_atomic32_t *var, erts_aint32_t val) +{ + ethr_sint32_t *sint = ethr_atomic32_addr(var); + *sint = val; +} + +ERTS_GLB_INLINE erts_aint32_t +erts_atomic32_read_dirty(erts_atomic32_t *var) +{ + ethr_sint32_t *sint = ethr_atomic32_addr(var); + return *sint; +} + +#endif + #else /* !USE_THREADS */ /* Double word size atomics */ @@ -1155,6 +1228,9 @@ erts_atomic32_read_bset_wb(erts_atomic32_t *var, #define erts_dw_atomic_read_wb erts_no_dw_atomic_read #define erts_dw_atomic_cmpxchg_wb erts_no_dw_atomic_cmpxchg +#define erts_dw_atomic_set_dirty erts_no_dw_atomic_set +#define erts_dw_atomic_read_dirty erts_no_dw_atomic_read + /* Word size atomics */ #define erts_atomic_init_nob erts_no_atomic_set @@ -1262,6 +1338,9 @@ erts_atomic32_read_bset_wb(erts_atomic32_t *var, #define erts_atomic_cmpxchg_wb erts_no_atomic_cmpxchg #define erts_atomic_read_bset_wb erts_no_atomic_read_bset +#define erts_atomic_set_dirty erts_no_atomic_set +#define erts_atomic_read_dirty erts_no_atomic_read + /* 32-bit atomics */ #define erts_atomic32_init_nob erts_no_atomic32_set @@ -1369,6 +1448,9 @@ erts_atomic32_read_bset_wb(erts_atomic32_t *var, #define erts_atomic32_cmpxchg_wb erts_no_atomic32_cmpxchg #define erts_atomic32_read_bset_wb erts_no_atomic32_read_bset +#define erts_atomic32_set_dirty erts_no_atomic32_set +#define erts_atomic32_read_dirty erts_no_atomic32_read + #endif /* !USE_THREADS */ #if ERTS_GLB_INLINE_INCL_FUNC_DEF diff --git a/erts/emulator/beam/erl_unicode.c b/erts/emulator/beam/erl_unicode.c index 80982f3760..ad6f8b993a 100644 --- a/erts/emulator/beam/erl_unicode.c +++ b/erts/emulator/beam/erl_unicode.c @@ -724,7 +724,7 @@ L_Again: /* Restart with sublist, old listend was pushed on stack */ hp = HAlloc(p, 2); obj = CDR(objp); ioterm = CONS(hp, rest_term, obj); - //(*left) = 0; + /* (*left) = 0; */ goto done; } if (rest_term != NIL) { @@ -2747,3 +2747,11 @@ int erts_utf8_to_latin1(byte* dest, const byte* source, int slen) return dp - dest; } +BIF_RETTYPE io_printable_range_0(BIF_ALIST_0) +{ + if (erts_get_printable_characters() == ERL_PRINTABLE_CHARACTERS_UNICODE) { + BIF_RET(am_unicode); + } else { + BIF_RET(am_latin1); + } +} diff --git a/erts/emulator/beam/io.c b/erts/emulator/beam/io.c index 3ea4b24848..a9771de7ad 100644 --- a/erts/emulator/beam/io.c +++ b/erts/emulator/beam/io.c @@ -82,11 +82,11 @@ static void pdl_init(void); #ifdef ERTS_SMP static void driver_monitor_lock_pdl(Port *p); static void driver_monitor_unlock_pdl(Port *p); -#define DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(Port) erts_thr_drvport2port_raw((Port), 1) +#define DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(Port) erts_thr_drvport2port((Port), 1) #define DRV_MONITOR_LOCK_PDL(Port) driver_monitor_lock_pdl(Port) #define DRV_MONITOR_UNLOCK_PDL(Port) driver_monitor_unlock_pdl(Port) #else -#define DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(Port) erts_thr_drvport2port_raw((Port), 0) +#define DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(Port) erts_thr_drvport2port((Port), 0) #define DRV_MONITOR_LOCK_PDL(Port) /* nothing */ #define DRV_MONITOR_UNLOCK_PDL(Port) /* nothing */ #endif @@ -97,12 +97,10 @@ static void driver_monitor_unlock_pdl(Port *p); static ERTS_INLINE ErlIOQueue* drvport2ioq(ErlDrvPort drvport) { - Port *prt = erts_thr_drvport2port_raw(drvport, 0); - erts_aint32_t state = erts_atomic32_read_nob(&prt->state); - if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) + Port *prt = erts_thr_drvport2port(drvport, 0); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return NULL; - else - return &prt->ioq; + return &prt->ioq; } static ERTS_INLINE int @@ -178,6 +176,22 @@ typedef struct line_buf_context { \ dtrace_proc_str((PID), process_str); \ dtrace_port_str((PORT), port_str); + +void +dtrace_drvport_str(ErlDrvPort drvport, char *port_buf) +{ + Port *port = erts_drvport2port(drvport); + + if (port != ERTS_INVALID_ERL_DRV_PORT) + erts_snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<%lu.%lu>", + port_channel_no(port->common.id), + port_number(port->common.id)); + else + erts_snprintf(port_buf, DTRACE_TERM_BUF_SIZE, "#Port<INVALID>", + port_channel_no(port->common.id), + port_number(port->common.id)); +} + #endif static ERTS_INLINE void @@ -398,6 +412,7 @@ static Port *create_port(char *name, #endif if (enop) *enop = 0; + erts_free(ERTS_ALC_T_PORT, prt); return NULL; } @@ -683,7 +698,7 @@ erts_open_driver(erts_driver_t* driver, /* Pointer to driver. */ } #endif fpe_was_unmasked = erts_block_fpe(); - drv_data = (*driver->start)((ErlDrvPort) port, name, opts); + drv_data = (*driver->start)(ERTS_Port2ErlDrvPort(port), name, opts); if (((SWord) drv_data) == -1) error_type = -1; else if (((SWord) drv_data) == -2) { @@ -777,8 +792,8 @@ driver_create_port(ErlDrvPort creator_port_ix, /* Creating port */ if (!erts_get_scheduler_id()) return ERTS_INVALID_ERL_DRV_PORT; - creator_port = erts_drvport2port(creator_port_ix, NULL); - if (!creator_port) + creator_port = erts_drvport2port(creator_port_ix); + if (creator_port == ERTS_INVALID_ERL_DRV_PORT) return ERTS_INVALID_ERL_DRV_PORT; rp = erts_proc_lookup(pid); @@ -849,7 +864,7 @@ driver_create_port(ErlDrvPort creator_port_ix, /* Creating port */ port->drv_data = (UWord) drv_data; - return (ErlDrvPort) port; + return ERTS_Port2ErlDrvPort(port); } #ifdef ERTS_SMP @@ -1185,6 +1200,7 @@ typedef struct { int async; /* Asynchronous operation */ int pre_chk_sched_flags; /* Check sched flags before lock? */ int fpe_was_unmasked; + int reds_left_in; } ErtsTryImmDrvCallState; #define ERTS_INIT_TRY_IMM_DRV_CALL_STATE(C_P, PRT, SFLGS, PTS_FLGS, A, PRT_OP) \ @@ -1199,6 +1215,7 @@ static ERTS_INLINE ErtsTryImmDrvCallResult try_imm_drv_call(ErtsTryImmDrvCallState *sp) { ErtsTryImmDrvCallResult res; + int reds_left_in; erts_aint32_t invalid_state, invalid_sched_flags; Port *prt = sp->port; Process *c_p = sp->c_p; @@ -1232,16 +1249,24 @@ try_imm_drv_call(ErtsTryImmDrvCallState *sp) goto locked_fail; } - if (c_p) { + + if (!c_p) + reds_left_in = CONTEXT_REDS/10; + else { if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS)) trace_virtual_sched(c_p, am_out); if (erts_system_profile_flags.runnable_procs && erts_system_profile_flags.exclusive) profile_runnable_proc(c_p, am_inactive); + reds_left_in = ERTS_BIF_REDS_LEFT(c_p); erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN); } + ASSERT(0 <= reds_left_in && reds_left_in <= CONTEXT_REDS); + sp->reds_left_in = reds_left_in; + prt->reds = CONTEXT_REDS - reds_left_in; + ERTS_SMP_CHK_NO_PROC_LOCKS; if (IS_TRACED_FL(prt, F_TRACE_SCHED_PORTS)) @@ -1262,10 +1287,12 @@ locked_fail: static ERTS_INLINE void finalize_imm_drv_call(ErtsTryImmDrvCallState *sp) { + int reds; Port *prt = sp->port; Process *c_p = sp->c_p; - erts_port_driver_callback_epilogue(prt, NULL); + reds = prt->reds; + reds += erts_port_driver_callback_epilogue(prt, NULL); erts_unblock_fpe(sp->fpe_was_unmasked); @@ -1280,6 +1307,12 @@ finalize_imm_drv_call(ErtsTryImmDrvCallState *sp) if (c_p) { erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN); + if (reds != (CONTEXT_REDS - sp->reds_left_in)) { + int bump_reds = reds - (CONTEXT_REDS - sp->reds_left_in); + ASSERT(bump_reds > 0); + BUMP_REDS(c_p, bump_reds); + } + if (IS_TRACED_FL(c_p, F_TRACE_SCHED_PROCS)) trace_virtual_sched(c_p, am_in); if (erts_system_profile_flags.runnable_procs @@ -3470,7 +3503,7 @@ erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed) { ErtsLink *lnk; Eterm rreason; - erts_aint32_t state; + erts_aint32_t state, set_state_flags; ERTS_SMP_CHK_NO_PROC_LOCKS; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(p)); @@ -3499,9 +3532,12 @@ erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed) if (reason == am_normal && from != ERTS_PORT_GET_CONNECTED(p) && from != p->common.id) return 0; + set_state_flags = ERTS_PORT_SFLG_EXITING; if (send_closed) - erts_atomic32_read_bor_relb(&p->state, - ERTS_PORT_SFLG_SEND_CLOSED); + set_state_flags |= ERTS_PORT_SFLG_SEND_CLOSED; + + state = erts_atomic32_read_bor_mb(&p->state, set_state_flags); + state |= set_state_flags; if (IS_TRACED_FL(p, F_TRACE_PORTS)) { trace_port(p, am_closed, reason); @@ -3509,17 +3545,11 @@ erts_deliver_port_exit(Port *p, Eterm from, Eterm reason, int send_closed) erts_trace_check_exiting(p->common.id); - /* - * Setting the port to not busy here, frees the list of pending - * processes and makes them runnable. - */ - set_busy_port((ErlDrvPort) p, 0); + set_busy_port(ERTS_Port2ErlDrvPort(p), 0); if (p->common.u.alive.reg != NULL) (void) erts_unregister_name(NULL, 0, p, p->common.u.alive.reg->name); - state = erts_atomic32_read_bor_relb(&p->state, ERTS_PORT_SFLG_EXITING); - { SweepContext sc = {p->common.id, rreason}; lnk = ERTS_P_LINKS(p); @@ -4759,8 +4789,8 @@ set_busy_port(ErlDrvPort dprt, int on) ERTS_SMP_CHK_NO_PROC_LOCKS; - prt = erts_drvport2port_raw(dprt); - if (!prt) + prt = erts_drvport2port(dprt); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return; if (on) { @@ -4859,8 +4889,8 @@ erts_port_resume_procs(Port *prt) void set_port_control_flags(ErlDrvPort port_num, int flags) { - Port *prt = erts_drvport2port_raw(port_num); - if (prt) + Port *prt = erts_drvport2port(port_num); + if (prt != ERTS_INVALID_ERL_DRV_PORT) prt->control_flags = flags; } @@ -4870,8 +4900,8 @@ int get_port_flags(ErlDrvPort ix) Port *prt; erts_aint32_t state; - prt = erts_drvport2port(ix, &state); - if (!prt) + prt = erts_drvport2port_state(ix, &state); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return 0; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); @@ -4960,7 +4990,7 @@ erts_stale_drv_select(Eterm port, int deselect) { char *type; - ErlDrvPort drv_port = (ErlDrvPort) erts_port_lookup_raw(port); + ErlDrvPort drv_port = ERTS_Port2ErlDrvPort(erts_port_lookup_raw(port)); ErtsPortNames *pnp = erts_get_port_names(port); erts_dsprintf_buf_t *dsbufp; @@ -5082,7 +5112,6 @@ ErlDrvTermData driver_mk_term_nil(void) void driver_report_exit(ErlDrvPort ix, int status) { - Port* prt = erts_drvport2port(ix, NULL); Eterm* hp; Eterm tuple; Process *rp; @@ -5091,6 +5120,10 @@ void driver_report_exit(ErlDrvPort ix, int status) ErlOffHeap *ohp; ErtsProcLocks rp_locks = 0; int scheduler = erts_get_scheduler_id() != 0; + Port* prt = erts_drvport2port(ix); + + if (prt == ERTS_INVALID_ERL_DRV_PORT) + return; ERTS_SMP_CHK_NO_PROC_LOCKS; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); @@ -5687,8 +5720,18 @@ deliver_term_check_port(ErlDrvTermData port_id, Eterm *connected_p) #ifdef ERTS_SMP ErtsThrPrgrDelayHandle dhndl = erts_thr_progress_unmanaged_delay(); #endif + erts_aint32_t state; Port *prt = erts_port_lookup_raw((Eterm) port_id); - erts_aint32_t state = erts_atomic32_read_nob(&prt->state); + if (!prt) + return -1; + state = erts_atomic32_read_nob(&prt->state); + if (state & (ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP + | ERTS_PORT_SFLG_CLOSING)) { + if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) + return -1; + else + return 0; + } if (connected_p) { #ifdef ERTS_SMP if (dhndl != ERTS_THR_PRGR_DHANDLE_MANAGED) @@ -5705,9 +5748,7 @@ deliver_term_check_port(ErlDrvTermData port_id, Eterm *connected_p) ERTS_SMP_LC_ASSERT(dhndl == ERTS_THR_PRGR_DHANDLE_MANAGED ? erts_lc_is_port_locked(prt) : !erts_lc_is_port_locked(prt)); - return ((state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) - ? -1 - : ((state & ERTS_PORT_SFLG_CLOSING) ? 0 : 1)); + return 1; } int erl_drv_output_term(ErlDrvTermData port_id, ErlDrvTermData* data, int len) @@ -5733,14 +5774,12 @@ driver_output_term(ErlDrvPort drvport, ErlDrvTermData* data, int len) ERTS_SMP_CHK_NO_PROC_LOCKS; /* NOTE! It *not* safe to access 'drvport' from unmanaged threads. */ - prt = erts_drvport2port(drvport, &state); - if (!prt) + prt = erts_drvport2port_state(drvport, &state); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; /* invalid (dead) */ ERTS_SMP_CHK_NO_PROC_LOCKS; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); - if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) - return -1; - else if (state & ERTS_PORT_SFLG_CLOSING) + if (state & ERTS_PORT_SFLG_CLOSING) return 0; return driver_deliver_term(ERTS_PORT_GET_CONNECTED(prt), data, len); @@ -5780,13 +5819,11 @@ driver_send_term(ErlDrvPort drvport, #endif { erts_aint32_t state; - Port* prt = erts_drvport2port(drvport, &state); - if (!prt) + Port* prt = erts_drvport2port_state(drvport, &state); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; /* invalid (dead) */ ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); - if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) - return -1; - else if (state & ERTS_PORT_SFLG_CLOSING) + if (state & ERTS_PORT_SFLG_CLOSING) return 0; } return driver_deliver_term(to, data, len); @@ -5802,11 +5839,11 @@ int driver_output_binary(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen, ErlDrvBinary* bin, ErlDrvSizeT offs, ErlDrvSizeT len) { erts_aint32_t state; - Port* prt = erts_drvport2port(ix, &state); + Port* prt = erts_drvport2port_state(ix, &state); ERTS_SMP_CHK_NO_PROC_LOCKS; - if (prt == NULL) + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); if (state & ERTS_PORT_SFLG_CLOSING) @@ -5837,15 +5874,14 @@ int driver_output2(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen, char* buf, ErlDrvSizeT len) { erts_aint32_t state; - Port* prt = erts_drvport2port(ix, &state); + Port* prt = erts_drvport2port_state(ix, &state); ERTS_SMP_CHK_NO_PROC_LOCKS; - if (prt == NULL) + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); - if (state & ERTS_PORT_SFLG_CLOSING) return 0; @@ -5902,8 +5938,8 @@ int driver_outputv(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen, if (hlen < 0) hlen = 0; - prt = erts_drvport2port(ix, &state); - if (prt == NULL) + prt = erts_drvport2port_state(ix, &state); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); @@ -5924,7 +5960,7 @@ int driver_outputv(ErlDrvPort ix, char* hbuf, ErlDrvSizeT hlen, binv++; n--; } else { - iov->iov_base += skip; + iov->iov_base = ((char *)(iov->iov_base)) + skip; iov->iov_len -= skip; skip = 0; } @@ -6179,8 +6215,8 @@ ErlDrvPDL driver_pdl_create(ErlDrvPort dp) { ErlDrvPDL pdl; - Port *pp = erts_drvport2port(dp, NULL); - if (!pp || pp->port_data_lock) + Port *pp = erts_drvport2port(dp); + if (pp == ERTS_INVALID_ERL_DRV_PORT || pp->port_data_lock) return NULL; pdl = erts_alloc(ERTS_ALC_T_PORT_DATA_LOCK, sizeof(struct erl_drv_port_data_lock)); @@ -6369,7 +6405,7 @@ int driver_enqv(ErlDrvPort ix, ErlIOVec* vec, ErlDrvSizeT skip) n--; } else { - iov->iov_base += skip; + iov->iov_base = ((char *)(iov->iov_base)) + skip; iov->iov_len -= skip; skip = 0; } @@ -6434,7 +6470,7 @@ int driver_pushqv(ErlDrvPort ix, ErlIOVec* vec, ErlDrvSizeT skip) n--; } else { - iov->iov_base += skip; + iov->iov_base = ((char *)(iov->iov_base)) + skip; iov->iov_len -= skip; skip = 0; } @@ -6493,7 +6529,7 @@ ErlDrvSizeT driver_deq(ErlDrvPort ix, ErlDrvSizeT size) q->v_head++; } else { - q->v_head->iov_base += size; + q->v_head->iov_base = ((char *)(q->v_head->iov_base)) + size; q->v_head->iov_len -= size; size = 0; } @@ -6638,11 +6674,11 @@ drv_cancel_timer(Port *prt) int driver_set_timer(ErlDrvPort ix, unsigned long t) { - Port* prt = erts_drvport2port(ix, NULL); + Port* prt = erts_drvport2port(ix); ERTS_SMP_CHK_NO_PROC_LOCKS; - if (prt == NULL) + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; if (prt->drv_ptr->timeout == NULL) @@ -6665,8 +6701,8 @@ int driver_set_timer(ErlDrvPort ix, unsigned long t) int driver_cancel_timer(ErlDrvPort ix) { - Port* prt = erts_drvport2port(ix, NULL); - if (prt == NULL) + Port* prt = erts_drvport2port(ix); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); drv_cancel_timer(prt); @@ -6677,11 +6713,11 @@ int driver_cancel_timer(ErlDrvPort ix) int driver_read_timer(ErlDrvPort ix, unsigned long* t) { - Port* prt = erts_drvport2port(ix, NULL); + Port* prt = erts_drvport2port(ix); ERTS_SMP_CHK_NO_PROC_LOCKS; - if (prt == NULL) + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); #ifdef ERTS_SMP @@ -6757,19 +6793,13 @@ int driver_monitor_process(ErlDrvPort drvport, { Port *prt; int ret; - erts_aint32_t state; #if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)) ErtsSchedulerData *sched = erts_get_scheduler_data(); #endif prt = DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(drvport); - - state = erts_atomic32_read_nob(&prt->state); - - if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) { - DRV_MONITOR_UNLOCK_PDL(prt); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; - } /* Now (in SMP) we should have either the port lock (if we have a scheduler) or the port data lock (if we're a driver thread) */ @@ -6836,19 +6866,13 @@ int driver_demonitor_process(ErlDrvPort drvport, { Port *prt; int ret; - erts_aint32_t state; #if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)) ErtsSchedulerData *sched = erts_get_scheduler_data(); #endif prt = DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(drvport); - - state = erts_atomic32_read_nob(&prt->state); - - if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) { - DRV_MONITOR_UNLOCK_PDL(prt); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; - } /* Now we should have either the port lock (if we have a scheduler) or the port data lock (if we're a driver thread) */ @@ -6897,18 +6921,13 @@ ErlDrvTermData driver_get_monitored_process(ErlDrvPort drvport, { Port *prt; ErlDrvTermData ret; - erts_aint32_t state; #if !HEAP_ON_C_STACK || (defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)) ErtsSchedulerData *sched = erts_get_scheduler_data(); #endif prt = DRV_MONITOR_LOOKUP_PORT_LOCK_PDL(drvport); - - state = erts_atomic32_read_nob(&prt->state); - if (state & ERTS_PORT_SFLGS_INVALID_DRIVER_LOOKUP) { - DRV_MONITOR_UNLOCK_PDL(prt); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return driver_term_nil; - } /* Now we should have either the port lock (if we have a scheduler) or the port data lock (if we're a driver thread) */ @@ -6981,11 +7000,11 @@ static int driver_failure_term(ErlDrvPort ix, Eterm term, int eof) { erts_aint32_t state; - Port* prt = erts_drvport2port(ix, &state); + Port* prt = erts_drvport2port_state(ix, &state); ERTS_SMP_CHK_NO_PROC_LOCKS; - if (prt == NULL) + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); if (eof) @@ -7014,14 +7033,14 @@ driver_failure_term(ErlDrvPort ix, Eterm term, int eof) */ int driver_exit(ErlDrvPort ix, int err) { - Port* prt = erts_drvport2port(ix, NULL); + Port* prt = erts_drvport2port(ix); Process* rp; ErtsLink *lnk, *rlnk = NULL; Eterm connected; ERTS_SMP_CHK_NO_PROC_LOCKS; - if (prt == NULL) + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; connected = ERTS_PORT_GET_CONNECTED(prt); @@ -7095,16 +7114,18 @@ ErlDrvTermData driver_mk_atom(char* string) ErlDrvTermData driver_mk_port(ErlDrvPort ix) { - Port* prt = erts_drvport2port(ix, NULL); + Port* prt = erts_drvport2port(ix); + if (prt == ERTS_INVALID_ERL_DRV_PORT) + return (ErlDrvTermData) NIL; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); return (ErlDrvTermData) prt->common.id; } ErlDrvTermData driver_connected(ErlDrvPort ix) { - Port* prt = erts_drvport2port(ix, NULL); + Port* prt = erts_drvport2port(ix); ERTS_SMP_CHK_NO_PROC_LOCKS; - if (prt == NULL) + if (prt == ERTS_INVALID_ERL_DRV_PORT) return NIL; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); return ERTS_PORT_GET_CONNECTED(prt); @@ -7112,9 +7133,9 @@ ErlDrvTermData driver_connected(ErlDrvPort ix) ErlDrvTermData driver_caller(ErlDrvPort ix) { - Port* prt = erts_drvport2port(ix, NULL); + Port* prt = erts_drvport2port(ix); ERTS_SMP_CHK_NO_PROC_LOCKS; - if (prt == NULL) + if (prt == ERTS_INVALID_ERL_DRV_PORT) return NIL; ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); return prt->caller; @@ -7122,17 +7143,15 @@ ErlDrvTermData driver_caller(ErlDrvPort ix) int driver_lock_driver(ErlDrvPort ix) { - Port* prt = erts_drvport2port(ix, NULL); + Port* prt = erts_drvport2port(ix); DE_Handle* dh; ERTS_SMP_CHK_NO_PROC_LOCKS; - erts_smp_rwmtx_rwlock(&erts_driver_list_lock); - - if (prt == NULL) { - erts_smp_rwmtx_rwunlock(&erts_driver_list_lock); + if (prt == ERTS_INVALID_ERL_DRV_PORT) return -1; - } + + erts_smp_rwmtx_rwlock(&erts_driver_list_lock); ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); if ((dh = (DE_Handle*)prt->drv_ptr->handle ) == NULL) { @@ -7327,7 +7346,7 @@ no_event_callback(ErlDrvData drv_data, ErlDrvEvent event, ErlDrvEventData event_ { Port *prt = get_current_port(); report_missing_drv_callback(prt, "Event", "event()"); - driver_event((ErlDrvPort) prt, event, NULL); + driver_event(ERTS_Port2ErlDrvPort(prt), event, NULL); } static void @@ -7335,7 +7354,7 @@ no_ready_input_callback(ErlDrvData drv_data, ErlDrvEvent event) { Port *prt = get_current_port(); report_missing_drv_callback(prt, "Input", "ready_input()"); - driver_select((ErlDrvPort) prt, event, + driver_select(ERTS_Port2ErlDrvPort(prt), event, (ERL_DRV_READ | ERL_DRV_USE_NO_CALLBACK), 0); } @@ -7344,7 +7363,7 @@ no_ready_output_callback(ErlDrvData drv_data, ErlDrvEvent event) { Port *prt = get_current_port(); report_missing_drv_callback(prt, "Output", "ready_output()"); - driver_select((ErlDrvPort) prt, event, + driver_select(ERTS_Port2ErlDrvPort(prt), event, (ERL_DRV_WRITE | ERL_DRV_USE_NO_CALLBACK), 0); } diff --git a/erts/emulator/beam/ops.tab b/erts/emulator/beam/ops.tab index 8a79b4910e..1e5ae46bfa 100644 --- a/erts/emulator/beam/ops.tab +++ b/erts/emulator/beam/ops.tab @@ -1,7 +1,7 @@ # # %CopyrightBegin% # -# Copyright Ericsson AB 1997-2012. All Rights Reserved. +# Copyright Ericsson AB 1997-2013. 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 diff --git a/erts/emulator/beam/packet_parser.c b/erts/emulator/beam/packet_parser.c index 7c9b2d444a..db0e78b1a7 100644 --- a/erts/emulator/beam/packet_parser.c +++ b/erts/emulator/beam/packet_parser.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2008-2011. All Rights Reserved. + * Copyright Ericsson AB 2008-2013. 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 diff --git a/erts/emulator/beam/sys.h b/erts/emulator/beam/sys.h index 9416a91480..05bff430e3 100644 --- a/erts/emulator/beam/sys.h +++ b/erts/emulator/beam/sys.h @@ -1040,11 +1040,24 @@ char* win32_errorstr(int); #define ERL_FILENAME_WARNING_IGNORE (1) #define ERL_FILENAME_WARNING_ERROR (2) +/*********************************************************************** + * The user can request a range of character that he/she consider + * printable. Currently this can be either latin1 or unicode, but + * in the future a set of ranges, or languages, could be specified. + ***********************************************************************/ +#define ERL_PRINTABLE_CHARACTERS_LATIN1 (0) +#define ERL_PRINTABLE_CHARACTERS_UNICODE (1) + int erts_get_native_filename_encoding(void); /* The set function is only to be used by erl_init! */ void erts_set_user_requested_filename_encoding(int encoding, int warning); int erts_get_user_requested_filename_encoding(void); int erts_get_filename_warning_type(void); +/* This function is called from erl_init. The setting is read by BIF's + in io/io_lib. Setting is not atomic. */ +void erts_set_printable_characters(int range); +/* Get the setting (ERL_PRINTABLE_CHARACTERS_{LATIN1|UNICODE} */ +int erts_get_printable_characters(void); void erts_init_sys_common_misc(void); diff --git a/erts/emulator/beam/utils.c b/erts/emulator/beam/utils.c index a8f15fdc38..d5d97d748a 100644 --- a/erts/emulator/beam/utils.c +++ b/erts/emulator/beam/utils.c @@ -2713,25 +2713,26 @@ tailrecur_ne: case SMALL_FLOAT: GET_DOUBLE(bw, f2); if (f2.fd < MAX_LOSSLESS_FLOAT && f2.fd > MIN_LOSSLESS_FLOAT) { - // Float is within the no loss limit + /* Float is within the no loss limit */ f1.fd = signed_val(aw); j = float_comp(f1.fd, f2.fd); #if ERTS_SIZEOF_ETERM == 8 } else if (f2.fd > (double) (MAX_SMALL + 1)) { - // Float is a positive bignum, i.e. bigger + /* Float is a positive bignum, i.e. bigger */ j = -1; } else if (f2.fd < (double) (MIN_SMALL - 1)) { - // Float is a negative bignum, i.e. smaller + /* Float is a negative bignum, i.e. smaller */ j = 1; - } else { // Float is a Sint but less precise + } else { + /* Float is a Sint but less precise */ j = signed_val(aw) - (Sint) f2.fd; } #else } else { - // If float is positive it is bigger than small + /* If float is positive it is bigger than small */ j = (f2.fd > 0.0) ? -1 : 1; } -#endif // ERTS_SIZEOF_ETERM == 8 +#endif /* ERTS_SIZEOF_ETERM == 8 */ break; case FLOAT_BIG: { @@ -2743,18 +2744,18 @@ tailrecur_ne: GET_DOUBLE(bw, f2); if ((f2.fd < (double) (MAX_SMALL + 1)) && (f2.fd > (double) (MIN_SMALL - 1))) { - // Float is a Sint + /* Float is a Sint */ j = big_sign(aw) ? -1 : 1; } else if (big_arity(aw) > BIG_ARITY_FLOAT_MAX || pow(2.0,(big_arity(aw)-1)*D_EXP) > fabs(f2.fd)) { - // If bignum size shows that it is bigger than the abs float + /* If bignum size shows that it is bigger than the abs float */ j = big_sign(aw) ? -1 : 1; } else if (big_arity(aw) < BIG_ARITY_FLOAT_MAX && (pow(2.0,(big_arity(aw))*D_EXP)-1.0) < fabs(f2.fd)) { - // If bignum size shows that it is smaller than the abs float + /* If bignum size shows that it is smaller than the abs float */ j = f2.fd < 0 ? 1 : -1; } else if (f2.fd < MAX_LOSSLESS_FLOAT && f2.fd > MIN_LOSSLESS_FLOAT) { - // Float is within the no loss limit + /* Float is within the no loss limit */ if (big_to_double(aw, &f1.fd) < 0) { j = big_sign(aw) ? -1 : 1; } else { @@ -2771,25 +2772,26 @@ tailrecur_ne: case FLOAT_SMALL: GET_DOUBLE(aw, f1); if (f1.fd < MAX_LOSSLESS_FLOAT && f1.fd > MIN_LOSSLESS_FLOAT) { - // Float is within the no loss limit + /* Float is within the no loss limit */ f2.fd = signed_val(bw); j = float_comp(f1.fd, f2.fd); #if ERTS_SIZEOF_ETERM == 8 } else if (f1.fd > (double) (MAX_SMALL + 1)) { - // Float is a positive bignum, i.e. bigger + /* Float is a positive bignum, i.e. bigger */ j = 1; } else if (f1.fd < (double) (MIN_SMALL - 1)) { - // Float is a negative bignum, i.e. smaller + /* Float is a negative bignum, i.e. smaller */ j = -1; - } else { // Float is a Sint but less precise it + } else { + /* Float is a Sint but less precise it */ j = (Sint) f1.fd - signed_val(bw); } #else } else { - // If float is positive it is bigger than small + /* If float is positive it is bigger than small */ j = (f1.fd > 0.0) ? 1 : -1; } -#endif // ERTS_SIZEOF_ETERM == 8 +#endif /* ERTS_SIZEOF_ETERM == 8 */ break; default: j = b_tag - a_tag; diff --git a/erts/emulator/drivers/common/efile_drv.c b/erts/emulator/drivers/common/efile_drv.c index 2279fec72a..a2ef0db83c 100644 --- a/erts/emulator/drivers/common/efile_drv.c +++ b/erts/emulator/drivers/common/efile_drv.c @@ -1149,7 +1149,7 @@ static void invoke_read_line(void *data) { struct t_data *d = (struct t_data *) data; int status; - size_t read_size; + size_t read_size = 0; int local_loop = (d->again == 0); DTRACE_INVOKE_SETUP(FILE_READ_LINE); @@ -1160,7 +1160,14 @@ static void invoke_read_line(void *data) /* Need more place */ ErlDrvSizeT need = (d->c.read_line.read_size >= DEFAULT_LINEBUF_SIZE) ? d->c.read_line.read_size + DEFAULT_LINEBUF_SIZE : DEFAULT_LINEBUF_SIZE; - ErlDrvBinary *newbin = driver_alloc_binary(need); + ErlDrvBinary *newbin; +#if !ALWAYS_READ_LINE_AHEAD + /* Use read_ahead size if need does not exceed it */ + if (need < (d->c.read_line.binp)->orig_size && + d->c.read_line.read_ahead) + need = (d->c.read_line.binp)->orig_size; +#endif + newbin = driver_alloc_binary(need); if (newbin == NULL) { d->result_ok = 0; d->errInfo.posix_errno = ENOMEM; @@ -1339,7 +1346,7 @@ static void invoke_preadv(void *data) = efile_pread(&d->errInfo, (int) d->fd, c->offsets[c->cnt] + c->size, - ev->iov[1 + c->cnt].iov_base + c->size, + ((char *)ev->iov[1 + c->cnt].iov_base) + c->size, read_size, &bytes_read))) { bytes_read_so_far += bytes_read; @@ -1634,7 +1641,7 @@ static void invoke_pwritev(void *data) { - c->free_size; } d->result_ok = efile_pwrite(&d->errInfo, (int) d->fd, - iov[iovcnt].iov_base + p, + (char *)(iov[iovcnt].iov_base) + p, write_size, c->specs[c->cnt].offset); if (! d->result_ok) { @@ -2552,7 +2559,7 @@ file_async_ready(ErlDrvData e, ErlDrvThreadData data) reply_Sint64(desc, d->c.sendfile.written); desc->sendfile_state = not_sending; free_sendfile(data); - } else if (d->result_ok == 1) { // If we are using select to send the rest of the data + } else if (d->result_ok == 1) { /* If we are using select to send the rest of the data */ desc->sendfile_state = sending; desc->d = d; driver_select(desc->port, (ErlDrvEvent)(long)d->c.sendfile.out_fd, @@ -3806,7 +3813,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { res_ev->iov[0].iov_base = res_ev->binv[0]->orig_bytes; /* Fill in the number of buffers in the header */ put_int32(0, res_ev->iov[0].iov_base); - put_int32(n, res_ev->iov[0].iov_base+4); + put_int32(n, (char *)(res_ev->iov[0].iov_base) + 4); /**/ res_ev->size = res_ev->iov[0].iov_len; if (n == 0) { @@ -4107,7 +4114,7 @@ file_outputv(ErlDrvData e, ErlIOVec *ev) { } if (hd_len != 0 || tl_len != 0 || flags != 0) { - // We do not allow header, trailers and/or flags right now + /* We do not allow header, trailers and/or flags right now */ reply_posix_error(desc, EINVAL); goto done; } diff --git a/erts/emulator/drivers/common/erl_efile.h b/erts/emulator/drivers/common/erl_efile.h index b29b4f971c..bd85e43b8c 100644 --- a/erts/emulator/drivers/common/erl_efile.h +++ b/erts/emulator/drivers/common/erl_efile.h @@ -67,7 +67,7 @@ #define FILENAMES_16BIT 1 #endif -// We use sendfilev if it exist on solaris +/* We use sendfilev if it exist on solaris */ #if !defined(HAVE_SENDFILE) && defined(HAVE_SENDFILEV) #define HAVE_SENDFILE #endif @@ -88,20 +88,6 @@ typedef struct _Efile_error { } Efile_error; /* - * This structure contains date and time. - */ - -//typedef struct _Efile_time { -// unsigned year; /* (4 digits). */ -// unsigned month; /* (1..12). */ -// unsigned day; /* (1..31). */ -// unsigned hour; /* (0..23). */ -// unsigned minute; /* (0..59). */ -// unsigned second; /* (0..59). */ -//} Efile_time; - - -/* * Describes what is returned by file:file_info/1. */ diff --git a/erts/emulator/drivers/common/inet_drv.c b/erts/emulator/drivers/common/inet_drv.c index f0c22e9ebe..2451f41a82 100644 --- a/erts/emulator/drivers/common/inet_drv.c +++ b/erts/emulator/drivers/common/inet_drv.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1997-2012. All Rights Reserved. + * Copyright Ericsson AB 1997-2013. 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 @@ -3854,8 +3854,10 @@ static void desc_close(inet_descriptor* desc) desc->forced_events = 0; desc->send_would_block = 0; #endif - // We should close the fd here, but the other driver might still - // be selecting on it. + /* + * We should close the fd here, but the other driver might still + * be selecting on it. + */ if (!desc->is_ignored) driver_select(desc->port,(ErlDrvEvent)(long)desc->event, ERL_DRV_USE, 0); @@ -7834,7 +7836,7 @@ static ErlDrvSSizeT inet_ctl(inet_descriptor* desc, int cmd, char* buf, if (!IS_CONNECTED(desc)) return ctl_error(ENOTCONN, rbuf, rsize); - if (!desc->stype == SOCK_STREAM) + if (desc->stype != SOCK_STREAM) return ctl_error(EINVAL, rbuf, rsize); if (*buf == 1 && !desc->is_ignored) { @@ -8816,7 +8818,7 @@ static int tcp_recv_error(tcp_descriptor* desc, int err) if (desc->inet.exitf) driver_exit(desc->inet.port, err); else - desc_close(INETP(desc)); + desc_close_read(INETP(desc)); } return -1; } diff --git a/erts/emulator/drivers/common/zlib_drv.c b/erts/emulator/drivers/common/zlib_drv.c index 60394b610b..89b7be14f2 100644 --- a/erts/emulator/drivers/common/zlib_drv.c +++ b/erts/emulator/drivers/common/zlib_drv.c @@ -119,7 +119,7 @@ static int zlib_deflate(ZLibData* d, int flush); #if defined(__WIN32__) static int i32(char* buf) #else -static inline int i32(char* buf) +static __inline__ int i32(char* buf) #endif { return (int) ( diff --git a/erts/emulator/drivers/unix/unix_efile.c b/erts/emulator/drivers/unix/unix_efile.c index 558651fff9..2bd5177be1 100644 --- a/erts/emulator/drivers/unix/unix_efile.c +++ b/erts/emulator/drivers/unix/unix_efile.c @@ -629,7 +629,7 @@ efile_writev(Efile_error* errInfo, /* Where to return error codes */ if (w < iov[cnt].iov_len) { /* Adjust the buffer for next write */ iov[cnt].iov_len -= w; - iov[cnt].iov_base += w; + iov[cnt].iov_base = ((char *)iov[cnt].iov_base) + w; w = 0; break; } else { diff --git a/erts/emulator/drivers/win32/win_efile.c b/erts/emulator/drivers/win32/win_efile.c index f2b0c8a843..1059fa5c3a 100644 --- a/erts/emulator/drivers/win32/win_efile.c +++ b/erts/emulator/drivers/win32/win_efile.c @@ -1159,8 +1159,11 @@ char* buf; /* Buffer to read into. */ size_t count; /* Number of bytes to read. */ size_t* pBytesRead; /* Where to return number of bytes read. */ { - if (!ReadFile((HANDLE) fd, buf, count, (DWORD *) pBytesRead, NULL)) + DWORD nbytes = 0; + if (!ReadFile((HANDLE) fd, buf, count, &nbytes, NULL)) return set_error(errInfo); + + *pBytesRead = nbytes; return 1; } diff --git a/erts/emulator/hipe/hipe_bif0.c b/erts/emulator/hipe/hipe_bif0.c index 1562748f2d..fa99c817f0 100644 --- a/erts/emulator/hipe/hipe_bif0.c +++ b/erts/emulator/hipe/hipe_bif0.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2001-2012. All Rights Reserved. + * Copyright Ericsson AB 2001-2013. 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 @@ -1791,7 +1791,7 @@ BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1) if (BIF_ARG_1 == am_all) { hipe_purge_all_refs(); - BIF_RET(NIL); + BIF_RET(am_ok); } if (!term_to_mfa(BIF_ARG_1, &mfa)) @@ -1828,7 +1828,7 @@ BIF_RETTYPE hipe_bifs_remove_refs_from_1(BIF_ALIST_1) caller_mfa->refers_to = NULL; } hipe_mfa_info_table_unlock(); - BIF_RET(NIL); + BIF_RET(am_ok); } diff --git a/erts/emulator/hipe/hipe_native_bif.c b/erts/emulator/hipe/hipe_native_bif.c index 3be821f8f7..1f76268934 100644 --- a/erts/emulator/hipe/hipe_native_bif.c +++ b/erts/emulator/hipe/hipe_native_bif.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2001-2011. All Rights Reserved. + * Copyright Ericsson AB 2001-2013. 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 @@ -238,7 +238,7 @@ void hipe_handle_exception(Process *c_p) if (c_p->mbuf) { erts_printf("%s line %u: p==%p, p->mbuf==%p\n", __FUNCTION__, __LINE__, c_p, c_p->mbuf); - //erts_garbage_collect(c_p, 0, NULL, 0); + /* erts_garbage_collect(c_p, 0, NULL, 0); */ } /* @@ -270,7 +270,7 @@ void hipe_handle_exception(Process *c_p) c_p->def_arg_reg[0] = exception_tag[GET_EXC_CLASS(c_p->freason)]; if (c_p->mbuf) { - //erts_printf("%s line %u: p==%p, p->mbuf==%p, p->lastbif==%p\n", __FUNCTION__, __LINE__, c_p, c_p->mbuf, c_p->hipe.lastbif); + /* erts_printf("%s line %u: p==%p, p->mbuf==%p, p->lastbif==%p\n", __FUNCTION__, __LINE__, c_p, c_p->mbuf, c_p->hipe.lastbif); */ erts_garbage_collect(c_p, 0, NULL, 0); } @@ -503,9 +503,7 @@ static int validate_unicode(Eterm arg) { if (is_not_small(arg) || arg > make_small(0x10FFFFUL) || - (make_small(0xD800UL) <= arg && arg <= make_small(0xDFFFUL)) || - arg == make_small(0xFFFEUL) || - arg == make_small(0xFFFFUL)) + (make_small(0xD800UL) <= arg && arg <= make_small(0xDFFFUL))) return 0; return 1; } diff --git a/erts/emulator/hipe/hipe_x86_gc.h b/erts/emulator/hipe/hipe_x86_gc.h index ccb0d2ffb8..ac6b4f70bb 100644 --- a/erts/emulator/hipe/hipe_x86_gc.h +++ b/erts/emulator/hipe/hipe_x86_gc.h @@ -25,7 +25,7 @@ #include "hipe_x86_asm.h" /* for NR_ARG_REGS */ /* uncomment to simulate & test what the initial PowerPC port will do */ -//#define SKIP_YOUNGEST_FRAME +/* #define SKIP_YOUNGEST_FRAME */ struct nstack_walk_state { #ifdef SKIP_YOUNGEST_FRAME diff --git a/erts/emulator/pcre/pcre_exec.c b/erts/emulator/pcre/pcre_exec.c index 3fe13ca32e..26cb219ef1 100644 --- a/erts/emulator/pcre/pcre_exec.c +++ b/erts/emulator/pcre/pcre_exec.c @@ -36,7 +36,7 @@ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ----------------------------------------------------------------------------- */ -//#define ERLANG_DEBUG 1 +/* #define ERLANG_DEBUG 1 */ /* This module contains erts_pcre_exec(), the externally visible function that does pattern matching using an NFA algorithm, trying to mimic Perl as closely as diff --git a/erts/emulator/sys/common/erl_check_io.c b/erts/emulator/sys/common/erl_check_io.c index 474408ae7c..853dd90c34 100644 --- a/erts/emulator/sys/common/erl_check_io.c +++ b/erts/emulator/sys/common/erl_check_io.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2006-2012. All Rights Reserved. + * Copyright Ericsson AB 2006-2013. 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 @@ -481,6 +481,7 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix, int on) { void (*stop_select_fn)(ErlDrvEvent, void*) = NULL; + Port *prt = erts_drvport2port(ix); Eterm id = erts_drvport2id(ix); ErtsSysFdType fd = (ErtsSysFdType) e; ErtsPollEvents ctl_events = (ErtsPollEvents) 0; @@ -491,9 +492,11 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix, #ifdef USE_VM_PROBES DTRACE_CHARBUF(name, 64); #endif - - ERTS_SMP_LC_ASSERT(erts_drvport2port(ix, NULL) - && erts_lc_is_port_locked(erts_drvport2port(ix, NULL))); + + if (prt == ERTS_INVALID_ERL_DRV_PORT) + return -1; + + ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); #ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS if ((unsigned)fd >= (unsigned)erts_smp_atomic_read_nob(&drv_ev_state_len)) { @@ -519,9 +522,9 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix, if (!on && (mode&ERL_DRV_USE_NO_CALLBACK) == ERL_DRV_USE) { if (IS_FD_UNKNOWN(state)) { /* fast track to stop_select callback */ - stop_select_fn = erts_drvport2port(ix, NULL)->drv_ptr->stop_select; + stop_select_fn = prt->drv_ptr->stop_select; #ifdef USE_VM_PROBES - strncpy(name, erts_drvport2port(ix, NULL)->drv_ptr->name, sizeof(name)-1); + strncpy(name, prt->drv_ptr->name, sizeof(name)-1); name[sizeof(name)-1] = '\0'; #endif ret = 0; @@ -654,14 +657,14 @@ ERTS_CIO_EXPORT(driver_select)(ErlDrvPort ix, } } if ((mode & ERL_DRV_USE_NO_CALLBACK) == ERL_DRV_USE) { - erts_driver_t* drv_ptr = erts_drvport2port(ix, NULL)->drv_ptr; + erts_driver_t* drv_ptr = prt->drv_ptr; ASSERT(new_events==0); if (state->remove_cnt == 0 || !wake_poller) { /* Safe to close fd now as it is not in pollset or there was no need to eject fd (kernel poll) */ stop_select_fn = drv_ptr->stop_select; #ifdef USE_VM_PROBES - strncpy(name, erts_drvport2port(ix, NULL)->drv_ptr->name, sizeof(name)-1); + strncpy(name, prt->drv_ptr->name, sizeof(name)-1); name[sizeof(name)-1] = '\0'; #endif } @@ -712,9 +715,12 @@ ERTS_CIO_EXPORT(driver_event)(ErlDrvPort ix, ErtsDrvEventState *state; int do_wake = 0; int ret; + Port *prt = erts_drvport2port(ix); + + if (prt == ERTS_INVALID_ERL_DRV_PORT) + return -1; - ERTS_SMP_LC_ASSERT(erts_drvport2port(ix, NULL) - && erts_lc_is_port_locked(erts_drvport2port(ix, NULL))); + ERTS_SMP_LC_ASSERT(erts_lc_is_port_locked(prt)); #ifdef ERTS_SYS_CONTINOUS_FD_NUMBERS if ((unsigned)fd >= (unsigned)erts_smp_atomic_read_nob(&drv_ev_state_len)) { @@ -949,7 +955,7 @@ static void print_select_op(erts_dsprintf_buf_t *dsbufp, ErlDrvPort ix, ErtsSysFdType fd, int mode, int on) { - Port *pp = erts_drvport2port(ix, NULL); + Port *pp = erts_drvport2port(ix); erts_dsprintf(dsbufp, "driver_select(%p, %d,%s%s%s%s, %d) " "by ", @@ -960,8 +966,8 @@ print_select_op(erts_dsprintf_buf_t *dsbufp, mode & ERL_DRV_USE ? " ERL_DRV_USE" : "", mode & (ERL_DRV_USE_NO_CALLBACK & ~ERL_DRV_USE) ? "_NO_CALLBACK" : "", on); - print_driver_name(dsbufp, pp->common.id); - erts_dsprintf(dsbufp, "driver %T ", pp ? pp->common.id : NIL); + print_driver_name(dsbufp, pp != ERTS_INVALID_ERL_DRV_PORT ? pp->common.id : NIL); + erts_dsprintf(dsbufp, "driver %T ", pp != ERTS_INVALID_ERL_DRV_PORT ? pp->common.id : NIL); } static void @@ -1020,8 +1026,9 @@ steal_pending_stop_select(erts_dsprintf_buf_t *dsbufp, ErlDrvPort ix, state->driver.drv_ptr = NULL; } else if ((mode & ERL_DRV_USE_NO_CALLBACK) == ERL_DRV_USE) { - erts_driver_t* drv_ptr = erts_drvport2port(ix, NULL)->drv_ptr; - if (drv_ptr != state->driver.drv_ptr) { + Port *prt = erts_drvport2port(ix); + erts_driver_t* drv_ptr = prt != ERTS_INVALID_ERL_DRV_PORT ? prt->drv_ptr : NULL; + if (drv_ptr && drv_ptr != state->driver.drv_ptr) { /* Some other driver wants the stop_select callback */ if (state->driver.drv_ptr->handle) { erts_ddll_dereference_driver(state->driver.drv_ptr->handle); @@ -1042,7 +1049,7 @@ static void print_event_op(erts_dsprintf_buf_t *dsbufp, ErlDrvPort ix, ErtsSysFdType fd, ErlDrvEventData event_data) { - Port *pp = erts_drvport2port(ix, NULL); + Port *pp = erts_drvport2port(ix); erts_dsprintf(dsbufp, "driver_event(%p, %d, ", ix, (int) fd); if (!event_data) erts_dsprintf(dsbufp, "NULL"); @@ -1051,8 +1058,9 @@ print_event_op(erts_dsprintf_buf_t *dsbufp, (unsigned int) event_data->events, (unsigned int) event_data->revents); erts_dsprintf(dsbufp, ") by "); - print_driver_name(dsbufp, pp->common.id); - erts_dsprintf(dsbufp, "driver %T ", pp ? pp->common.id : NIL); + if (pp != ERTS_INVALID_ERL_DRV_PORT) + print_driver_name(dsbufp, pp->common.id); + erts_dsprintf(dsbufp, "driver %T ", pp != ERTS_INVALID_ERL_DRV_PORT ? pp->common.id : NIL); } static void diff --git a/erts/emulator/sys/common/erl_mseg.c b/erts/emulator/sys/common/erl_mseg.c index bd8ba82a5f..aa460420d5 100644 --- a/erts/emulator/sys/common/erl_mseg.c +++ b/erts/emulator/sys/common/erl_mseg.c @@ -350,7 +350,7 @@ schedule_cache_check(ErtsMsegAllctr_t *ma) { static ERTS_INLINE void * mmap_align(ErtsMsegAllctr_t *ma, void *addr, size_t length, int prot, int flags, int fd, off_t offset) { - void *p, *q; + char *p, *q; UWord d; p = mmap(addr, length, prot, flags, fd, offset); @@ -366,14 +366,14 @@ mmap_align(ErtsMsegAllctr_t *ma, void *addr, size_t length, int prot, int flags, if ((p = mmap(addr, length + MSEG_ALIGNED_SIZE, prot, flags, fd, offset)) == MAP_FAILED) return MAP_FAILED; - q = (void *)ALIGNED_CEILING(p); - d = q - p; + q = (void *)ALIGNED_CEILING((char *)p); + d = (UWord)(q - p); if (d > 0) munmap(p, d); if (MSEG_ALIGNED_SIZE - d > 0) - munmap((void *) (q + length), MSEG_ALIGNED_SIZE - d); + munmap((void *)(q + length), MSEG_ALIGNED_SIZE - d); return q; } @@ -708,7 +708,7 @@ static ERTS_INLINE void *cache_get_segment(MemKind *mk, Uint *size_p, Uint flags /* Use current cache placement for remaining segment space */ - best->seg = seg + size; + best->seg = ((char *)seg) + size; best->size = csize - size; ASSERT((size % GET_PAGE_SIZE) == 0); @@ -1028,7 +1028,7 @@ mseg_realloc(ErtsMsegAllctr_t *ma, ErtsAlcType_t atype, void *seg, sys_memcpy(((char *) new_seg), ((char *) seg), MIN(new_size, old_size)); - mseg_dealloc(ma, atype, seg, old_size, opt); + mseg_dealloc(ma, atype, seg, old_size, flags, opt); } #endif } diff --git a/erts/emulator/sys/common/erl_sys_common_misc.c b/erts/emulator/sys/common/erl_sys_common_misc.c index 0b31c125e5..31ad3b82d5 100644 --- a/erts/emulator/sys/common/erl_sys_common_misc.c +++ b/erts/emulator/sys/common/erl_sys_common_misc.c @@ -49,10 +49,15 @@ static int filename_encoding = ERL_FILENAME_UNKNOWN; static int filename_warning = ERL_FILENAME_WARNING_WARNING; #if defined(__WIN32__) || defined(__DARWIN__) -static int user_filename_encoding = ERL_FILENAME_UTF8; /* Default unicode on windows */ +/* Default unicode on windows and MacOS X */ +static int user_filename_encoding = ERL_FILENAME_UTF8; #else static int user_filename_encoding = ERL_FILENAME_LATIN1; #endif +/* This controls the heuristic in printing characters in shell and w/ + io:format("~tp", ...) etc. */ +static int printable_character_set = ERL_PRINTABLE_CHARACTERS_LATIN1; + void erts_set_user_requested_filename_encoding(int encoding, int warning) { user_filename_encoding = encoding; @@ -69,6 +74,15 @@ int erts_get_filename_warning_type(void) return filename_warning; } +void erts_set_printable_characters(int range) { + /* Not an atomic */ + printable_character_set = range; +} + +int erts_get_printable_characters(void) { + return printable_character_set; +} + void erts_init_sys_common_misc(void) { #if defined(__WIN32__) diff --git a/erts/emulator/sys/unix/sys.c b/erts/emulator/sys/unix/sys.c index 0b96eded76..a7ea4b2490 100644 --- a/erts/emulator/sys/unix/sys.c +++ b/erts/emulator/sys/unix/sys.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2012. All Rights Reserved. + * Copyright Ericsson AB 1996-2013. 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 @@ -1211,8 +1211,8 @@ static int set_driver_data(ErlDrvPort port_num, report_exit_list = report_exit; } - prt = erts_drvport2port(port_num, NULL); - if (prt) + prt = erts_drvport2port(port_num); + if (prt != ERTS_INVALID_ERL_DRV_PORT) prt->os_pid = pid; if (read_write & DO_READ) { @@ -2650,7 +2650,7 @@ report_exit_status(ErtsSysReportExit *rep, int status) if (rep->ifd >= 0) { driver_data[rep->ifd].alive = 0; driver_data[rep->ifd].status = status; - (void) driver_select((ErlDrvPort) pp, + (void) driver_select(ERTS_Port2ErlDrvPort(pp), rep->ifd, (ERL_DRV_READ|ERL_DRV_USE), 1); @@ -2658,7 +2658,7 @@ report_exit_status(ErtsSysReportExit *rep, int status) if (rep->ofd >= 0) { driver_data[rep->ofd].alive = 0; driver_data[rep->ofd].status = status; - (void) driver_select((ErlDrvPort) pp, + (void) driver_select(ERTS_Port2ErlDrvPort(pp), rep->ofd, (ERL_DRV_WRITE|ERL_DRV_USE), 1); diff --git a/erts/emulator/sys/unix/sys_float.c b/erts/emulator/sys/unix/sys_float.c index f2f4de869d..787f8d6728 100644 --- a/erts/emulator/sys/unix/sys_float.c +++ b/erts/emulator/sys/unix/sys_float.c @@ -152,7 +152,7 @@ static int mask_sse2(void) #if defined(__x86_64__) -static inline int cpu_has_sse2(void) { return 1; } +static ERTS_INLINE int cpu_has_sse2(void) { return 1; } #else /* !__x86_64__ */ @@ -179,7 +179,7 @@ static unsigned int xor_eflags(unsigned int mask) return eax; } -static __inline__ unsigned int cpuid_eax(unsigned int op) +static ERTS_INLINE unsigned int cpuid_eax(unsigned int op) { unsigned int eax, save_ebx; @@ -195,7 +195,7 @@ static __inline__ unsigned int cpuid_eax(unsigned int op) return eax; } -static __inline__ unsigned int cpuid_edx(unsigned int op) +static ERTS_INLINE unsigned int cpuid_edx(unsigned int op) { unsigned int eax, edx, save_ebx; @@ -215,7 +215,7 @@ static __inline__ unsigned int cpuid_edx(unsigned int op) * register on the Intel486 processor to generate alignment * faults. This bit cannot be set on the Intel386 processor. */ -static __inline__ int is_386(void) +static ERTS_INLINE int is_386(void) { return ((xor_eflags(1<<18) >> 18) & 1) == 0; } @@ -223,7 +223,7 @@ static __inline__ int is_386(void) /* Newer x86 processors have a CPUID instruction, as indicated by * the ID bit (#21) in EFLAGS being modifiable. */ -static __inline__ int has_CPUID(void) +static ERTS_INLINE int has_CPUID(void) { return (xor_eflags(1<<21) >> 21) & 1; } diff --git a/erts/emulator/sys/win32/erl_win_dyn_driver.h b/erts/emulator/sys/win32/erl_win_dyn_driver.h index ae3228ff28..a7c53c904d 100644 --- a/erts/emulator/sys/win32/erl_win_dyn_driver.h +++ b/erts/emulator/sys/win32/erl_win_dyn_driver.h @@ -37,6 +37,7 @@ WDD_TYPEDEF(int, driver_failure_posix,(ErlDrvPort, int)); WDD_TYPEDEF(int, driver_failure,(ErlDrvPort, int)); WDD_TYPEDEF(int, driver_exit, (ErlDrvPort, int)); WDD_TYPEDEF(int, driver_failure_eof, (ErlDrvPort)); +WDD_TYPEDEF(void, erl_drv_busy_msgq_limits, (ErlDrvPort, ErlDrvSizeT *, ErlDrvSizeT *)); WDD_TYPEDEF(int, driver_select, (ErlDrvPort, ErlDrvEvent, int, int)); WDD_TYPEDEF(int, driver_event, (ErlDrvPort, ErlDrvEvent,ErlDrvEventData)); WDD_TYPEDEF(int, driver_output, (ErlDrvPort, char *, ErlDrvSizeT)); @@ -47,6 +48,7 @@ WDD_TYPEDEF(ErlDrvSizeT, driver_vec_to_buf, (ErlIOVec *, char *, ErlDrvSizeT)); WDD_TYPEDEF(int, driver_set_timer, (ErlDrvPort, unsigned long)); WDD_TYPEDEF(int, driver_cancel_timer, (ErlDrvPort)); WDD_TYPEDEF(int, driver_read_timer, (ErlDrvPort, unsigned long *)); +WDD_TYPEDEF(int, erl_drv_consume_timeslice, (ErlDrvPort, int)); WDD_TYPEDEF(char *, erl_errno_id, (int)); WDD_TYPEDEF(void, set_busy_port, (ErlDrvPort, int)); WDD_TYPEDEF(void, set_port_control_flags, (ErlDrvPort, int)); @@ -152,6 +154,7 @@ typedef struct { WDD_FTYPE(driver_failure) *driver_failure; WDD_FTYPE(driver_exit) *driver_exit; WDD_FTYPE(driver_failure_eof) *driver_failure_eof; + WDD_FTYPE(erl_drv_busy_msgq_limits) *erl_drv_busy_msgq_limits; WDD_FTYPE(driver_select) *driver_select; WDD_FTYPE(driver_event) *driver_event; WDD_FTYPE(driver_output) *driver_output; @@ -162,6 +165,7 @@ typedef struct { WDD_FTYPE(driver_set_timer) *driver_set_timer; WDD_FTYPE(driver_cancel_timer) *driver_cancel_timer; WDD_FTYPE(driver_read_timer) *driver_read_timer; + WDD_FTYPE(erl_drv_consume_timeslice) *erl_drv_consume_timeslice; WDD_FTYPE(erl_errno_id) *erl_errno_id; WDD_FTYPE(set_busy_port)* set_busy_port; WDD_FTYPE(set_port_control_flags) *set_port_control_flags; @@ -261,6 +265,7 @@ extern TWinDynDriverCallbacks WinDynDriverCallbacks; #define driver_failure (WinDynDriverCallbacks.driver_failure) #define driver_exit (WinDynDriverCallbacks.driver_exit) #define driver_failure_eof (WinDynDriverCallbacks.driver_failure_eof) +#define erl_drv_busy_msgq_limits (WinDynDriverCallbacks.erl_drv_busy_msgq_limits) #define driver_select (WinDynDriverCallbacks.driver_select) #define driver_event (WinDynDriverCallbacks.driver_event) #define driver_output (WinDynDriverCallbacks.driver_output) @@ -271,6 +276,7 @@ extern TWinDynDriverCallbacks WinDynDriverCallbacks; #define driver_set_timer (WinDynDriverCallbacks.driver_set_timer) #define driver_cancel_timer (WinDynDriverCallbacks.driver_cancel_timer) #define driver_read_timer (WinDynDriverCallbacks.driver_read_timer) +#define erl_drv_consume_timeslice (WinDynDriverCallbacks.erl_drv_consume_timeslice) #define erl_errno_id (WinDynDriverCallbacks.erl_errno_id) #define set_busy_port (WinDynDriverCallbacks.set_busy_port) #define set_port_control_flags (WinDynDriverCallbacks.set_port_control_flags) @@ -394,6 +400,7 @@ do { \ ((W).driver_failure) = driver_failure; \ ((W).driver_exit) = driver_exit; \ ((W).driver_failure_eof) = driver_failure_eof; \ +((W).erl_drv_busy_msgq_limits) = erl_drv_busy_msgq_limits;\ ((W).driver_select) = driver_select; \ ((W).driver_event) = driver_event; \ ((W).driver_output) = driver_output; \ @@ -404,6 +411,7 @@ do { \ ((W).driver_set_timer) = driver_set_timer; \ ((W).driver_cancel_timer) = driver_cancel_timer; \ ((W).driver_read_timer) = driver_read_timer; \ +((W).erl_drv_consume_timeslice) = erl_drv_consume_timeslice;\ ((W).erl_errno_id) = erl_errno_id; \ ((W).set_busy_port) = set_busy_port; \ ((W).set_port_control_flags) = set_port_control_flags; \ diff --git a/erts/emulator/sys/win32/sys.c b/erts/emulator/sys/win32/sys.c index 1cd9072cea..e0422de026 100755 --- a/erts/emulator/sys/win32/sys.c +++ b/erts/emulator/sys/win32/sys.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2012. All Rights Reserved. + * Copyright Ericsson AB 1996-2013. 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 @@ -57,11 +57,13 @@ extern void _dosmaperr(DWORD); #define __argv e_argv #endif +typedef struct driver_data DriverData; + static void init_console(); static int get_and_remove_option(int* argc, char** argv, const char* option); static char *get_and_remove_option2(int *argc, char **argv, const char *option); -static int init_async_io(struct async_io* aio, int use_threads); +static int init_async_io(DriverData *dp, struct async_io* aio, int use_threads); static void release_async_io(struct async_io* aio, ErlDrvPort); static void async_read_file(struct async_io* aio, LPVOID buf, DWORD numToRead); static int async_write_file(struct async_io* aio, LPVOID buf, DWORD numToWrite); @@ -96,7 +98,7 @@ static erts_smp_atomic_t pipe_creation_counter; static int driver_write(long, HANDLE, byte*, int); static int create_file_thread(struct async_io* aio, int mode); #ifdef ERTS_SMP -static void close_active_handle(ErlDrvPort, HANDLE handle); +static void close_active_handle(DriverData *, HANDLE handle); static DWORD WINAPI threaded_handle_closer(LPVOID param); #endif static DWORD WINAPI threaded_reader(LPVOID param); @@ -440,6 +442,8 @@ typedef struct async_io { DWORD bytesTransferred; /* Bytes read or write in the last operation. * Valid only when DF_OVR_READY is set. */ + DriverData *dp; /* Pointer to driver data struct which + this struct is part of */ } AsyncIo; @@ -458,7 +462,7 @@ static BOOL (WINAPI *fpSetHandleInformation)(HANDLE,DWORD,DWORD); * none of the file handles. */ -typedef struct driver_data { +struct driver_data { int totalNeeded; /* Total number of bytes needed to fill * up the packet header or packet. */ int bytesInBuffer; /* Number of bytes read so far in @@ -476,7 +480,8 @@ typedef struct driver_data { AsyncIo in; /* Control block for overlapped reading. */ AsyncIo out; /* Control block for overlapped writing. */ int report_exit; /* Do report exit status for the port */ -} DriverData; + erts_atomic32_t refc; /* References to this struct */ +}; /* Driver interfaces */ static ErlDrvData spawn_start(ErlDrvPort, char*, SysDriverOpts*); @@ -581,6 +586,26 @@ struct erl_drv_entry vanilla_driver_entry = { stop_select }; +static ERTS_INLINE void +refer_driver_data(DriverData *dp) +{ +#ifdef DEBUG + erts_aint32_t refc = erts_atomic32_inc_read_nob(&dp->refc); + ASSERT(refc > 1); +#else + erts_atomic32_inc_nob(&dp->refc); +#endif +} + +static ERTS_INLINE void +unrefer_driver_data(DriverData *dp) +{ + erts_aint32_t refc = erts_atomic32_dec_read_mb(&dp->refc); + ASSERT(refc >= 0); + if (refc == 0) + driver_free(dp); +} + /* * Initialises a DriverData structure. * @@ -604,6 +629,7 @@ new_driver_data(ErlDrvPort port_num, int packet_bytes, int wait_objs_required, i * any more, since driver_select() can't fail. */ + erts_atomic32_init_nob(&dp->refc, 1); dp->bytesInBuffer = 0; dp->totalNeeded = packet_bytes; dp->inBufSize = PORT_BUFSIZ; @@ -616,9 +642,9 @@ new_driver_data(ErlDrvPort port_num, int packet_bytes, int wait_objs_required, i dp->port_num = port_num; dp->packet_bytes = packet_bytes; dp->port_pid = INVALID_HANDLE_VALUE; - if (init_async_io(&dp->in, use_threads) == -1) + if (init_async_io(dp, &dp->in, use_threads) == -1) goto async_io_error1; - if (init_async_io(&dp->out, use_threads) == -1) + if (init_async_io(dp, &dp->out, use_threads) == -1) goto async_io_error2; return dp; @@ -662,7 +688,7 @@ release_driver_data(DriverData* dp) dp->in.fd = INVALID_HANDLE_VALUE; DEBUGF(("Waiting for the in event thingie")); if (WaitForSingleObject(dp->in.ov.hEvent,timeout) == WAIT_TIMEOUT) { - close_active_handle(dp->port_num, dp->in.ov.hEvent); + close_active_handle(dp, dp->in.ov.hEvent); dp->in.ov.hEvent = NULL; timeout = 0; } @@ -673,7 +699,7 @@ release_driver_data(DriverData* dp) dp->out.fd = INVALID_HANDLE_VALUE; DEBUGF(("Waiting for the out event thingie")); if (WaitForSingleObject(dp->out.ov.hEvent,timeout) == WAIT_TIMEOUT) { - close_active_handle(dp->port_num, dp->out.ov.hEvent); + close_active_handle(dp, dp->out.ov.hEvent); dp->out.ov.hEvent = NULL; } DEBUGF(("...done\n")); @@ -719,19 +745,20 @@ release_driver_data(DriverData* dp) * the exit thread. */ - driver_free(dp); + unrefer_driver_data(dp); } #ifdef ERTS_SMP struct handles_to_be_closed { HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + DriverData *drv_data[MAXIMUM_WAIT_OBJECTS]; unsigned cnt; }; static struct handles_to_be_closed* htbc_curr = NULL; CRITICAL_SECTION htbc_lock; -static void close_active_handle(ErlDrvPort port_num, HANDLE handle) +static void close_active_handle(DriverData *dp, HANDLE handle) { struct handles_to_be_closed* htbc; int i; @@ -744,12 +771,18 @@ static void close_active_handle(ErlDrvPort port_num, HANDLE handle) htbc = (struct handles_to_be_closed*) erts_alloc(ERTS_ALC_T_DRV_TAB, sizeof(*htbc)); htbc->handles[0] = CreateAutoEvent(FALSE); + htbc->drv_data[0] = NULL; htbc->cnt = 1; thread = (HANDLE *) _beginthreadex(NULL, 0, threaded_handle_closer, htbc, 0, &tid); CloseHandle(thread); } - htbc->handles[htbc->cnt++] = handle; - driver_select(port_num, (ErlDrvEvent)handle, ERL_DRV_USE_NO_CALLBACK, 0); + i = htbc->cnt++; + htbc->handles[i] = handle; + htbc->drv_data[i] = dp; + if (dp) + refer_driver_data(dp); /* Need to keep driver data until we have + closed the event; outstanding operation + might write into it.. */ SetEvent(htbc->handles[0]); htbc_curr = htbc; LeaveCriticalSection(&htbc_lock); @@ -781,8 +814,13 @@ threaded_handle_closer(LPVOID param) default: ix = res - WAIT_OBJECT_0; if (ix > 0 && ix < htbc->cnt) { + int move_ix; CloseHandle(htbc->handles[ix]); - htbc->handles[ix] = htbc->handles[--htbc->cnt]; + if (htbc->drv_data[ix]) + unrefer_driver_data(htbc->drv_data[ix]); + move_ix = --htbc->cnt; + htbc->handles[ix] = htbc->handles[move_ix]; + htbc->drv_data[ix] = htbc->drv_data[move_ix]; } } if (htbc != htbc_curr) { @@ -798,6 +836,7 @@ threaded_handle_closer(LPVOID param) } LeaveCriticalSection(&htbc_lock); CloseHandle(htbc->handles[0]); + ASSERT(!htbc->drv_data[0]); erts_free(ERTS_ALC_T_DRV_TAB, htbc); DEBUGF(("threaded_handle_closer %p terminating\r\n", htbc)); return 0; @@ -864,8 +903,9 @@ reuse_driver_data(DriverData *dp, HANDLE ifd, HANDLE ofd, int read_write, ErlDrv */ static int -init_async_io(AsyncIo* aio, int use_threads) +init_async_io(DriverData *dp, AsyncIo* aio, int use_threads) { + aio->dp = dp; aio->flags = 0; aio->thread = (HANDLE) -1; aio->fd = INVALID_HANDLE_VALUE; @@ -884,6 +924,8 @@ init_async_io(AsyncIo* aio, int use_threads) if (aio->ov.hEvent == NULL) return -1; if (use_threads) { + OV_BUFFER_PTR(aio) = NULL; + OV_NUM_TO_READ(aio) = 0; aio->ioAllowed = CreateAutoEvent(FALSE); if (aio->ioAllowed == NULL) return -1; @@ -914,12 +956,8 @@ release_async_io(AsyncIo* aio, ErlDrvPort port_num) CloseHandle(aio->fd); aio->fd = INVALID_HANDLE_VALUE; - if (aio->ov.hEvent != NULL) { - (void) driver_select(port_num, - (ErlDrvEvent)aio->ov.hEvent, - ERL_DRV_USE, 0); - /* was CloseHandle(aio->ov.hEvent); */ - } + if (aio->ov.hEvent != NULL) + CloseHandle(aio->ov.hEvent); aio->ov.hEvent = NULL; @@ -1260,9 +1298,9 @@ spawn_start(ErlDrvPort port_num, char* name, SysDriverOpts* opts) retval = set_driver_data(dp, hFromChild, hToChild, opts->read_write, opts->exit_status); if (retval != ERL_DRV_ERROR_GENERAL && retval != ERL_DRV_ERROR_ERRNO) { - Port *prt = erts_drvport2port_raw(port_num); + Port *prt = erts_drvport2port(port_num); /* We assume that this cannot generate a negative number */ - ASSERT(prt); + ASSERT(prt != ERTS_INVALID_ERL_DRV_PORT); prt->os_pid = (SWord) pid; } } @@ -1287,12 +1325,15 @@ create_file_thread(AsyncIo* aio, int mode) { DWORD tid; /* Id for thread. */ + refer_driver_data(aio->dp); aio->thread = (HANDLE) _beginthreadex(NULL, 0, (mode & DO_WRITE) ? threaded_writer : threaded_reader, aio, 0, &tid); - - return aio->thread != (HANDLE) -1; + if (aio->thread != (HANDLE) -1) + return 1; + unrefer_driver_data(aio->dp); + return 0; } /* @@ -2078,6 +2119,7 @@ threaded_reader(LPVOID param) if (aio->flags & DF_EXIT_THREAD) break; } + unrefer_driver_data(aio->dp); return 0; } @@ -2157,6 +2199,7 @@ threaded_writer(LPVOID param) } CloseHandle(aio->fd); aio->fd = INVALID_HANDLE_VALUE; + unrefer_driver_data(aio->dp); return 0; } @@ -2297,6 +2340,7 @@ static void fd_stop(ErlDrvData data) (void) driver_select(dp->port_num, (ErlDrvEvent)dp->out.ov.hEvent, ERL_DRV_WRITE, 0); + ASSERT(dp->out.flushEvent); SetEvent(dp->out.flushEvent); WaitForSingleObject(dp->out.flushReplyEvent, INFINITE); } @@ -2349,12 +2393,12 @@ stop(ErlDrvData data) if (dp->in.ov.hEvent != NULL) { (void) driver_select(dp->port_num, (ErlDrvEvent)dp->in.ov.hEvent, - ERL_DRV_READ, 0); + ERL_DRV_READ|ERL_DRV_USE_NO_CALLBACK, 0); } if (dp->out.ov.hEvent != NULL) { (void) driver_select(dp->port_num, (ErlDrvEvent)dp->out.ov.hEvent, - ERL_DRV_WRITE, 0); + ERL_DRV_WRITE|ERL_DRV_USE_NO_CALLBACK, 0); } if (dp->out.thread == (HANDLE) -1 && dp->in.thread == (HANDLE) -1) { @@ -2366,6 +2410,8 @@ stop(ErlDrvData data) */ HANDLE thread; DWORD tid; + + /* threaded_exiter implicitly takes over refc from us... */ thread = (HANDLE *) _beginthreadex(NULL, 0, threaded_exiter, dp, 0, &tid); CloseHandle(thread); } diff --git a/erts/emulator/test/decode_packet_SUITE.erl b/erts/emulator/test/decode_packet_SUITE.erl index 1714551e15..2baf91cf29 100644 --- a/erts/emulator/test/decode_packet_SUITE.erl +++ b/erts/emulator/test/decode_packet_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2008-2011. All Rights Reserved. +%% Copyright Ericsson AB 2008-2013. 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 diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl index dae36fed8f..dfba7d098f 100644 --- a/erts/emulator/test/driver_SUITE.erl +++ b/erts/emulator/test/driver_SUITE.erl @@ -78,7 +78,8 @@ otp_9302/1, thr_free_drv/1, async_blast/1, - thr_msg_blast/1]). + thr_msg_blast/1, + consume_timeslice/1]). -export([bin_prefix/2]). @@ -149,7 +150,8 @@ all() -> otp_9302, thr_free_drv, async_blast, - thr_msg_blast]. + thr_msg_blast, + consume_timeslice]. groups() -> [{timer, [], @@ -2073,10 +2075,329 @@ thr_msg_blast(Config) when is_list(Config) -> Res end. +consume_timeslice(Config) when is_list(Config) -> + %% + %% Verify that erl_drv_consume_timeslice() works. + %% + %% The first four cases expect that the command signal is + %% delivered immediately, i.e., isn't scheduled. Since there + %% are no conflicts these signals should normally be delivered + %% immediately. However some builds and configurations may + %% schedule these ops anyway, in these cases we do not verify + %% scheduling counts. + %% + %% When signal is delivered immediately we must take into account + %% that process and port are "virtualy" scheduled out and in + %% in the trace generated. + %% + %% Port ! {_, {command, _}, and port_command() differs. The send + %% instruction needs to check if the caller is out of reductions + %% at the end of the instruction, since no erlang function call + %% is involved. Otherwise, a sequence of send instructions would + %% not be scheduled out even when out of reductions. port_commond() + %% doesn't do that since it will always (since R16A) be called via + %% the erlang wrappers in the erlang module. + %% + %% The last two cases tests scheduled operations. We create + %% a conflict by executing at the same time on different + %% schedulers. When only one scheduler we enable parallelism on + %% the port instead. + %% + + Path = ?config(data_dir, Config), + erl_ddll:start(), + ok = load_driver(Path, consume_timeslice_drv), + Port = open_port({spawn, consume_timeslice_drv}, [{parallelism, false}]), + + Parent = self(), + Go = make_ref(), + + "enabled" = port_control(Port, $E, ""), + Proc1 = spawn_link(fun () -> + receive Go -> ok end, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}} + end), + receive after 100 -> ok end, + count_pp_sched_start(), + Proc1 ! Go, + wait_command_msgs(Port, 10), + [{Port, Sprt1}, {Proc1, Sproc1}] = count_pp_sched_stop([Port, Proc1]), + case Sprt1 of + 10 -> + true = in_range(5, Sproc1-10, 7); + _ -> + case erlang:system_info(lock_checking) of + true -> ?t:format("Ignore bad sched count due to lock checking", []); + false -> ?t:fail({unexpected_sched_counts, Sprt1, Sproc1}) + end + end, + + "disabled" = port_control(Port, $D, ""), + Proc2 = spawn_link(fun () -> + receive Go -> ok end, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}}, + Port ! {Parent, {command, ""}} + end), + receive after 100 -> ok end, + count_pp_sched_start(), + Proc2 ! Go, + wait_command_msgs(Port, 10), + [{Port, Sprt2}, {Proc2, Sproc2}] = count_pp_sched_stop([Port, Proc2]), + case Sprt2 of + 10 -> + true = in_range(1, Sproc2-10, 2); + _ -> + case erlang:system_info(lock_checking) of + true -> ?t:format("Ignore bad sched count due to lock checking", []); + false -> ?t:fail({unexpected_sched_counts, Sprt2, Sproc2}) + end + end, + + "enabled" = port_control(Port, $E, ""), + Proc3 = spawn_link(fun () -> + receive Go -> ok end, + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, "") + end), + count_pp_sched_start(), + Proc3 ! Go, + wait_command_msgs(Port, 10), + [{Port, Sprt3}, {Proc3, Sproc3}] = count_pp_sched_stop([Port, Proc3]), + case Sprt3 of + 10 -> + true = in_range(5, Sproc3-10, 7); + _ -> + case erlang:system_info(lock_checking) of + true -> ?t:format("Ignore bad sched count due to lock checking", []); + false -> ?t:fail({unexpected_sched_counts, Sprt3, Sproc3}) + end + end, + + "disabled" = port_control(Port, $D, ""), + Proc4 = spawn_link(fun () -> + receive Go -> ok end, + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, ""), + port_command(Port, "") + end), + count_pp_sched_start(), + Proc4 ! Go, + wait_command_msgs(Port, 10), + [{Port, Sprt4}, {Proc4, Sproc4}] = count_pp_sched_stop([Port, Proc4]), + case Sprt4 of + 10 -> + true = in_range(1, Sproc4-10, 2); + _ -> + case erlang:system_info(lock_checking) of + true -> ?t:format("Ignore bad sched count due to lock checking", []); + false -> ?t:fail({unexpected_sched_counts, Sprt4, Sproc4}) + end + end, + + SOnl = erlang:system_info(schedulers_online), + %% If only one scheduler use port with parallelism set to true, + %% in order to trigger scheduling of command signals + Port2 = case SOnl of + 1 -> + Port ! {self(), close}, + receive {Port, closed} -> ok end, + open_port({spawn, consume_timeslice_drv}, + [{parallelism, true}]); + _ -> + process_flag(scheduler, 1), + 1 = erlang:system_info(scheduler_id), + Port + end, + count_pp_sched_start(), + "enabled" = port_control(Port2, $E, ""), + W5 = case SOnl of + 1 -> + false; + _ -> + W1= spawn_opt(fun () -> + 2 = erlang:system_info(scheduler_id), + "sleeped" = port_control(Port2, $S, "") + end, [link,{scheduler,2}]), + receive after 100 -> ok end, + W1 + end, + Proc5 = spawn_opt(fun () -> + receive Go -> ok end, + 1 = erlang:system_info(scheduler_id), + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}} + end, [link,{scheduler,1}]), + receive after 100 -> ok end, + Proc5 ! Go, + wait_procs_exit([W5, Proc5]), + wait_command_msgs(Port2, 10), + [{Port2, Sprt5}, {Proc5, Sproc5}] = count_pp_sched_stop([Port2, Proc5]), + true = in_range(2, Sproc5, 3), + true = in_range(7, Sprt5, 20), + + count_pp_sched_start(), + "disabled" = port_control(Port2, $D, ""), + W6 = case SOnl of + 1 -> + false; + _ -> + W2= spawn_opt(fun () -> + 2 = erlang:system_info(scheduler_id), + "sleeped" = port_control(Port2, $S, "") + end, [link,{scheduler,2}]), + receive after 100 -> ok end, + W2 + end, + Proc6 = spawn_opt(fun () -> + receive Go -> ok end, + 1 = erlang:system_info(scheduler_id), + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}}, + Port2 ! {Parent, {command, ""}} + end, [link,{scheduler,1}]), + receive after 100 -> ok end, + Proc6 ! Go, + wait_procs_exit([W6, Proc6]), + wait_command_msgs(Port2, 10), + [{Port2, Sprt6}, {Proc6, Sproc6}] = count_pp_sched_stop([Port2, Proc6]), + true = in_range(2, Sproc6, 3), + true = in_range(3, Sprt6, 6), + + process_flag(scheduler, 0), + + Port2 ! {self(), close}, + receive {Port2, closed} -> ok end, + ok. + +wait_command_msgs(_, 0) -> + ok; +wait_command_msgs(Port, N) -> + receive + {Port, command} -> + wait_command_msgs(Port, N-1) + end. + +in_range(Low, Val, High) when is_integer(Low), + is_integer(Val), + is_integer(High), + Low =< Val, + Val =< High -> + true; +in_range(Low, Val, High) when is_integer(Low), + is_integer(Val), + is_integer(High) -> + false. + +count_pp_sched_start() -> + erlang:trace(all, true, [running_procs, running_ports, {tracer, self()}]), + ok. + +count_pp_sched_stop(Ps) -> + Td = erlang:trace_delivered(all), + erlang:trace(all, false, [running_procs, running_ports, {tracer, self()}]), + PNs = lists:map(fun (P) -> {P, 0} end, Ps), + receive {trace_delivered, all, Td} -> ok end, + Res = count_proc_sched(Ps, PNs), + ?t:format("Scheduling counts: ~p~n", [Res]), + erlang:display({scheduling_counts, Res}), + Res. + +do_inc_pn(_P, []) -> + throw(undefined); +do_inc_pn(P, [{P,N}|PNs]) -> + [{P,N+1}|PNs]; +do_inc_pn(P, [PN|PNs]) -> + [PN|do_inc_pn(P, PNs)]. + +inc_pn(P, PNs) -> + try + do_inc_pn(P, PNs) + catch + throw:undefined -> PNs + end. + +count_proc_sched(Ps, PNs) -> + receive + TT when element(1, TT) == trace, element(3, TT) == in -> +% erlang:display(TT), + count_proc_sched(Ps, inc_pn(element(2, TT), PNs)); + TT when element(1, TT) == trace, element(3, TT) == out -> + count_proc_sched(Ps, PNs) + after 0 -> + PNs + end. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% Utilities %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +%flush_msgs() -> +% receive +% M -> +% erlang:display(M), +% flush_msgs() +% after 0 -> +% ok +% end. + +wait_procs_exit([]) -> + ok; +wait_procs_exit([P|Ps]) when is_pid(P) -> + Mon = erlang:monitor(process, P), + receive + {'DOWN', Mon, process, P, _} -> + wait_procs_exit(Ps) + end; +wait_procs_exit([_|Ps]) -> + wait_procs_exit(Ps). + get_port_msg(Port, Timeout) -> receive {Port, What} -> diff --git a/erts/emulator/test/driver_SUITE_data/Makefile.src b/erts/emulator/test/driver_SUITE_data/Makefile.src index b667dff6b6..1fedd72200 100644 --- a/erts/emulator/test/driver_SUITE_data/Makefile.src +++ b/erts/emulator/test/driver_SUITE_data/Makefile.src @@ -15,7 +15,8 @@ MISC_DRVS = outputv_drv@dll@ \ otp_9302_drv@dll@ \ thr_free_drv@dll@ \ async_blast_drv@dll@ \ - thr_msg_blast_drv@dll@ + thr_msg_blast_drv@dll@ \ + consume_timeslice_drv@dll@ SYS_INFO_DRVS = sys_info_base_drv@dll@ \ sys_info_prev_drv@dll@ \ diff --git a/erts/emulator/test/driver_SUITE_data/consume_timeslice_drv.c b/erts/emulator/test/driver_SUITE_data/consume_timeslice_drv.c new file mode 100644 index 0000000000..578a210ab2 --- /dev/null +++ b/erts/emulator/test/driver_SUITE_data/consume_timeslice_drv.c @@ -0,0 +1,172 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2012-2013. 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% + */ + +#include "erl_driver.h" +#ifdef __WIN32__ +#include <windows.h> +#else +#include <unistd.h> +#endif +#include <stdio.h> +#include <string.h> + +static void stop(ErlDrvData drv_data); +static ErlDrvData start(ErlDrvPort port, + char *command); +static void output(ErlDrvData drv_data, + char *buf, ErlDrvSizeT len); +static ErlDrvSSizeT control(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen); + +static ErlDrvEntry consume_timeslice_drv_entry = { + NULL /* init */, + start, + stop, + output, + NULL /* ready_input */, + NULL /* ready_output */, + "consume_timeslice_drv", + NULL /* finish */, + NULL /* handle */, + control, + NULL /* timeout */, + NULL /* outputv */, + NULL /* ready_async */, + NULL /* flush */, + NULL /* call */, + NULL /* event */, + ERL_DRV_EXTENDED_MARKER, + ERL_DRV_EXTENDED_MAJOR_VERSION, + ERL_DRV_EXTENDED_MINOR_VERSION, + ERL_DRV_FLAG_USE_PORT_LOCKING, + NULL /* handle2 */, + NULL /* handle_monitor */ +}; + +typedef struct { + ErlDrvPort port; + ErlDrvTermData tport; + ErlDrvTermData cmd_msg[6]; + int consume_timeslice; +} consume_timeslice_data_t; + + +DRIVER_INIT(consume_timeslice_drv) +{ + return &consume_timeslice_drv_entry; +} + +static void stop(ErlDrvData drv_data) +{ + driver_free((void *) drv_data); +} + +static ErlDrvData start(ErlDrvPort port, + char *command) +{ + consume_timeslice_data_t *ctsd; + + ctsd = driver_alloc(sizeof(consume_timeslice_data_t)); + if (!ctsd) + return ERL_DRV_ERROR_GENERAL; + + ctsd->port = port; + ctsd->tport = driver_mk_port(port); + ctsd->consume_timeslice = 0; + + ctsd->cmd_msg[0] = ERL_DRV_PORT; + ctsd->cmd_msg[1] = ctsd->tport; + ctsd->cmd_msg[2] = ERL_DRV_ATOM; + ctsd->cmd_msg[3] = driver_mk_atom("command"); + ctsd->cmd_msg[4] = ERL_DRV_TUPLE; + ctsd->cmd_msg[5] = (ErlDrvTermData) 2; + + return (ErlDrvData) ctsd; +} + +static void output(ErlDrvData drv_data, + char *buf, ErlDrvSizeT len) +{ + consume_timeslice_data_t *ctsd = (consume_timeslice_data_t *) drv_data; + int res; + + if (ctsd->consume_timeslice) { + int res = erl_drv_consume_timeslice(ctsd->port, 50); + if (res < 0) { + driver_failure_atom(ctsd->port, "erl_drv_consume_timeslice() failed"); + return; + } + } + + res = erl_drv_output_term(ctsd->tport, + ctsd->cmd_msg, + sizeof(ctsd->cmd_msg)/sizeof(ErlDrvTermData)); + if (res <= 0) { + driver_failure_atom(ctsd->port, "erl_drv_output_term() failed"); + return; + } +} +static ErlDrvSSizeT control(ErlDrvData drv_data, + unsigned int command, + char *buf, ErlDrvSizeT len, + char **rbuf, ErlDrvSizeT rlen) +{ + consume_timeslice_data_t *ctsd = (consume_timeslice_data_t *) drv_data; + int res; + char *res_str; + ErlDrvSSizeT res_len; + + switch (command) { + case 'E': + ctsd->consume_timeslice = 1; + res_str = "enabled"; + break; + case 'D': + ctsd->consume_timeslice = 0; + res_str = "disabled"; + break; + case 'S': +#ifdef __WIN32__ + Sleep((DWORD) 1000); +#else + sleep(1); +#endif + res_str = "sleeped"; + break; + default: + res_str = "what?"; + break; + } + + res_len = strlen(res_str); + if (res_len > rlen) { + char *abuf = driver_alloc(sizeof(char)*res_len); + if (!abuf) { + driver_failure_atom(ctsd->port, "driver_alloc() failed"); + return 0; + } + *rbuf = abuf; + } + + memcpy((void *) *rbuf, (void *) res_str, res_len); + + return res_len; +} diff --git a/erts/emulator/test/efile_SUITE.erl b/erts/emulator/test/efile_SUITE.erl index 9ac004200e..65367eab98 100644 --- a/erts/emulator/test/efile_SUITE.erl +++ b/erts/emulator/test/efile_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 1997-2011. All Rights Reserved. +%% Copyright Ericsson AB 1997-2013. 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 @@ -21,6 +21,8 @@ init_per_group/2,end_per_group/2]). -export([iter_max_files/1]). +-export([do_iter_max_files/2]). + -include_lib("test_server/include/test_server.hrl"). suite() -> [{ct_hooks,[ts_install_cth]}]. @@ -51,11 +53,17 @@ end_per_group(_GroupName, Config) -> iter_max_files(suite) -> []; iter_max_files(Config) when is_list(Config) -> - ?line DataDir = ?config(data_dir,Config), - ?line TestFile = filename:join(DataDir, "existing_file"), - ?line L = do_iter_max_files(10, TestFile), - ?line io:format("Number of files opened in each test:~n~w\n", [L]), - ?line all_equal(L), + DataDir = ?config(data_dir,Config), + TestFile = filename:join(DataDir, "existing_file"), + N = 10, + %% Run on a different node in order to set the max ports + Dir = filename:dirname(code:which(?MODULE)), + {ok,Node} = test_server:start_node(test_iter_max_files,slave, + [{args,"+Q 1524 -pa " ++ Dir}]), + L = rpc:call(Node,?MODULE,do_iter_max_files,[N, TestFile]), + test_server:stop_node(Node), + io:format("Number of files opened in each test:~n~w\n", [L]), + all_equal(L), Head = hd(L), if Head >= 2 -> ok; true -> ?line test_server:fail(too_few_files) @@ -91,6 +99,6 @@ open_files(Name) -> {ok, Fd} -> [Fd| open_files(Name)]; {error, Reason} -> - io:format("Error reason: ~p", [Reason]), +% io:format("Error reason: ~p", [Reason]), [] end. diff --git a/erts/emulator/test/hash_SUITE.erl b/erts/emulator/test/hash_SUITE.erl index 830ed91da9..43c9d64af7 100644 --- a/erts/emulator/test/hash_SUITE.erl +++ b/erts/emulator/test/hash_SUITE.erl @@ -1,7 +1,8 @@ +%% -*- coding: utf-8 -*- %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2000-2011. All Rights Reserved. +%% Copyright Ericsson AB 2000-2013. 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 @@ -75,7 +76,7 @@ config(priv_dir,_) -> test_phash2/1,otp_5292/1,bit_level_binaries/1,otp_7127/1, end_per_testcase/2,init_per_testcase/2]). init_per_testcase(_Case, Config) -> - ?line Dog=test_server:timetrap(test_server:minutes(10)), + Dog=test_server:timetrap(test_server:minutes(10)), [{watchdog, Dog}|Config]. end_per_testcase(_Case, Config) -> @@ -169,24 +170,24 @@ otp_7127(Config) when is_list(Config) -> %% define -DSTANDALONE when compiling. %% basic_test() -> - ?line 685556714 = erlang:phash({a,b,c},16#FFFFFFFF), - ?line 14468079 = erlang:hash({a,b,c},16#7FFFFFF), - ?line 37442646 = erlang:phash([a,b,c,{1,2,3},c:pid(0,2,3), + 685556714 = erlang:phash({a,b,c},16#FFFFFFFF), + 14468079 = erlang:hash({a,b,c},16#7FFFFFF), + 37442646 = erlang:phash([a,b,c,{1,2,3},c:pid(0,2,3), 16#77777777777777],16#FFFFFFFF), - ?line Comment = case erlang:hash([a,b,c,{1,2,3},c:pid(0,2,3), + Comment = case erlang:hash([a,b,c,{1,2,3},c:pid(0,2,3), 16#77777777777777],16#7FFFFFF) of 102727602 -> - ?line big = erlang:system_info(endian), + big = erlang:system_info(endian), "Big endian machine"; 105818829 -> - ?line little = erlang:system_info(endian), + little = erlang:system_info(endian), "Little endian machine" end, ExternalReference = <<131,114,0,3,100,0,13,110,111,110,111,100,101,64, 110,111,104,111,115,116,0,0,0,0,122,0,0,0,0,0,0,0,0>>, - ?line 1113403635 = erlang:phash(binary_to_term(ExternalReference), + 1113403635 = erlang:phash(binary_to_term(ExternalReference), 16#FFFFFFFF), - ?line 123 = erlang:hash(binary_to_term(ExternalReference), + 123 = erlang:hash(binary_to_term(ExternalReference), 16#7FFFFFF), ExternalFun = <<131,117,0,0,0,3,103,100,0,13,110,111,110,111,100,101,64, 110,111,104,111,115,116,0,0,0,38,0,0,0,0,0,100,0,8,101, @@ -204,9 +205,9 @@ basic_test() -> 104,101,108,108,100,0,10,108,111,99,97,108,95,102,117, 110,99,108,0,0,0,1,103,100,0,13,110,111,110,111,100,101, 64,110,111,104,111,115,116,0,0,0,22,0,0,0,0,0,106>>, - ?line 170987488 = erlang:phash(binary_to_term(ExternalFun), + 170987488 = erlang:phash(binary_to_term(ExternalFun), 16#FFFFFFFF), - ?line 124460689 = erlang:hash(binary_to_term(ExternalFun), + 124460689 = erlang:hash(binary_to_term(ExternalFun), 16#7FFFFFF), case (catch erlang:phash(1,0)) of {'EXIT',{badarg, _}} -> @@ -237,23 +238,23 @@ range_test() -> spread_test(N) -> - ?line test_fun(N,{erlang,phash},16#50000000000,fun(X) -> + test_fun(N,{erlang,phash},16#50000000000,fun(X) -> X end), - ?line test_fun(N,{erlang,phash},0,fun(X) -> + test_fun(N,{erlang,phash},0,fun(X) -> X end), - ?line test_fun(N,{erlang,phash},16#123456789ABCDEF123456789ABCDEF,fun(X) -> + test_fun(N,{erlang,phash},16#123456789ABCDEF123456789ABCDEF,fun(X) -> X end), - ?line test_fun(N,{erlang,phash},16#50000000000,fun(X) -> + test_fun(N,{erlang,phash},16#50000000000,fun(X) -> integer_to_list(X) end), - ?line test_fun(N,{erlang,phash},16#50000000000,fun(X) -> + test_fun(N,{erlang,phash},16#50000000000,fun(X) -> integer_to_bytelist(X,[]) end), - ?line test_fun(N,{erlang,phash},16#50000000000,fun(X) -> - integer_to_binary(X) + test_fun(N,{erlang,phash},16#50000000000,fun(X) -> + integer_to_binary_value(X) end). @@ -265,14 +266,14 @@ cmp_test(N) -> do_cmp_hashes(0,_) -> ok; do_cmp_hashes(N,Steps) -> - ?line R0 = random:uniform(1 bsl Steps - 1) + random:uniform(16#FFFFFFFF), - ?line R = case random:uniform(2) of + R0 = random:uniform(1 bsl Steps - 1) + random:uniform(16#FFFFFFFF), + R = case random:uniform(2) of 1 -> R0; _ -> -R0 end, - ?line NSteps = case N rem 10 of + NSteps = case N rem 10 of 0 -> case (Steps + 8) rem 1024 of 0 -> @@ -283,9 +284,9 @@ do_cmp_hashes(N,Steps) -> _ -> Steps end, - ?line X = erlang:phash(R,16#FFFFFFFF), - ?line Y = make_hash(R,16#FFFFFFFF), - ?line case X =:= Y of + X = erlang:phash(R,16#FFFFFFFF), + Y = make_hash(R,16#FFFFFFFF), + case X =:= Y of true -> do_cmp_hashes(N - 1, NSteps); _ -> @@ -363,6 +364,15 @@ phash2_test() -> %% (cannot use block_hash due to compatibility issues...) {abc,26499}, {abd,26500}, + {'åäö', 62518}, + %% 81 runes as an atom, 'ᚠᚡᚢᚣᚤᚥᚦᚧᚨᚩᚪᚫᚬᚭᚮᚯᚰᚱᚲᚳᚴᚵᚶᚷᚸᚹᚺᚻᚼᚽᚾᚿᛀᛁᛂᛃᛄᛅᛆᛇᛈᛉᛊᛋᛌᛍᛎᛏᛐᛑᛒᛓᛔᛕᛖᛗᛘᛙᛚᛛᛜᛝᛞᛟᛠᛡᛢᛣᛤᛥᛦᛧᛨᛩᛪ᛫᛬᛭ᛮᛯᛰ' + {erlang:binary_to_term(<<131, 118, 0, 243, (unicode:characters_to_binary(lists:seq(5792, 5872)))/binary >>), 241561024}, + %% åäö dynamic + {erlang:binary_to_term(<<131, 118, 0, 6, 195, 165, 195, 164, 195, 182>>),62518}, + %% the atom '゙゚゛゜ゝゞゟ゠ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズ' + {erlang:binary_to_term(<<131, 118, 0, 102, (unicode:characters_to_binary(lists:seq(12441, 12542)))/binary>>), 246053818}, + %% the atom, '😃' + {erlang:binary_to_term(<<131, 118, 0, 4, 240, 159, 152, 131>>), 1026307}, %% small {0,3175731469}, @@ -469,8 +479,8 @@ phash2_test() -> SpecFun = fun(S) -> sofs:no_elements(S) > 1 end, F = sofs:relation_to_family(sofs:converse(sofs:relation(L))), D = sofs:to_external(sofs:family_specification(SpecFun, F)), - ?line [] = D, - ?line [] = [{E,H,H2} || {E,H} <- L, (H2 = erlang:phash2(E, Max)) =/= H], + [] = D, + [] = [{E,H,H2} || {E,H} <- L, (H2 = erlang:phash2(E, Max)) =/= H], ok. -ifdef(FALSE). @@ -497,17 +507,17 @@ otp_5292_test() -> end, S2 = md5([md5(hash_int(S, E, PH)) || {Start, N, Sz} <- d(), {S, E} <- int(Start, N, Sz)]), - ?line Comment = case S1 of + Comment = case S1 of <<4,248,208,156,200,131,7,1,173,13,239,173,112,81,16,174>> -> - ?line big = erlang:system_info(endian), + big = erlang:system_info(endian), "Big endian machine"; <<180,28,33,231,239,184,71,125,76,47,227,241,78,184,176,233>> -> - ?line little = erlang:system_info(endian), + little = erlang:system_info(endian), "Little endian machine" end, - ?line <<124,81,198,121,174,233,19,137,10,83,33,80,226,111,238,99>> = S2, - ?line 2 = erlang:hash(1, (1 bsl 27) -1), - ?line {'EXIT', _} = (catch erlang:hash(1, (1 bsl 27))), + <<124,81,198,121,174,233,19,137,10,83,33,80,226,111,238,99>> = S2, + 2 = erlang:hash(1, (1 bsl 27) -1), + {'EXIT', _} = (catch erlang:hash(1, (1 bsl 27))), {comment, Comment}. d() -> @@ -528,21 +538,21 @@ md5(T) -> erlang:md5(term_to_binary(T)). bit_level_binaries() -> - ?line [3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] = + [3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] = bit_level_all_different(fun erlang:hash/2), - ?line [3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] = + [3511317,7022633,14044578,28087749,56173436,112344123,90467083|_] = bit_level_all_different(fun erlang:phash/2), - ?line [102233154,19716,102133857,4532024,123369135,24565730,109558721|_] = + [102233154,19716,102133857,4532024,123369135,24565730,109558721|_] = bit_level_all_different(fun erlang:phash2/2), - ?line 13233341 = test_hash_phash(<<42:7>>, 16#7FFFFFF), - ?line 79121243 = test_hash_phash(<<99:7>>, 16#7FFFFFF), - ?line 95517726 = test_hash_phash(<<16#378ABF73:31>>, 16#7FFFFFF), + 13233341 = test_hash_phash(<<42:7>>, 16#7FFFFFF), + 79121243 = test_hash_phash(<<99:7>>, 16#7FFFFFF), + 95517726 = test_hash_phash(<<16#378ABF73:31>>, 16#7FFFFFF), - ?line 64409098 = test_phash2(<<99:7>>, 16#7FFFFFF), - ?line 55555814 = test_phash2(<<123,19:2>>, 16#7FFFFFF), - ?line 83868582 = test_phash2(<<123,45,6:3>>, 16#7FFFFFF), - ?line 2123204 = test_phash2(<<123,45,7:3>>, 16#7FFFFFF), + 64409098 = test_phash2(<<99:7>>, 16#7FFFFFF), + 55555814 = test_phash2(<<123,19:2>>, 16#7FFFFFF), + 83868582 = test_phash2(<<123,45,6:3>>, 16#7FFFFFF), + 2123204 = test_phash2(<<123,45,7:3>>, 16#7FFFFFF), ok. @@ -579,7 +589,7 @@ test_phash2(Bitstr, Rem) -> otp_7127_test() -> %% Used to return 2589127136. - ?line 38990304 = erlang:phash2(<<"Scott9">>), + 38990304 = erlang:phash2(<<"Scott9">>), ok. %% @@ -711,7 +721,7 @@ collect_hits() -> init_table(), N. -integer_to_binary(N) -> +integer_to_binary_value(N) -> list_to_binary(lists:reverse(integer_to_bytelist(N,[]))). integer_to_bytelist(0,Acc) -> diff --git a/erts/emulator/test/mtx_SUITE.erl b/erts/emulator/test/mtx_SUITE.erl index 22da84c808..a492501959 100644 --- a/erts/emulator/test/mtx_SUITE.erl +++ b/erts/emulator/test/mtx_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2013. 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 diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index 0a9d997c3b..dcf58fa474 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -1,7 +1,7 @@ %% %% %CopyrightBegin% %% -%% Copyright Ericsson AB 2010-2011. All Rights Reserved. +%% Copyright Ericsson AB 2010-2013. 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 diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index 2504d24b51..c8f286f629 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 2009-2011. All Rights Reserved. + * Copyright Ericsson AB 2009-2013. 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 diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl index c625e655ce..b92a0e2059 100644 --- a/erts/emulator/test/num_bif_SUITE.erl +++ b/erts/emulator/test/num_bif_SUITE.erl @@ -31,24 +31,28 @@ %% list_to_integer/1 %% round/1 %% trunc/1 - --export([all/0, suite/0,groups/0,init_per_suite/1, end_per_suite/1, - init_per_group/2,end_per_group/2, t_abs/1, t_float/1, - t_float_to_list/1, t_integer_to_list/1, - t_list_to_integer/1, - t_list_to_float_safe/1, t_list_to_float_risky/1, - t_round/1, t_trunc/1]). +%% integer_to_binary/1 +%% integer_to_binary/2 +%% binary_to_integer/1 + +-export([all/0, suite/0, groups/0, init_per_suite/1, end_per_suite/1, + init_per_group/2, end_per_group/2, t_abs/1, t_float/1, + t_float_to_string/1, t_integer_to_string/1, + t_string_to_integer/1, + t_string_to_float_safe/1, t_string_to_float_risky/1, + t_round/1, t_trunc/1 + ]). suite() -> [{ct_hooks,[ts_install_cth]}]. all() -> - [t_abs, t_float, t_float_to_list, t_integer_to_list, - {group, t_list_to_float}, t_list_to_integer, t_round, + [t_abs, t_float, t_float_to_string, t_integer_to_string, + {group, t_string_to_float}, t_string_to_integer, t_round, t_trunc]. groups() -> - [{t_list_to_float, [], - [t_list_to_float_safe, t_list_to_float_risky]}]. + [{t_string_to_float, [], + [t_string_to_float_safe, t_string_to_float_risky]}]. init_per_suite(Config) -> Config. @@ -65,273 +69,382 @@ end_per_group(_GroupName, Config) -> t_abs(Config) when is_list(Config) -> %% Floats. - ?line 5.5 = abs(id(5.5)), - ?line 0.0 = abs(id(0.0)), - ?line 100.0 = abs(id(-100.0)), + 5.5 = abs(id(5.5)), + 0.0 = abs(id(0.0)), + 100.0 = abs(id(-100.0)), %% Integers. - ?line 5 = abs(id(5)), - ?line 0 = abs(id(0)), - ?line 100 = abs(id(-100)), + 5 = abs(id(5)), + 0 = abs(id(0)), + 100 = abs(id(-100)), %% The largest smallnum. OTP-3190. - ?line X = id((1 bsl 27) - 1), - ?line X = abs(X), - ?line X = abs(X-1)+1, - ?line X = abs(X+1)-1, - ?line X = abs(-X), - ?line X = abs(-X-1)-1, - ?line X = abs(-X+1)+1, + X = id((1 bsl 27) - 1), + X = abs(X), + X = abs(X-1)+1, + X = abs(X+1)-1, + X = abs(-X), + X = abs(-X-1)-1, + X = abs(-X+1)+1, %% Bignums. BigNum = id(13984792374983749), - ?line BigNum = abs(BigNum), - ?line BigNum = abs(-BigNum), + BigNum = abs(BigNum), + BigNum = abs(-BigNum), ok. t_float(Config) when is_list(Config) -> - ?line 0.0 = float(id(0)), - ?line 2.5 = float(id(2.5)), - ?line 0.0 = float(id(0.0)), - ?line -100.55 = float(id(-100.55)), - ?line 42.0 = float(id(42)), - ?line -100.0 = float(id(-100)), + 0.0 = float(id(0)), + 2.5 = float(id(2.5)), + 0.0 = float(id(0.0)), + -100.55 = float(id(-100.55)), + 42.0 = float(id(42)), + -100.0 = float(id(-100)), %% Bignums. - ?line 4294967305.0 = float(id(4294967305)), - ?line -4294967305.0 = float(id(-4294967305)), + 4294967305.0 = float(id(4294967305)), + -4294967305.0 = float(id(-4294967305)), %% Extremly big bignums. - ?line Big = id(list_to_integer(id(lists:duplicate(2000, $1)))), - ?line {'EXIT', {badarg, _}} = (catch float(Big)), - - %% Invalid types and lists. - ?line {'EXIT', {badarg, _}} = (catch list_to_integer(id(atom))), - ?line {'EXIT', {badarg, _}} = (catch list_to_integer(id(123))), - ?line {'EXIT', {badarg, _}} = (catch list_to_integer(id([$1,[$2]]))), - ?line {'EXIT', {badarg, _}} = (catch list_to_integer(id("1.2"))), - ?line {'EXIT', {badarg, _}} = (catch list_to_integer(id("a"))), - ?line {'EXIT', {badarg, _}} = (catch list_to_integer(id(""))), + Big = id(list_to_integer(id(lists:duplicate(2000, $1)))), + {'EXIT', {badarg, _}} = (catch float(Big)), + ok. -%% Tests float_to_list/1, float_to_list/2. - -t_float_to_list(Config) when is_list(Config) -> - test_ftl("0.0e+0", 0.0), - test_ftl("2.5e+1", 25.0), - test_ftl("2.5e+0", 2.5), - test_ftl("2.5e-1", 0.25), - test_ftl("-3.5e+17", -350.0e15), - "1.00000000000000000000e+00" = float_to_list(1.0), - "1.00000000000000000000e+00" = float_to_list(1.0, []), - "-1.00000000000000000000e+00" = float_to_list(-1.0, []), - "-1.00000000000000000000" = float_to_list(-1.0, [{decimals, 20}]), - {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{decimals, -1}])), - {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{decimals, 254}])), - {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{scientific, 250}])), - {'EXIT', {badarg, _}} = (catch float_to_list(1.0e+300, [{decimals, 1}])), - "1.0e+300" = float_to_list(1.0e+300, [{scientific, 1}]), - "1.0" = float_to_list(1.0, [{decimals, 249}, compact]), - "1" = float_to_list(1.0, [{decimals, 0}]), - "2" = float_to_list(1.9, [{decimals, 0}]), - "123456789012345680.0" = erlang:float_to_list( - 123456789012345678.0, [{decimals, 236}, compact]), - {'EXIT', {badarg, _}} = (catch float_to_list( - 123456789012345678.0, [{decimals, 237}])), - Expected = "1." ++ string:copies("0", 249) ++ "e+00", - Expected = float_to_list(1.0, [{scientific, 249}, compact]), +%% Tests float_to_list/1, float_to_list/2, float_to_binary/1, float_to_binary/2 + +t_float_to_string(Config) when is_list(Config) -> + test_fts("0.00000000000000000000e+00", 0.0), + test_fts("2.50000000000000000000e+01", 25.0), + test_fts("2.50000000000000000000e+00", 2.5), + test_fts("2.50000000000000000000e-01", 0.25), + test_fts("-3.50000000000000000000e+17", -350.0e15), + test_fts("1.00000000000000000000e+00",1.0), + test_fts("1.00000000000000000000e+00",1.0, []), + test_fts("-1.00000000000000000000e+00",-1.0, []), + test_fts("-1.00000000000000000000",-1.0, [{decimals, 20}]), + {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{decimals, -1}])), + {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{decimals, 254}])), + {'EXIT', {badarg, _}} = (catch float_to_list(1.0, [{scientific, 250}])), + {'EXIT', {badarg, _}} = (catch float_to_list(1.0e+300, [{decimals, 1}])), + {'EXIT', {badarg, _}} = (catch float_to_binary(1.0, [{decimals, -1}])), + {'EXIT', {badarg, _}} = (catch float_to_binary(1.0, [{decimals, 254}])), + {'EXIT', {badarg, _}} = (catch float_to_binary(1.0, [{scientific, 250}])), + {'EXIT', {badarg, _}} = (catch float_to_binary(1.0e+300, [{decimals, 1}])), + test_fts("1.0e+300",1.0e+300, [{scientific, 1}]), + test_fts("1.0",1.0, [{decimals, 249}, compact]), + test_fts("1",1.0,[{decimals,0}]), + test_fts("2",1.9,[{decimals,0}]), + test_fts("123456789012345680.0",123456789012345678.0, + [{decimals, 236}, compact]), + {'EXIT', {badarg, _}} = (catch float_to_list( + 123456789012345678.0, [{decimals, 237}])), + {'EXIT', {badarg, _}} = (catch float_to_binary( + 123456789012345678.0, [{decimals, 237}])), + test_fts("1." ++ string:copies("0", 249) ++ "e+00", + 1.0, [{scientific, 249}, compact]), X1 = float_to_list(1.0), X2 = float_to_list(1.0, [{scientific, 20}]), X1 = X2, - "1.000e+00" = float_to_list(1.0, [{scientific, 3}]), - "1.000" = float_to_list(1.0, [{decimals, 3}]), - "1.0" = float_to_list(1.0, [{decimals, 1}]), - "1.0" = float_to_list(1.0, [{decimals, 3}, compact]), - "1.12" = float_to_list(1.123, [{decimals, 2}]), - "1.123" = float_to_list(1.123, [{decimals, 3}]), - "1.123" = float_to_list(1.123, [{decimals, 3}, compact]), - "1.1230" = float_to_list(1.123, [{decimals, 4}]), - "1.12300" = float_to_list(1.123, [{decimals, 5}]), - "1.123" = float_to_list(1.123, [{decimals, 5}, compact]), - "1.1234" = float_to_list(1.1234,[{decimals, 6}, compact]), - "1.01" = float_to_list(1.005, [{decimals, 2}]), - "-1.01" = float_to_list(-1.005,[{decimals, 2}]), - "0.999" = float_to_list(0.999, [{decimals, 3}]), - "-0.999" = float_to_list(-0.999,[{decimals, 3}]), - "1.0" = float_to_list(0.999, [{decimals, 2}, compact]), - "-1.0" = float_to_list(-0.999,[{decimals, 2}, compact]), - "0.5" = float_to_list(0.5, [{decimals, 1}]), - "-0.5" = float_to_list(-0.5, [{decimals, 1}]), + + Y1 = float_to_binary(1.0), + Y2 = float_to_binary(1.0, [{scientific, 20}]), + Y1 = Y2, + + test_fts("1.000e+00",1.0, [{scientific, 3}]), + test_fts("1.000",1.0, [{decimals, 3}]), + test_fts("1.0",1.0, [{decimals, 1}]), + test_fts("1.0",1.0, [{decimals, 3}, compact]), + test_fts("1.12",1.123, [{decimals, 2}]), + test_fts("1.123",1.123, [{decimals, 3}]), + test_fts("1.123",1.123, [{decimals, 3}, compact]), + test_fts("1.1230",1.123, [{decimals, 4}]), + test_fts("1.12300",1.123, [{decimals, 5}]), + test_fts("1.123",1.123, [{decimals, 5}, compact]), + test_fts("1.1234",1.1234,[{decimals, 6}, compact]), + test_fts("1.01",1.005, [{decimals, 2}]), + test_fts("-1.01",-1.005,[{decimals, 2}]), + test_fts("0.999",0.999, [{decimals, 3}]), + test_fts("-0.999",-0.999,[{decimals, 3}]), + test_fts("1.0",0.999, [{decimals, 2}, compact]), + test_fts("-1.0",-0.999,[{decimals, 2}, compact]), + test_fts("0.5",0.5, [{decimals, 1}]), + test_fts("-0.5",-0.5, [{decimals, 1}]), "2.333333" = erlang:float_to_list(7/3, [{decimals, 6}, compact]), "2.333333" = erlang:float_to_list(7/3, [{decimals, 6}]), - "0.00000000000000000000e+00" = float_to_list(0.0, [compact]), - "0.0" = float_to_list(0.0, [{decimals, 10}, compact]), - "123000000000000000000.0" = float_to_list(1.23e20, [{decimals, 10}, compact]), - "1.2300000000e+20" = float_to_list(1.23e20, [{scientific, 10}, compact]), - "1.23000000000000000000e+20" = float_to_list(1.23e20, []), + <<"2.333333">> = erlang:float_to_binary(7/3, [{decimals, 6}, compact]), + <<"2.333333">> = erlang:float_to_binary(7/3, [{decimals, 6}]), + test_fts("0.00000000000000000000e+00",0.0, [compact]), + test_fts("0.0",0.0, [{decimals, 10}, compact]), + test_fts("123000000000000000000.0",1.23e20, [{decimals, 10}, compact]), + test_fts("1.2300000000e+20",1.23e20, [{scientific, 10}, compact]), + test_fts("1.23000000000000000000e+20",1.23e20, []), ok. -test_ftl(Expect, Float) -> - %% No ?line on the next line -- we want the line number from t_float_to_list. - Expect = remove_zeros(lists:reverse(float_to_list(Float)), []). - -%% Removes any non-significant zeros in a floating point number. -%% Example: 2.500000e+01 -> 2.5e+1 - -remove_zeros([$+, $e|Rest], [$0, X|Result]) -> - remove_zeros([$+, $e|Rest], [X|Result]); -remove_zeros([$-, $e|Rest], [$0, X|Result]) -> - remove_zeros([$-, $e|Rest], [X|Result]); -remove_zeros([$0, $.|Rest], [$e|Result]) -> - remove_zeros(Rest, [$., $0, $e|Result]); -remove_zeros([$0|Rest], [$e|Result]) -> - remove_zeros(Rest, [$e|Result]); -remove_zeros([Char|Rest], Result) -> - remove_zeros(Rest, [Char|Result]); -remove_zeros([], Result) -> - Result. - -%% Tests integer_to_list/1. - -t_integer_to_list(Config) when is_list(Config) -> - ?line "0" = integer_to_list(id(0)), - ?line "42" = integer_to_list(id(42)), - ?line "-42" = integer_to_list(id(-42)), - ?line "32768" = integer_to_list(id(32768)), - ?line "268435455" = integer_to_list(id(268435455)), - ?line "-268435455" = integer_to_list(id(-268435455)), - ?line "123456932798748738738" = integer_to_list(id(123456932798748738738)), - ?line Big_List = id(lists:duplicate(2000, id($1))), - ?line Big = list_to_integer(Big_List), - ?line Big_List = integer_to_list(Big), - ok. +test_fts(Expect, Float) -> + Expect = float_to_list(Float), + BinExpect = list_to_binary(Expect), + BinExpect = float_to_binary(Float). -%% Tests list_to_float/1. +test_fts(Expect, Float, Args) -> + Expect = float_to_list(Float,Args), + BinExpect = list_to_binary(Expect), + BinExpect = float_to_binary(Float,Args). -t_list_to_float_safe(Config) when is_list(Config) -> - ?line 0.0 = list_to_float(id("0.0")), - ?line 0.0 = list_to_float(id("-0.0")), - ?line 0.5 = list_to_float(id("0.5")), - ?line -0.5 = list_to_float(id("-0.5")), - ?line 100.0 = list_to_float(id("1.0e2")), - ?line 127.5 = list_to_float(id("127.5")), - ?line -199.5 = list_to_float(id("-199.5")), +%% Tests list_to_float/1. - ?line {'EXIT',{badarg,_}} = (catch list_to_float(id("0"))), - ?line {'EXIT',{badarg,_}} = (catch list_to_float(id("0..0"))), - ?line {'EXIT',{badarg,_}} = (catch list_to_float(id("0e12"))), - ?line {'EXIT',{badarg,_}} = (catch list_to_float(id("--0.0"))), +t_string_to_float_safe(Config) when is_list(Config) -> + test_stf(0.0,"0.0"), + test_stf(0.0,"-0.0"), + test_stf(0.5,"0.5"), + test_stf(-0.5,"-0.5"), + test_stf(100.0,"1.0e2"), + test_stf(127.5,"127.5"), + test_stf(-199.5,"-199.5"), + + {'EXIT',{badarg,_}} = (catch list_to_float(id("0"))), + {'EXIT',{badarg,_}} = (catch list_to_float(id("0..0"))), + {'EXIT',{badarg,_}} = (catch list_to_float(id("0e12"))), + {'EXIT',{badarg,_}} = (catch list_to_float(id("--0.0"))), + {'EXIT',{badarg,_}} = (catch binary_to_float(id(<<"0">>))), + {'EXIT',{badarg,_}} = (catch binary_to_float(id(<<"0..0">>))), + {'EXIT',{badarg,_}} = (catch binary_to_float(id(<<"0e12">>))), + {'EXIT',{badarg,_}} = (catch binary_to_float(id(<<"--0.0">>))), + + UBin = <<0:3,(id(<<"0.0">>))/binary,0:5>>, + <<_:3,UnAlignedBin:3/binary,0:5>> = id(UBin), + 0.0 = binary_to_float(UnAlignedBin), + + ABin = <<0:8,(id(<<"1.0">>))/binary,0:8>>, + <<_:8,AlignedBin:3/binary,0:8>> = id(ABin), + 1.0 = binary_to_float(AlignedBin), ok. %% This might crash the emulator... %% (Known to crash the Unix version of Erlang 4.4.1) -t_list_to_float_risky(Config) when is_list(Config) -> - ?line Many_Ones = lists:duplicate(25000, id($1)), - ?line id(list_to_float("2."++Many_Ones)), - ?line {'EXIT', {badarg, _}} = (catch list_to_float("2"++Many_Ones)), - ok. - -%% Tests list_to_integer/1. +t_string_to_float_risky(Config) when is_list(Config) -> + Many_Ones = lists:duplicate(25000, id($1)), + id(list_to_float("2."++Many_Ones)), + {'EXIT', {badarg, _}} = (catch list_to_float("2"++Many_Ones)), -t_list_to_integer(Config) when is_list(Config) -> - ?line 0 = list_to_integer(id("0")), - ?line 0 = list_to_integer(id("00")), - ?line 0 = list_to_integer(id("-0")), - ?line 1 = list_to_integer(id("1")), - ?line -1 = list_to_integer(id("-1")), - ?line 42 = list_to_integer(id("42")), - ?line -12 = list_to_integer(id("-12")), - ?line 32768 = list_to_integer(id("32768")), - ?line 268435455 = list_to_integer(id("268435455")), - ?line -268435455 = list_to_integer(id("-268435455")), - - %% Bignums. - ?line 123456932798748738738 = list_to_integer(id("123456932798748738738")), - ?line id(list_to_integer(lists:duplicate(2000, id($1)))), + id(binary_to_float(list_to_binary("2."++Many_Ones))), + {'EXIT', {badarg, _}} = (catch binary_to_float( + list_to_binary("2"++Many_Ones))), ok. +test_stf(Expect,List) -> + Expect = list_to_float(List), + Bin = list_to_binary(List), + Expect = binary_to_float(Bin). + %% Tests round/1. t_round(Config) when is_list(Config) -> - ?line 0 = round(id(0.0)), - ?line 0 = round(id(0.4)), - ?line 1 = round(id(0.5)), - ?line 0 = round(id(-0.4)), - ?line -1 = round(id(-0.5)), - ?line 255 = round(id(255.3)), - ?line 256 = round(id(255.6)), - ?line -1033 = round(id(-1033.3)), - ?line -1034 = round(id(-1033.6)), + 0 = round(id(0.0)), + 0 = round(id(0.4)), + 1 = round(id(0.5)), + 0 = round(id(-0.4)), + -1 = round(id(-0.5)), + 255 = round(id(255.3)), + 256 = round(id(255.6)), + -1033 = round(id(-1033.3)), + -1034 = round(id(-1033.6)), % OTP-3722: - ?line X = id((1 bsl 27) - 1), - ?line MX = -X, - ?line MXm1 = -X-1, - ?line MXp1 = -X+1, - ?line F = id(X + 0.0), - ?line X = round(F), - ?line X = round(F+1)-1, - ?line X = round(F-1)+1, - ?line MX = round(-F), - ?line MXm1 = round(-F-1), - ?line MXp1 = round(-F+1), - - ?line X = round(F+0.1), - ?line X = round(F+1+0.1)-1, - ?line X = round(F-1+0.1)+1, - ?line MX = round(-F+0.1), - ?line MXm1 = round(-F-1+0.1), - ?line MXp1 = round(-F+1+0.1), - - ?line X = round(F-0.1), - ?line X = round(F+1-0.1)-1, - ?line X = round(F-1-0.1)+1, - ?line MX = round(-F-0.1), - ?line MXm1 = round(-F-1-0.1), - ?line MXp1 = round(-F+1-0.1), - - ?line 0.5 = abs(round(F+0.5)-(F+0.5)), - ?line 0.5 = abs(round(F-0.5)-(F-0.5)), - ?line 0.5 = abs(round(-F-0.5)-(-F-0.5)), - ?line 0.5 = abs(round(-F+0.5)-(-F+0.5)), + X = id((1 bsl 27) - 1), + MX = -X, + MXm1 = -X-1, + MXp1 = -X+1, + F = id(X + 0.0), + X = round(F), + X = round(F+1)-1, + X = round(F-1)+1, + MX = round(-F), + MXm1 = round(-F-1), + MXp1 = round(-F+1), + + X = round(F+0.1), + X = round(F+1+0.1)-1, + X = round(F-1+0.1)+1, + MX = round(-F+0.1), + MXm1 = round(-F-1+0.1), + MXp1 = round(-F+1+0.1), + + X = round(F-0.1), + X = round(F+1-0.1)-1, + X = round(F-1-0.1)+1, + MX = round(-F-0.1), + MXm1 = round(-F-1-0.1), + MXp1 = round(-F+1-0.1), + + 0.5 = abs(round(F+0.5)-(F+0.5)), + 0.5 = abs(round(F-0.5)-(F-0.5)), + 0.5 = abs(round(-F-0.5)-(-F-0.5)), + 0.5 = abs(round(-F+0.5)-(-F+0.5)), %% Bignums. - ?line 4294967296 = round(id(4294967296.1)), - ?line 4294967297 = round(id(4294967296.9)), - ?line -4294967296 = -round(id(4294967296.1)), - ?line -4294967297 = -round(id(4294967296.9)), + 4294967296 = round(id(4294967296.1)), + 4294967297 = round(id(4294967296.9)), + -4294967296 = -round(id(4294967296.1)), + -4294967297 = -round(id(4294967296.9)), ok. t_trunc(Config) when is_list(Config) -> - ?line 0 = trunc(id(0.0)), - ?line 5 = trunc(id(5.3333)), - ?line -10 = trunc(id(-10.978987)), + 0 = trunc(id(0.0)), + 5 = trunc(id(5.3333)), + -10 = trunc(id(-10.978987)), % The largest smallnum, converted to float (OTP-3722): - ?line X = id((1 bsl 27) - 1), - ?line F = id(X + 0.0), + X = id((1 bsl 27) - 1), + F = id(X + 0.0), io:format("X = ~p/~w/~w, F = ~p/~w/~w, trunc(F) = ~p/~w/~w~n", [X, X, binary_to_list(term_to_binary(X)), F, F, binary_to_list(term_to_binary(F)), trunc(F), trunc(F), binary_to_list(term_to_binary(trunc(F)))]), - ?line X = trunc(F), - ?line X = trunc(F+1)-1, - ?line X = trunc(F-1)+1, - ?line X = -trunc(-F), - ?line X = -trunc(-F-1)-1, - ?line X = -trunc(-F+1)+1, + X = trunc(F), + X = trunc(F+1)-1, + X = trunc(F-1)+1, + X = -trunc(-F), + X = -trunc(-F-1)-1, + X = -trunc(-F+1)+1, %% Bignums. - ?line 4294967305 = trunc(id(4294967305.7)), - ?line -4294967305 = trunc(id(-4294967305.7)), + 4294967305 = trunc(id(4294967305.7)), + -4294967305 = trunc(id(-4294967305.7)), ok. + +%% Tests integer_to_binary/1. + +t_integer_to_string(Config) when is_list(Config) -> + test_its("0",0), + test_its("42",42), + test_its("-42",-42), + test_its("32768",32768), + test_its("268435455",268435455), + test_its("-268435455",-268435455), + test_its("123456932798748738738",123456932798748738738), + + %% 1 bsl 33, just beyond 32 bit + test_its("8589934592",8589934592), + test_its("-8589934592",-8589934592), + %% 1 bsl 65, just beyond 64 bit + test_its("36893488147419103232",36893488147419103232), + test_its("-36893488147419103232",-36893488147419103232), + + %% Bignums. + BigBin = id(list_to_binary(lists:duplicate(2000, id($1)))), + Big = erlang:binary_to_integer(BigBin), + BigBin = erlang:integer_to_binary(Big), + + %% Invalid types + lists:foreach(fun(Value) -> + {'EXIT', {badarg, _}} = + (catch erlang:integer_to_binary(Value)), + {'EXIT', {badarg, _}} = + (catch erlang:integer_to_list(Value)) + end,[atom,1.2,0.0,[$1,[$2]]]), + + ok. + +test_its(List,Int) -> + Int = list_to_integer(List), + Int = binary_to_integer(list_to_binary(List)). + +%% Tests binary_to_integer/1. + +t_string_to_integer(Config) when is_list(Config) -> + 0 = erlang:binary_to_integer(id(<<"00">>)), + 0 = erlang:binary_to_integer(id(<<"-0">>)), + 0 = erlang:binary_to_integer(id(<<"+0">>)), + + test_sti(0), + test_sti(1), + test_sti(-1), + test_sti(42), + test_sti(-12), + test_sti(32768), + test_sti(268435455), + test_sti(-268435455), + + %% 1 bsl 28 - 1, just before 32 bit bignum + test_sti(1 bsl 28 - 1), + %% 1 bsl 28, just beyond 32 bit small + test_sti(1 bsl 28), + %% 1 bsl 33, just beyond 32 bit + test_sti(1 bsl 33), + %% 1 bsl 60 - 1, just before 64 bit bignum + test_sti(1 bsl 60 - 1), + %% 1 bsl 60, just beyond 64 bit small + test_sti(1 bsl 60), + %% 1 bsl 65, just beyond 64 bit + test_sti(1 bsl 65), + %% Bignums. + test_sti(123456932798748738738,16), + test_sti(list_to_integer(lists:duplicate(2000, $1))), + + %% unalign string + Str = <<"10">>, + UnalignStr = <<0:3, (id(Str))/binary, 0:5>>, + <<_:3, SomeStr:2/binary, _:5>> = id(UnalignStr), + 10 = erlang:binary_to_integer(SomeStr), + + %% Invalid types + lists:foreach(fun(Value) -> + {'EXIT', {badarg, _}} = + (catch binary_to_integer(Value)), + {'EXIT', {badarg, _}} = + (catch erlang:list_to_integer(Value)) + end,[atom,1.2,0.0,[$1,[$2]]]), + + % Default base error cases + lists:foreach(fun(Value) -> + {'EXIT', {badarg, _}} = + (catch erlang:binary_to_integer( + list_to_binary(Value))), + {'EXIT', {badarg, _}} = + (catch erlang:list_to_integer(Value)) + end,["1.0"," 1"," -1",""]), + + % Custom base error cases + lists:foreach(fun({Value,Base}) -> + {'EXIT', {badarg, _}} = + (catch binary_to_integer( + list_to_binary(Value),Base)), + {'EXIT', {badarg, _}} = + (catch erlang:list_to_integer(Value,Base)) + end,[{" 1",1},{" 1",37},{"2",2},{"C",11}, + {"1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111z",16}, + {"1z111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111",16}, + {"111z11111111",16}]), + + ok. + +test_sti(Num) -> + [begin + io:format("Testing ~p:~p",[Num,Base]), + test_sti(Num,Base) + end|| Base <- lists:seq(2,36)]. + +test_sti(Num,Base) -> + Num = list_to_integer(int2list(Num,Base),Base), + Num = -1*list_to_integer(int2list(Num*-1,Base),Base), + Num = binary_to_integer(int2bin(Num,Base),Base), + Num = -1*binary_to_integer(int2bin(Num*-1,Base),Base). + % Calling this function (which is not supposed to be inlined) prevents % the compiler from calculating the answer, so we don't test the compiler % instead of the newest runtime system. id(X) -> X. + +%% Uses the printing library to to integer_to_binary conversions. +int2bin(Int,Base) when Base < 37 -> + iolist_to_binary(int2list(Int,Base)). + +int2list(Int,Base) when Base < 37 -> + lists:flatten(io_lib:format("~."++integer_to_list(Base)++"B",[Int])). diff --git a/erts/emulator/utils/gen_git_version b/erts/emulator/utils/gen_git_version index d93a97cbbb..ef06a4b8e2 100755 --- a/erts/emulator/utils/gen_git_version +++ b/erts/emulator/utils/gen_git_version @@ -24,8 +24,7 @@ then else VC=unset fi -echo "VSN = $VSN" -echo "VC = $VC" + if test "$VSN" != "$VC" then echo "# Automatically generated by $0 - DO NOT EDIT." > $OUTPUT_FILE |