diff options
Diffstat (limited to 'erts/emulator/test')
-rw-r--r-- | erts/emulator/test/atomics_SUITE.erl | 3 | ||||
-rw-r--r-- | erts/emulator/test/bif_SUITE.erl | 54 | ||||
-rw-r--r-- | erts/emulator/test/big_SUITE.erl | 57 | ||||
-rw-r--r-- | erts/emulator/test/driver_SUITE.erl | 17 | ||||
-rw-r--r-- | erts/emulator/test/driver_SUITE_data/chkio_drv.c | 49 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE.erl | 95 | ||||
-rw-r--r-- | erts/emulator/test/nif_SUITE_data/nif_SUITE.c | 25 | ||||
-rw-r--r-- | erts/emulator/test/num_bif_SUITE.erl | 14 | ||||
-rw-r--r-- | erts/emulator/test/persistent_term_SUITE.erl | 80 | ||||
-rw-r--r-- | erts/emulator/test/process_SUITE.erl | 14 | ||||
-rw-r--r-- | erts/emulator/test/scheduler_SUITE.erl | 27 | ||||
-rw-r--r-- | erts/emulator/test/signal_SUITE.erl | 2 | ||||
-rw-r--r-- | erts/emulator/test/system_info_SUITE.erl | 84 |
13 files changed, 405 insertions, 116 deletions
diff --git a/erts/emulator/test/atomics_SUITE.erl b/erts/emulator/test/atomics_SUITE.erl index 8c42354770..a5407c42ee 100644 --- a/erts/emulator/test/atomics_SUITE.erl +++ b/erts/emulator/test/atomics_SUITE.erl @@ -126,6 +126,9 @@ unsigned_limits(Config) when is_list(Config) -> Min = atomics:add_get(Ref, 1, 1), Max = atomics:sub_get(Ref, 1, 1), + atomics:put(Ref, 1, Max), + io:format("Max=~p~n", [atomics:get(Ref, 1)]), + {'EXIT',{badarg,_}} = (catch atomics:add(Ref, 1, Max+1)), IncrMin = -(1 bsl (Bits-1)), ok = atomics:put(Ref, 1, -IncrMin), diff --git a/erts/emulator/test/bif_SUITE.erl b/erts/emulator/test/bif_SUITE.erl index 9e7bcd5255..3eedf2f6a6 100644 --- a/erts/emulator/test/bif_SUITE.erl +++ b/erts/emulator/test/bif_SUITE.erl @@ -37,7 +37,8 @@ group_leader_prio/1, group_leader_prio_dirty/1, is_process_alive/1, process_info_blast/1, - os_env_case_sensitivity/1]). + os_env_case_sensitivity/1, + test_length/1]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -52,7 +53,8 @@ all() -> erl_crash_dump_bytes, min_max, erlang_halt, is_builtin, error_stacktrace, error_stacktrace_during_call_trace, group_leader_prio, group_leader_prio_dirty, - is_process_alive, process_info_blast, os_env_case_sensitivity]. + is_process_alive, process_info_blast, os_env_case_sensitivity, + test_length]. %% Uses erlang:display to test that erts_printf does not do deep recursion display(Config) when is_list(Config) -> @@ -1181,7 +1183,53 @@ consume_msgs() -> after 0 -> ok end. - + +%% Test that length/1 returns the correct result after trapping, and +%% also that the argument is correct in the stacktrace for a badarg +%% exception. + +test_length(_Config) -> + {Start,Inc} = case test_server:timetrap_scale_factor() of + 1 -> {16*4000,3977}; + _ -> {100,1} + end, + Good = lists:reverse(lists:seq(1, Start)), + Bad = Good ++ [bad|cons], + test_length(Start, 10*Start, Inc, Good, Bad), + + %% Test that calling length/1 from a match spec works. + MsList = lists:seq(1, 2*Start), + MsInput = [{tag,Good},{tag,MsList}], + Ms0 = [{{tag,'$1'},[{'>',{length,'$1'},Start}],['$1']}], + Ms = ets:match_spec_compile(Ms0), + [MsList] = ets:match_spec_run(MsInput, Ms), + ok. + +test_length(I, N, Inc, Good, Bad) when I < N -> + Length = id(length), + I = length(Good), + I = erlang:Length(Good), + + %% Test length/1 in guards. + if + length(Good) =:= I -> + ok + end, + if + length(Bad) =:= I -> + error(should_fail); + true -> + ok + end, + + {'EXIT',{badarg,[{erlang,length,[[I|_]],_}|_]}} = (catch length(Bad)), + {'EXIT',{badarg,[{erlang,length,[[I|_]],_}|_]}} = (catch erlang:Length(Bad)), + IncSeq = lists:seq(I + 1, I + Inc), + test_length(I+Inc, N, Inc, + lists:reverse(IncSeq, Good), + lists:reverse(IncSeq, Bad)); +test_length(_, _, _, _, _) -> ok. + %% helpers id(I) -> I. diff --git a/erts/emulator/test/big_SUITE.erl b/erts/emulator/test/big_SUITE.erl index 0a42b09903..3b9b9e5989 100644 --- a/erts/emulator/test/big_SUITE.erl +++ b/erts/emulator/test/big_SUITE.erl @@ -24,7 +24,7 @@ -export([t_div/1, eq_28/1, eq_32/1, eq_big/1, eq_math/1, big_literals/1, borders/1, negative/1, big_float_1/1, big_float_2/1, - bxor_2pow/1, + bxor_2pow/1, band_2pow/1, shift_limit_1/1, powmod/1, system_limit/1, toobig/1, otp_6692/1]). %% Internal exports. @@ -43,7 +43,7 @@ suite() -> all() -> [t_div, eq_28, eq_32, eq_big, eq_math, big_literals, borders, negative, {group, big_float}, shift_limit_1, - bxor_2pow, + bxor_2pow, band_2pow, powmod, system_limit, toobig, otp_6692]. groups() -> @@ -168,7 +168,11 @@ eval({op,_,Op,A0,B0}, LFH) -> Res = eval_op(Op, A, B), erlang:garbage_collect(), Res; -eval({integer,_,I}, _) -> I; +eval({integer,_,I}, _) -> + %% "Parasitic" ("symbiotic"?) test of squaring all numbers + %% found in the test data. + test_squaring(I), + I; eval({call,_,{atom,_,Local},Args0}, LFH) -> Args = eval_list(Args0, LFH), LFH(Local, Args). @@ -192,6 +196,18 @@ eval_op('bxor', A, B) -> A bxor B; eval_op('bsl', A, B) -> A bsl B; eval_op('bsr', A, B) -> A bsr B. +test_squaring(I) -> + %% Multiplying an integer by itself is specially optimized, so we + %% should take special care to test squaring. The optimization + %% will kick in when the two operands have the same address. + Sqr = I * I, + + %% This expression will be multiplied in the usual way, because + %% the the two operands for '*' are stored at different addresses. + Sqr = I * ((I + id(1)) - id(1)), + + ok. + %% Built in test functions fac(0) -> 1; @@ -456,3 +472,38 @@ my_bxor(A, B, N, Acc0) -> false -> Acc0 bor (1 bsl N) end, my_bxor(A bsr 1, B bsr 1, N+1, Acc1). + + +%% ERL-804 +band_2pow(_Config) -> + IL = lists:seq(8*3, 8*16, 4), + JL = lists:seq(0, 64), + [band_2pow_1((1 bsl I), (1 bsl J)) + || I <- IL, J <- JL], + ok. + +band_2pow_1(A, B) -> + for(-1,1, fun(Ad) -> + for(-1,1, fun(Bd) -> + band_2pow_2(A+Ad, B+Bd), + band_2pow_2(-A+Ad, B+Bd), + band_2pow_2(A+Ad, -B+Bd), + band_2pow_2(-A+Ad, -B+Bd) + end) + end). + +band_2pow_2(A, B) -> + Correct = my_band(A, B), + case A band B of + Correct -> ok; + Wrong -> + io:format("~.16# band ~.16#\n", [A,B]), + io:format("Expected ~.16#\n", [Correct]), + io:format("Got ~.16#\n", [Wrong]), + ct:fail({failed, 'band'}) + + end. + +%% Implement band without band +my_band(A, B) -> + bnot ((bnot A) bor (bnot B)). diff --git a/erts/emulator/test/driver_SUITE.erl b/erts/emulator/test/driver_SUITE.erl index 9ffb484eb4..94501dad84 100644 --- a/erts/emulator/test/driver_SUITE.erl +++ b/erts/emulator/test/driver_SUITE.erl @@ -1754,7 +1754,7 @@ smp_select0(Config) -> ProcFun = fun()-> io:format("Worker ~p starting\n",[self()]), Port = open_port({spawn, DrvName}, []), smp_select_loop(Port, 100000), - sleep(1000), % wait for driver to handle pending events + smp_select_done(Port), true = erlang:port_close(Port), Master ! {ok,self()}, io:format("Worker ~p finished\n",[self()]) @@ -1784,6 +1784,21 @@ smp_select_loop(Port, N) -> smp_select_loop(Port, N-1) end. +smp_select_done(Port) -> + case erlang:port_control(Port, ?CHKIO_SMP_SELECT, "done") of + "wait" -> + receive + {Port, done} -> + ok + after 10*1000 -> + %% Seems we have a lost ready_input event. + %% Go ahead anyway, port will crash VM when closed. + ok + end; + + "ok" -> ok + end. + smp_select_wait([], _) -> ok; smp_select_wait(Pids, TimeoutMsg) -> diff --git a/erts/emulator/test/driver_SUITE_data/chkio_drv.c b/erts/emulator/test/driver_SUITE_data/chkio_drv.c index ee8f28e8b1..b9ee155b4b 100644 --- a/erts/emulator/test/driver_SUITE_data/chkio_drv.c +++ b/erts/emulator/test/driver_SUITE_data/chkio_drv.c @@ -90,7 +90,7 @@ typedef struct chkio_smp_select { int next_read; int next_write; int first_write; - enum {Closed, Opened, Selected, Waiting} state; + enum {Closed, Opened, Selected, Waiting, WaitingDone} state; int wasSelected; unsigned rand_state; }ChkioSmpSelect; @@ -292,18 +292,20 @@ stop_steal_aux(ChkioDrvData *cddp) static void free_smp_select(ChkioSmpSelect* pip, ErlDrvPort port) { switch (pip->state) { + case WaitingDone: case Waiting: { int word; - fprintf(stderr, "Closing pipe in state Waiting. Event lost?\n"); + fprintf(stderr, "Closing pipe in state Waiting*. Event lost?\r\n"); for (;;) { int bytes = read(pip->read_fd, &word, sizeof(word)); if (bytes != sizeof(word)) { if (bytes != 0) { - fprintf(stderr, "Failed to read from pipe, bytes=%d, errno=%d\n", bytes, errno); + fprintf(stderr, "Failed to read from pipe, bytes=%d, errno=%d\r\n", + bytes, errno); } break; } - fprintf(stderr, "Read from pipe: %d\n", word); + fprintf(stderr, "Read from pipe: %d\r\n", word); } abort(); } @@ -318,6 +320,8 @@ static void free_smp_select(ChkioSmpSelect* pip, ErlDrvPort port) close(pip->write_fd); pip->state = Closed; break; + case Closed: + break; } driver_free(pip); } @@ -383,6 +387,9 @@ chkio_drv_start(ErlDrvPort port, char *command) cddp->id = driver_mk_port(port); cddp->test = CHKIO_STOP; cddp->test_data = NULL; + + drv_use_singleton.fd_stop_select = -2; /* disable stop_select asserts */ + return (ErlDrvData) cddp; #endif } @@ -526,7 +533,7 @@ chkio_drv_ready_input(ErlDrvData drv_data, ErlDrvEvent event) printf("Read event on uninitiated pipe %d\n", fd); abort(); } - if (pip->state != Selected && pip->state != Waiting) { + if (pip->state != Selected && pip->state != Waiting && pip->state != WaitingDone) { printf("Read event on pipe in strange state %d\n", pip->state); abort(); } @@ -536,9 +543,9 @@ chkio_drv_ready_input(ErlDrvData drv_data, ErlDrvEvent event) inPipe = (pip->next_write - pip->next_read); if (inPipe == 0) { bytes = read(pip->read_fd, &word, sizeof(word)); - printf("Unexpected empty pipe, expected %u -> %u, bytes=%d, word=%d, written=%d\n", - pip->next_read, pip->next_write-1, bytes, word, - (pip->next_write - pip->first_write)); + printf("Unexpected empty pipe: ptr=%p, fds=%d->%d, read bytes=%d, word=%d, written=%d\n", + pip, pip->write_fd, pip->read_fd, + bytes, word, (pip->next_write - pip->first_write)); /*abort(); Allow unexpected events as it's been seen to be triggered by epoll on Linux. Most of the time the unwanted events are filtered by @@ -564,7 +571,20 @@ chkio_drv_ready_input(ErlDrvData drv_data, ErlDrvEvent event) TRACEF(("Read %d from fd=%d\n", word, fd)); pip->next_read++; } - pip->state = Selected; /* not Waiting anymore */ + if (pip->state == WaitingDone) { + if (pip->next_write == pip->next_read) { + /* All data read, send {Port, done} */ + ErlDrvTermData spec[] = {ERL_DRV_PORT, driver_mk_port(cddp->port), + ERL_DRV_ATOM, driver_mk_atom("done"), + ERL_DRV_TUPLE, 2}; + erl_drv_output_term(driver_mk_port(cddp->port), + spec, sizeof(spec) / sizeof(spec[0])); + pip->state = Selected; + } + } + else { + pip->state = Selected; /* not Waiting anymore */ + } break; } case CHKIO_DRV_USE: @@ -962,6 +982,16 @@ chkio_drv_control(ErlDrvData drv_data, } case CHKIO_SMP_SELECT: { ChkioSmpSelect* pip = (ChkioSmpSelect*) cddp->test_data; + if (len == 4 && memcmp(buf, "done", 4) == 0) { + if (pip && pip->state == Waiting) { + pip->state = WaitingDone; + res_str = "wait"; + } + else + res_str = "ok"; + res_len = -1; + break; + } if (pip == NULL) { erl_drv_mutex_lock(smp_pipes_mtx); if (smp_pipes) { @@ -1014,7 +1044,6 @@ chkio_drv_control(ErlDrvData drv_data, if (pip->wasSelected && (op & 1)) { TRACEF(("%T: Close pipe [%d->%d]\n", cddp->id, pip->write_fd, pip->read_fd)); - drv_use_singleton.fd_stop_select = -2; /* disable stop_select asserts */ if (driver_select(cddp->port, (ErlDrvEvent)(ErlDrvSInt)pip->read_fd, DO_READ|ERL_DRV_USE, 0) || close(pip->write_fd)) { diff --git a/erts/emulator/test/nif_SUITE.erl b/erts/emulator/test/nif_SUITE.erl index edad62a9fb..0d0930e124 100644 --- a/erts/emulator/test/nif_SUITE.erl +++ b/erts/emulator/test/nif_SUITE.erl @@ -486,6 +486,7 @@ t_on_load(Config) when is_list(Config) -> -define(ERL_NIF_SELECT_WRITE, (1 bsl 1)). -define(ERL_NIF_SELECT_STOP, (1 bsl 2)). -define(ERL_NIF_SELECT_CANCEL, (1 bsl 3)). +-define(ERL_NIF_SELECT_CUSTOM_MSG, (1 bsl 4)). -define(ERL_NIF_SELECT_STOP_CALLED, (1 bsl 0)). -define(ERL_NIF_SELECT_STOP_SCHEDULED, (1 bsl 1)). @@ -496,100 +497,106 @@ t_on_load(Config) when is_list(Config) -> select(Config) when is_list(Config) -> ensure_lib_loaded(Config), + select_do(0, make_ref(), make_ref(), null), + + RefBin = list_to_binary(lists:duplicate(100, $x)), + [select_do(?ERL_NIF_SELECT_CUSTOM_MSG, + small, {a, tuple, with, "some", RefBin}, MSG_ENV) + || MSG_ENV <- [null, alloc_env]], + ok. + +select_do(Flag, Ref, Ref2, MSG_ENV) -> + io:format("select_do(~p, ~p, ~p)\n", [Ref, Ref2, MSG_ENV]), - Ref = make_ref(), - Ref2 = make_ref(), {{R, R_ptr}, {W, W_ptr}} = pipe_nif(), ok = write_nif(W, <<"hej">>), <<"hej">> = read_nif(R, 3), %% Wait for read eagain = read_nif(R, 3), - 0 = select_nif(R,?ERL_NIF_SELECT_READ,R,null,Ref), + 0 = select_nif(R,?ERL_NIF_SELECT_READ bor Flag, R,null,Ref,MSG_ENV), [] = flush(0), ok = write_nif(W, <<"hej">>), - [{select, R, Ref, ready_input}] = flush(), - 0 = select_nif(R,?ERL_NIF_SELECT_READ,R,self(),Ref2), - [{select, R, Ref2, ready_input}] = flush(), + receive_ready(R, Ref, ready_input), + 0 = select_nif(R,?ERL_NIF_SELECT_READ bor Flag,R,self(),Ref2,MSG_ENV), + receive_ready(R, Ref2, ready_input), Papa = self(), Pid = spawn_link(fun() -> - [{select, R, Ref, ready_input}] = flush(), + receive_ready(R, Ref, ready_input), Papa ! {self(), done} end), - 0 = select_nif(R,?ERL_NIF_SELECT_READ,R,Pid,Ref), + 0 = select_nif(R, ?ERL_NIF_SELECT_READ bor Flag, R, Pid, Ref,MSG_ENV), {Pid, done} = receive_any(1000), %% Cancel read - 0 = select_nif(R,?ERL_NIF_SELECT_READ bor ?ERL_NIF_SELECT_CANCEL,R,null,Ref), + 0 = select_nif(R,?ERL_NIF_SELECT_READ bor ?ERL_NIF_SELECT_CANCEL,R,null,Ref,null), <<"hej">> = read_nif(R, 3), - 0 = select_nif(R,?ERL_NIF_SELECT_READ,R,null,Ref), + 0 = select_nif(R, ?ERL_NIF_SELECT_READ bor Flag, R, null, Ref, MSG_ENV), ?ERL_NIF_SELECT_READ_CANCELLED = - select_nif(R,?ERL_NIF_SELECT_READ bor ?ERL_NIF_SELECT_CANCEL,R,null,Ref), + select_nif(R,?ERL_NIF_SELECT_READ bor ?ERL_NIF_SELECT_CANCEL,R,null,Ref,null), ok = write_nif(W, <<"hej again">>), [] = flush(0), <<"hej again">> = read_nif(R, 9), %% Wait for write Written = write_full(W, $a), - 0 = select_nif(W,?ERL_NIF_SELECT_WRITE,W,self(),Ref), + 0 = select_nif(W, ?ERL_NIF_SELECT_WRITE bor Flag, W, self(), Ref, MSG_ENV), [] = flush(0), Written = read_nif(R,byte_size(Written)), - [{select, W, Ref, ready_output}] = flush(), + receive_ready(W, Ref, ready_output), %% Cancel write - 0 = select_nif(W,?ERL_NIF_SELECT_WRITE bor ?ERL_NIF_SELECT_CANCEL,W,null,Ref), + 0 = select_nif(W, ?ERL_NIF_SELECT_WRITE bor ?ERL_NIF_SELECT_CANCEL, W, null, Ref, null), Written2 = write_full(W, $b), - 0 = select_nif(W,?ERL_NIF_SELECT_WRITE,W,null,Ref), + 0 = select_nif(W, ?ERL_NIF_SELECT_WRITE bor Flag, W, null, Ref, MSG_ENV), ?ERL_NIF_SELECT_WRITE_CANCELLED = - select_nif(W,?ERL_NIF_SELECT_WRITE bor ?ERL_NIF_SELECT_CANCEL,W,null,Ref), + select_nif(W, ?ERL_NIF_SELECT_WRITE bor ?ERL_NIF_SELECT_CANCEL, W, null, Ref, null), Written2 = read_nif(R,byte_size(Written2)), [] = flush(0), %% Close write and wait for EOF eagain = read_nif(R, 1), - check_stop_ret(select_nif(W,?ERL_NIF_SELECT_STOP,W,null,Ref)), + check_stop_ret(select_nif(W, ?ERL_NIF_SELECT_STOP, W, null, Ref, null)), [{fd_resource_stop, W_ptr, _}] = flush(), {1, {W_ptr,_}} = last_fd_stop_call(), true = is_closed_nif(W), [] = flush(0), - 0 = select_nif(R,?ERL_NIF_SELECT_READ,R,self(),Ref), - [{select, R, Ref, ready_input}] = flush(), + 0 = select_nif(R, ?ERL_NIF_SELECT_READ bor Flag, R, self(), Ref, MSG_ENV), + receive_ready(R, Ref, ready_input), eof = read_nif(R,1), - check_stop_ret(select_nif(R,?ERL_NIF_SELECT_STOP,R,null,Ref)), + check_stop_ret(select_nif(R, ?ERL_NIF_SELECT_STOP, R, null, Ref, null)), [{fd_resource_stop, R_ptr, _}] = flush(), {1, {R_ptr,_}} = last_fd_stop_call(), true = is_closed_nif(R), - select_2(Config). + select_2(Flag, Ref, Ref2, MSG_ENV). -select_2(Config) -> +select_2(Flag, Ref1, Ref2, MSG_ENV) -> erlang:garbage_collect(), {_,_,2} = last_resource_dtor_call(), - Ref1 = make_ref(), - Ref2 = make_ref(), {{R, R_ptr}, {W, W_ptr}} = pipe_nif(), %% Change ref eagain = read_nif(R, 1), - 0 = select_nif(R,?ERL_NIF_SELECT_READ,R,null,Ref1), - 0 = select_nif(R,?ERL_NIF_SELECT_READ,R,self(),Ref2), + 0 = select_nif(R, ?ERL_NIF_SELECT_READ bor Flag, R, null, Ref1, MSG_ENV), + 0 = select_nif(R, ?ERL_NIF_SELECT_READ bor Flag, R, self(), Ref2, MSG_ENV), [] = flush(0), ok = write_nif(W, <<"hej">>), - [{select, R, Ref2, ready_input}] = flush(), + receive_ready(R, Ref2, ready_input), <<"hej">> = read_nif(R, 3), %% Change pid eagain = read_nif(R, 1), - 0 = select_nif(R,?ERL_NIF_SELECT_READ,R,null,Ref1), + 0 = select_nif(R, ?ERL_NIF_SELECT_READ bor Flag, R, null, Ref1, MSG_ENV), Papa = self(), spawn_link(fun() -> - 0 = select_nif(R,?ERL_NIF_SELECT_READ,R,null,Ref1), + 0 = select_nif(R, ?ERL_NIF_SELECT_READ bor Flag, R, null, Ref1, MSG_ENV), [] = flush(0), Papa ! sync, - [{select, R, Ref1, ready_input}] = flush(), + receive_ready(R, Ref1, ready_input), <<"hej">> = read_nif(R, 3), Papa ! done end), @@ -598,24 +605,30 @@ select_2(Config) -> done = receive_any(), [] = flush(0), - check_stop_ret(select_nif(R,?ERL_NIF_SELECT_STOP,R,null,Ref1)), + check_stop_ret(select_nif(R,?ERL_NIF_SELECT_STOP,R,null,Ref1, null)), [{fd_resource_stop, R_ptr, _}] = flush(), {1, {R_ptr,_}} = last_fd_stop_call(), true = is_closed_nif(R), %% Stop without previous read/write select - ?ERL_NIF_SELECT_STOP_CALLED = select_nif(W,?ERL_NIF_SELECT_STOP,W,null,Ref1), + ?ERL_NIF_SELECT_STOP_CALLED = select_nif(W,?ERL_NIF_SELECT_STOP,W,null,Ref1,null), [{fd_resource_stop, W_ptr, 1}] = flush(), {1, {W_ptr,1}} = last_fd_stop_call(), true = is_closed_nif(W), - select_3(Config). + select_3(). -select_3(_Config) -> +select_3() -> erlang:garbage_collect(), {_,_,2} = last_resource_dtor_call(), ok. +receive_ready(R, Ref, IOatom) when is_reference(Ref) -> + [{select, R, Ref, IOatom}] = flush(); +receive_ready(_, Msg, _) -> + [Got] = flush(), + {true,_,_} = {Got=:=Msg, Got, Msg}. + %% @doc The stealing child process for the select_steal test. Duplicates given %% W/RFds and runs select on them to steal select_steal_child_process(Parent, RFd) -> @@ -624,7 +637,7 @@ select_steal_child_process(Parent, RFd) -> Ref2 = make_ref(), %% Try to select from the child pid (steal from parent) - ?assertEqual(0, select_nif(R2Fd, ?ERL_NIF_SELECT_READ, R2Fd, null, Ref2)), + ?assertEqual(0, select_nif(R2Fd, ?ERL_NIF_SELECT_READ, R2Fd, null, Ref2, null)), ?assertEqual([], flush(0)), ?assertEqual(eagain, read_nif(R2Fd, 1)), @@ -632,7 +645,7 @@ select_steal_child_process(Parent, RFd) -> Parent ! {self(), stage1}, % signal parent to send the <<"stolen1">> %% Receive <<"stolen1">> via enif_select - ?assertEqual(0, select_nif(R2Fd, ?ERL_NIF_SELECT_READ, R2Fd, null, Ref2)), + ?assertEqual(0, select_nif(R2Fd, ?ERL_NIF_SELECT_READ, R2Fd, null, Ref2, null)), ?assertMatch([{select, R2Fd, Ref2, ready_input}], flush()), ?assertEqual(<<"stolen1">>, read_nif(R2Fd, 7)), @@ -650,7 +663,7 @@ select_steal(Config) when is_list(Config) -> {{RFd, RPtr}, {WFd, WPtr}} = pipe_nif(), %% Bind the socket to current pid in enif_select - ?assertEqual(0, select_nif(RFd, ?ERL_NIF_SELECT_READ, RFd, null, Ref)), + ?assertEqual(0, select_nif(RFd, ?ERL_NIF_SELECT_READ, RFd, null, Ref, null)), ?assertEqual([], flush(0)), %% Spawn a process and do some stealing @@ -664,15 +677,15 @@ select_steal(Config) when is_list(Config) -> ?assertMatch([{Pid, done}], flush(1)), % synchronize with the child %% Try to select from the parent pid (steal back) - ?assertEqual(0, select_nif(RFd, ?ERL_NIF_SELECT_READ, RFd, Pid, Ref)), + ?assertEqual(0, select_nif(RFd, ?ERL_NIF_SELECT_READ, RFd, Pid, Ref, null)), %% Ensure that no data is hanging and close. %% Rfd is stolen at this point. - check_stop_ret(select_nif(WFd, ?ERL_NIF_SELECT_STOP, WFd, null, Ref)), + check_stop_ret(select_nif(WFd, ?ERL_NIF_SELECT_STOP, WFd, null, Ref, null)), ?assertMatch([{fd_resource_stop, WPtr, _}], flush()), {1, {WPtr, 1}} = last_fd_stop_call(), - check_stop_ret(select_nif(RFd, ?ERL_NIF_SELECT_STOP, RFd, null, Ref)), + check_stop_ret(select_nif(RFd, ?ERL_NIF_SELECT_STOP, RFd, null, Ref, null)), ?assertMatch([{fd_resource_stop, RPtr, _}], flush()), {1, {RPtr, _DirectCall}} = last_fd_stop_call(), @@ -3396,7 +3409,7 @@ term_to_binary_nif(_, _) -> ?nif_stub. binary_to_term_nif(_, _, _) -> ?nif_stub. port_command_nif(_, _) -> ?nif_stub. format_term_nif(_,_) -> ?nif_stub. -select_nif(_,_,_,_,_) -> ?nif_stub. +select_nif(_,_,_,_,_,_) -> ?nif_stub. dupe_resource_nif(_) -> ?nif_stub. pipe_nif() -> ?nif_stub. write_nif(_,_) -> ?nif_stub. diff --git a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c index f2ce6dbe67..21af4b05b3 100644 --- a/erts/emulator/test/nif_SUITE_data/nif_SUITE.c +++ b/erts/emulator/test/nif_SUITE_data/nif_SUITE.c @@ -2486,7 +2486,8 @@ static ERL_NIF_TERM select_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv enum ErlNifSelectFlags mode; void* obj; ErlNifPid nifpid, *pid = NULL; - ERL_NIF_TERM ref; + ERL_NIF_TERM ref_or_msg; + ErlNifEnv* msg_env = NULL; int retval; if (!get_fd(env, argv[0], &fdr) @@ -2501,11 +2502,27 @@ static ERL_NIF_TERM select_nif(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv return enif_make_badarg(env); pid = &nifpid; } - ref = argv[4]; + ref_or_msg = argv[4]; + if (argv[5] != atom_null) { + msg_env = enif_alloc_env(); + ref_or_msg = enif_make_copy(msg_env, ref_or_msg); + } fdr->was_selected = 1; enif_self(env, &fdr->pid); - retval = enif_select(env, fdr->fd, mode, obj, pid, ref); + switch (mode) { + case ERL_NIF_SELECT_CUSTOM_MSG | ERL_NIF_SELECT_READ: + retval = enif_select_read(env, fdr->fd, obj, pid, ref_or_msg, msg_env); + break; + case ERL_NIF_SELECT_CUSTOM_MSG | ERL_NIF_SELECT_WRITE: + retval = enif_select_write(env, fdr->fd, obj, pid, ref_or_msg, msg_env); + break; + default: + retval = enif_select(env, fdr->fd, mode, obj, pid, ref_or_msg); + } + + if (msg_env) + enif_free_env(msg_env); return enif_make_int(env, retval); } @@ -3565,7 +3582,7 @@ static ErlNifFunc nif_funcs[] = {"binary_to_term_nif", 3, binary_to_term}, {"port_command_nif", 2, port_command}, {"format_term_nif", 2, format_term}, - {"select_nif", 5, select_nif}, + {"select_nif", 6, select_nif}, #ifndef __WIN32__ {"pipe_nif", 0, pipe_nif}, {"write_nif", 2, write_nif}, diff --git a/erts/emulator/test/num_bif_SUITE.erl b/erts/emulator/test/num_bif_SUITE.erl index f15217814a..6b834705cf 100644 --- a/erts/emulator/test/num_bif_SUITE.erl +++ b/erts/emulator/test/num_bif_SUITE.erl @@ -504,6 +504,10 @@ t_integer_to_string(Config) when is_list(Config) -> test_its("A", 10, 16), test_its("D4BE", 54462, 16), test_its("-D4BE", -54462, 16), + test_its("FFFFFFFFFF", 1099511627775, 16), + test_its("123456789ABCDEF123456789ABCDEF123456789ABCDEF", + 108977460683796539709587792812439445667270661579197935, + 16), lists:foreach(fun(Value) -> {'EXIT', {badarg, _}} = @@ -515,12 +519,14 @@ t_integer_to_string(Config) when is_list(Config) -> ok. test_its(List,Int) -> - Int = list_to_integer(List), - Int = binary_to_integer(list_to_binary(List)). + List = integer_to_list(Int), + Binary = list_to_binary(List), + Binary = integer_to_binary(Int). test_its(List,Int,Base) -> - Int = list_to_integer(List, Base), - Int = binary_to_integer(list_to_binary(List), Base). + List = integer_to_list(Int, Base), + Binary = list_to_binary(List), + Binary = integer_to_binary(Int, Base). %% Tests binary_to_integer/1. diff --git a/erts/emulator/test/persistent_term_SUITE.erl b/erts/emulator/test/persistent_term_SUITE.erl index 58cd3276b0..58038e24b7 100644 --- a/erts/emulator/test/persistent_term_SUITE.erl +++ b/erts/emulator/test/persistent_term_SUITE.erl @@ -21,7 +21,7 @@ -module(persistent_term_SUITE). -include_lib("common_test/include/ct.hrl"). --export([all/0,suite/0, +-export([all/0,suite/0,init_per_suite/1,end_per_suite/1, basic/1,purging/1,sharing/1,get_trapping/1, info/1,info_trapping/1,killed_while_trapping/1, off_heap_values/1,keys/1,collisions/1, @@ -39,39 +39,49 @@ all() -> killed_while_trapping,off_heap_values,keys,collisions, init_restart]. +init_per_suite(Config) -> + %% Put a term in the dict so that we know that the testcases handle + %% stray terms left by stdlib or other test suites. + persistent_term:put(init_per_suite, {?MODULE}), + Config. + +end_per_suite(Config) -> + persistent_term:erase(init_per_suite), + Config. + basic(_Config) -> Chk = chk(), N = 777, Seq = lists:seq(1, N), - par(2, N, Seq), - seq(3, Seq), - seq(3, Seq), %Same values. + par(2, N, Seq, Chk), + seq(3, Seq, Chk), + seq(3, Seq, Chk), %Same values. _ = [begin Key = {?MODULE,{key,I}}, true = persistent_term:erase(Key), false = persistent_term:erase(Key), {'EXIT',{badarg,_}} = (catch persistent_term:get(Key)) end || I <- Seq], - [] = [P || {{?MODULE,_},_}=P <- persistent_term:get()], + [] = [P || {{?MODULE,_},_}=P <- pget(Chk)], chk(Chk). -par(C, N, Seq) -> +par(C, N, Seq, Chk) -> _ = [spawn_link(fun() -> ok = persistent_term:put({?MODULE,{key,I}}, {value,C*I}) end) || I <- Seq], - Result = wait(N), + Result = wait(N, Chk), _ = [begin Double = C*I, {{?MODULE,{key,I}},{value,Double}} = Res end || {I,Res} <- lists:zip(Seq, Result)], ok. -seq(C, Seq) -> +seq(C, Seq, Chk) -> _ = [ok = persistent_term:put({?MODULE,{key,I}}, {value,C*I}) || I <- Seq], - All = persistent_term:get(), - All = [P || {{?MODULE,_},_}=P <- persistent_term:get()], + All = pget(Chk), + All = [P || {{?MODULE,_},_}=P <- All], All = [{Key,persistent_term:get(Key)} || {Key,_} <- All], Result = lists:sort(All), _ = [begin @@ -80,15 +90,15 @@ seq(C, Seq) -> end || {I,Res} <- lists:zip(Seq, Result)], ok. -wait(N) -> - All = [P || {{?MODULE,_},_}=P <- persistent_term:get()], +wait(N, Chk) -> + All = [P || {{?MODULE,_},_}=P <- pget(Chk)], case length(All) of N -> All = [{Key,persistent_term:get(Key)} || {Key,_} <- All], lists:sort(All); _ -> receive after 10 -> ok end, - wait(N) + wait(N, Chk) end. %% Make sure that terms that have been erased are copied into all @@ -200,23 +210,23 @@ get_trapping(_Config) -> _ -> 1000 end, spawn_link(fun() -> get_trapping_create(N) end), - All = do_get_trapping(N, []), + All = do_get_trapping(N, [], Chk), N = get_trapping_check_result(lists:sort(All), 1), erlang:garbage_collect(), get_trapping_erase(N), chk(Chk). -do_get_trapping(N, Prev) -> - case persistent_term:get() of +do_get_trapping(N, Prev, Chk) -> + case pget(Chk) of Prev when length(Prev) >= N -> All = [P || {{?MODULE,{get_trapping,_}},_}=P <- Prev], case length(All) of N -> All; - _ -> do_get_trapping(N, Prev) + _ -> do_get_trapping(N, Prev, Chk) end; New -> receive after 1 -> ok end, - do_get_trapping(N, New) + do_get_trapping(N, New, Chk) end. get_trapping_create(0) -> @@ -331,25 +341,25 @@ info_trapping(_Config) -> _ -> 1000 end, spawn_link(fun() -> info_trapping_create(N) end), - All = do_info_trapping(N, 0), + All = do_info_trapping(N, 0, Chk), N = info_trapping_check_result(lists:sort(All), 1), erlang:garbage_collect(), info_trapping_erase(N), chk(Chk). -do_info_trapping(N, PrevMem) -> +do_info_trapping(N, PrevMem, Chk) -> case info_info() of - {N,Mem} -> + {M,Mem} when M >= N -> true = Mem >= PrevMem, - All = [P || {{?MODULE,{info_trapping,_}},_}=P <- persistent_term:get()], + All = [P || {{?MODULE,{info_trapping,_}},_}=P <- pget(Chk)], case length(All) of N -> All; - _ -> do_info_trapping(N, PrevMem) + _ -> do_info_trapping(N, PrevMem, Chk) end; {_,Mem} -> true = Mem >= PrevMem, receive after 1 -> ok end, - do_info_trapping(N, Mem) + do_info_trapping(N, Mem, Chk) end. info_trapping_create(0) -> @@ -462,17 +472,17 @@ collisions(_Config) -> _ = [V = persistent_term:get(K) || {K,V} <- Kvs], %% Now delete the persistent terms in random order. - collisions_delete(lists:keysort(2, Kvs)), + collisions_delete(lists:keysort(2, Kvs), Chk), chk(Chk). -collisions_delete([{Key,Val}|Kvs]) -> +collisions_delete([{Key,Val}|Kvs], Chk) -> Val = persistent_term:get(Key), true = persistent_term:erase(Key), - true = lists:sort(persistent_term:get()) =:= lists:sort(Kvs), + true = lists:sort(pget(Chk)) =:= lists:sort(Kvs), _ = [V = persistent_term:get(K) || {K,V} <- Kvs], - collisions_delete(Kvs); -collisions_delete([]) -> + collisions_delete(Kvs, Chk); +collisions_delete([], _) -> ok. colliding_keys() -> @@ -589,15 +599,16 @@ do_test_init_restart_cmd(File) -> %% and after each test case. chk() -> - persistent_term:info(). + {persistent_term:info(), persistent_term:get()}. -chk(Chk) -> - Chk = persistent_term:info(), +chk({Info, _Initial} = Chk) -> + Info = persistent_term:info(), Key = {?MODULE,?FUNCTION_NAME}, - ok = persistent_term:put(Key, {term,Chk}), + ok = persistent_term:put(Key, {term,Info}), Term = persistent_term:get(Key), true = persistent_term:erase(Key), chk_not_stuck(Term), + [persistent_term:erase(K) || {K, _} <- pget(Chk)], ok. chk_not_stuck(Term) -> @@ -612,3 +623,6 @@ chk_not_stuck(Term) -> _ -> ok end. + +pget({_, Initial}) -> + persistent_term:get() -- Initial. diff --git a/erts/emulator/test/process_SUITE.erl b/erts/emulator/test/process_SUITE.erl index f4b1d885fe..edf08ce0bd 100644 --- a/erts/emulator/test/process_SUITE.erl +++ b/erts/emulator/test/process_SUITE.erl @@ -2104,6 +2104,13 @@ spawn_opt_max_heap_size(_Config) -> error_logger:add_report_handler(?MODULE, self()), + %% flush any prior messages in error_logger + Pid = spawn(fun() -> ok = nok end), + receive + {error, _, {emulator, _, [Pid|_]}} -> + flush() + end, + %% Test that numerical limit works max_heap_size_test(1024, 1024, true, true), @@ -2208,6 +2215,13 @@ receive_unexpected() -> ok end. +flush() -> + receive + _M -> flush() + after 0 -> + ok + end. + %% error_logger report handler proxy init(Pid) -> {ok, Pid}. diff --git a/erts/emulator/test/scheduler_SUITE.erl b/erts/emulator/test/scheduler_SUITE.erl index f04efb9003..2e0dfa42f3 100644 --- a/erts/emulator/test/scheduler_SUITE.erl +++ b/erts/emulator/test/scheduler_SUITE.erl @@ -1450,26 +1450,29 @@ poll_threads(Config) when is_list(Config) -> {Conc, PollType, KP} = get_ioconfig(Config), {Sched, SchedOnln, _} = get_sstate(Config, ""), - [1, 1] = get_ionum(Config,"+IOt 2 +IOp 2"), - [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 5"), - - [1, 1] = get_ionum(Config, "+S 2 +IOPt 100 +IOPp 100"), - if Conc -> - [5] = get_ionum(Config,"+IOt 5 +IOp 1"), - [3, 2] = get_ionum(Config,"+IOt 5 +IOp 2"), - [2, 2, 2, 2, 2] = get_ionum(Config,"+IOt 10 +IOPp 50"), + [1, 1, 1] = get_ionum(Config,"+IOt 2 +IOp 2"), + [1, 1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 5"), + [1, 1, 1] = get_ionum(Config, "+S 2 +IOPt 100 +IOPp 100"), - [2] = get_ionum(Config, "+S 2 +IOPt 100"), - [4] = get_ionum(Config, "+S 4 +IOPt 100"), - [4] = get_ionum(Config, "+S 4:2 +IOPt 100"), - [4, 4] = get_ionum(Config, "+S 8 +IOPt 100 +IOPp 25"), + [5, 1] = get_ionum(Config,"+IOt 5 +IOp 1"), + [3, 2, 1] = get_ionum(Config,"+IOt 5 +IOp 2"), + [2, 2, 2, 2, 2, 1] = get_ionum(Config,"+IOt 10 +IOPp 50"), + + [2, 1] = get_ionum(Config, "+S 2 +IOPt 100"), + [4, 1] = get_ionum(Config, "+S 4 +IOPt 100"), + [4, 1] = get_ionum(Config, "+S 4:2 +IOPt 100"), + [4, 4, 1] = get_ionum(Config, "+S 8 +IOPt 100 +IOPp 25"), fail = get_ionum(Config, "+IOt 1 +IOp 2"), ok; not Conc -> + [1, 1] = get_ionum(Config,"+IOt 2 +IOp 2"), + [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 5"), + [1, 1] = get_ionum(Config, "+S 2 +IOPt 100 +IOPp 100"), + [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 1"), [1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 5 +IOp 2"), [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] = get_ionum(Config,"+IOt 10 +IOPp 50"), diff --git a/erts/emulator/test/signal_SUITE.erl b/erts/emulator/test/signal_SUITE.erl index fab2f45f28..4e6baa9e0e 100644 --- a/erts/emulator/test/signal_SUITE.erl +++ b/erts/emulator/test/signal_SUITE.erl @@ -85,7 +85,7 @@ xm_sig_order_proc() -> receive may_not_reach -> exit(bad_signal_order); may_reach -> ok - after 0 -> ok + after 0 -> erlang:yield() end, xm_sig_order_proc(). diff --git a/erts/emulator/test/system_info_SUITE.erl b/erts/emulator/test/system_info_SUITE.erl index 8ea2d88ec4..55b1162cfb 100644 --- a/erts/emulator/test/system_info_SUITE.erl +++ b/erts/emulator/test/system_info_SUITE.erl @@ -37,8 +37,9 @@ -export([process_count/1, system_version/1, misc_smoke_tests/1, heap_size/1, wordsize/1, memory/1, ets_limit/1, atom_limit/1, - ets_count/1, - atom_count/1]). + ets_count/1, atom_count/1, system_logger/1]). + +-export([init/1, handle_event/2, handle_call/2]). suite() -> [{ct_hooks,[ts_install_cth]}, @@ -46,8 +47,8 @@ suite() -> all() -> [process_count, system_version, misc_smoke_tests, - ets_count, - heap_size, wordsize, memory, ets_limit, atom_limit, atom_count]. + ets_count, heap_size, wordsize, memory, ets_limit, atom_limit, atom_count, + system_logger]. %%% %%% The test cases ------------------------------------------------------------- @@ -578,3 +579,78 @@ atom_count(Config) when is_list(Config) -> true = Limit >= Count2, true = Count2 > Count1, ok. + + +system_logger(Config) when is_list(Config) -> + + TC = self(), + + ok = error_logger:add_report_handler(?MODULE, [TC]), + + generate_log_event(), + + flush(1, report_handler), + + Initial = erlang:system_info(system_logger), + + {Logger,_} = spawn_monitor(fun F() -> receive M -> TC ! {system_logger,M}, F() end end), + + Initial = erlang:system_flag(system_logger, Logger), + Logger = erlang:system_info(system_logger), + + generate_log_event(), + flush(1, system_logger), + + Logger = erlang:system_flag(system_logger, Logger), + + generate_log_event(), + flush(1, system_logger), + + exit(Logger, die), + receive {'DOWN',_,_,_,_} -> ok end, + + generate_log_event(), + flush(1, report_handler), + + logger = erlang:system_info(system_logger), + + logger = erlang:system_flag(system_logger, undefined), + generate_log_event(), + flush(), + + undefined = erlang:system_flag(system_logger, Initial), + + ok. + +flush() -> + receive + M -> + ct:fail({unexpected_message, M}) + after 0 -> + ok + end. + +flush(0, _Pat) -> + flush(); +flush(Cnt, Pat) -> + receive + M when element(1,M) =:= Pat -> + ct:log("~p",[M]), + flush(Cnt-1, Pat) + after 500 -> + ct:fail({missing, Cnt, Pat}) + end. + +generate_log_event() -> + {_Pid, Ref} = spawn_monitor(fun() -> ok = nok end), + receive {'DOWN', Ref, _, _, _} -> ok end. + +init([To]) -> + {ok, To}. + +handle_call(Msg, State) -> + {ok, Msg, State}. + +handle_event(Event, State) -> + State ! {report_handler, Event}, + {ok, State}. |