Skip to content

Commit 219d828

Browse files
committed
Fixes calls to timer:sleep(infinity)
Signed-off-by: Fred Dushin <[email protected]>
1 parent c59671c commit 219d828

File tree

4 files changed

+50
-57
lines changed

4 files changed

+50
-57
lines changed

libs/estdlib/src/timer.erl

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,9 @@
2222

2323
-export([sleep/1]).
2424

25-
-define(MAX_INT, 4294967295).
26-
2725
-spec sleep(non_neg_integer() | infinity) -> ok.
28-
sleep(infinity) ->
29-
receive
30-
'$atomvm_timer_interrupt' ->
31-
{error, unexpected_interrupt}
32-
after ?MAX_INT -> sleep(infinity)
33-
end;
34-
sleep(MSecs) ->
26+
sleep(Timeout) ->
3527
receive
36-
'$atomvm_timer_interrupt' ->
37-
{error, unexpected_interrupt}
38-
after MSecs -> ok
28+
after Timeout ->
29+
ok
3930
end.

src/libAtomVM/opcodesswitch.h

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2120,7 +2120,12 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f
21202120
DECODE_COMPACT_TERM(timeout, code, i, next_off)
21212121

21222122
#ifdef IMPL_EXECUTE_LOOP
2123-
if (!term_is_integer(timeout) && UNLIKELY(timeout != INFINITY_ATOM)) {
2123+
if (term_is_any_integer(timeout)) {
2124+
avm_int64_t t = term_maybe_unbox_int64(timeout);
2125+
if (t < 0 || t > 4294967295L) {
2126+
RAISE_ERROR(TIMEOUT_VALUE_ATOM);
2127+
}
2128+
} else if (UNLIKELY(timeout != INFINITY_ATOM)) {
21242129
RAISE_ERROR(TIMEOUT_VALUE_ATOM);
21252130
}
21262131
TRACE("wait_timeout/2, label: %i, timeout: %li\n", label, (long int) term_to_int32(timeout));
@@ -2137,7 +2142,7 @@ static bool maybe_call_native(Context *ctx, AtomString module_name, AtomString f
21372142
scheduler_set_timeout(ctx, term_to_int32(timeout));
21382143
}
21392144
needs_to_wait = 1;
2140-
} else if ((ctx->flags & WaitingTimeout) == 0) {
2145+
} else if ((ctx->flags & WaitingTimeout) != 0) {
21412146
needs_to_wait = 1;
21422147
} else if (!list_is_empty(&ctx->save_queue)) {
21432148
needs_to_wait = 1;

tests/libs/estdlib/test_timer.erl

Lines changed: 39 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -22,65 +22,62 @@
2222

2323
-export([test/0]).
2424

25+
-include("etest.hrl").
26+
2527
test() ->
2628
ok = test_timer(),
27-
ok = test_timer_interrupt(),
2829
ok = test_timer_loop(),
30+
ok = test_timer_badargs(),
31+
ok = test_infinity(),
2932
ok.
3033

31-
-include("etest.hrl").
32-
3334
test_timer() ->
34-
T0 = erlang:timestamp(),
35+
T0 = erlang:system_time(millisecond),
3536
ok = timer:sleep(101),
36-
T1 = erlang:timestamp(),
37-
ok = etest:assert_true((to_ms(T1) - to_ms(T0)) >= 101),
37+
T1 = erlang:system_time(millisecond),
38+
ok = etest:assert_true((T1 - T0) >= 101),
3839
ok.
3940

40-
test_timer_interrupt() ->
41-
Self = self(),
42-
Pid = spawn(fun() -> do_test_interrupt(Self) end),
43-
receive
44-
ready -> ok
45-
end,
46-
47-
%% this message should not interrupt the timer
48-
Pid ! try_to_interrupt,
49-
50-
Pid ! '$atomvm_timer_interrupt',
51-
?ASSERT_MATCH(pop_mailbox(), ok),
52-
ok.
53-
54-
pop_mailbox() ->
55-
receive
56-
X -> X
57-
end.
58-
59-
do_test_interrupt(Pid) ->
60-
Pid ! ready,
61-
case timer:sleep(infinity) of
62-
{error, unexpected_interrupt} ->
63-
Pid ! ok;
64-
_ ->
65-
Pid ! error
66-
end.
67-
6841
test_timer_loop() ->
6942
Self = self(),
7043
spawn(fun() ->
71-
timer:sleep(220),
72-
Self ! ping
44+
Self ! ready,
45+
timer:sleep(50),
46+
Self ! noise
7347
end),
48+
receive
49+
ready ->
50+
ok
51+
end,
7452
ok = timer_loop(5).
7553

7654
timer_loop(0) ->
77-
ok;
55+
receive
56+
noise ->
57+
ok;
58+
SomethingElse ->
59+
{error, SomethingElse}
60+
end;
7861
timer_loop(I) ->
79-
T0 = erlang:timestamp(),
62+
T0 = erlang:system_time(millisecond),
8063
ok = timer:sleep(101),
81-
T1 = erlang:timestamp(),
82-
ok = etest:assert_true((to_ms(T1) - to_ms(T0)) >= 101),
64+
T1 = erlang:system_time(millisecond),
65+
ok = etest:assert_true((T1 - T0) >= 101),
8366
timer_loop(I - 1).
8467

85-
to_ms({MegaSecs, Secs, MicroSecs}) ->
86-
((MegaSecs * 1000000 + Secs) * 1000 + MicroSecs div 1000).
68+
test_timer_badargs() ->
69+
{'EXIT', {timeout_value, _}} = (catch timer:sleep(-1)),
70+
{'EXIT', {timeout_value, _}} = (catch timer:sleep(4294967295 + 1)),
71+
{'EXIT', {timeout_value, _}} = (catch timer:sleep(not_infinity)),
72+
ok.
73+
74+
test_infinity() ->
75+
Self = self(),
76+
Pid = spawn(fun() ->
77+
Self ! ok,
78+
timer:sleep(infinity)
79+
end),
80+
receive
81+
ok ->
82+
ok = etest:assert_true(erlang:is_process_alive(Pid))
83+
end.

tests/libs/estdlib/tests.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ start() ->
3232
test_io_lib,
3333
test_maps,
3434
test_proplists,
35-
% , test_timer TODO: enable it again, once we try a way to make it less flaky
35+
test_timer,
3636
test_supervisor
3737
]).

0 commit comments

Comments
 (0)