aboutsummaryrefslogtreecommitdiffstats
path: root/lib/hipe/test/basic_SUITE_data/basic_receive.erl
blob: 20e3f350e88a41be01450007df94910432369d68 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
%%% -*- erlang-indent-level: 2 -*-
%%%-------------------------------------------------------------------
%%% Author: Kostis Sagonas
%%%
%%% Contains code examples that test correct handling of receives.
%%%-------------------------------------------------------------------
-module(basic_receive).

-export([test/0]).

test() ->
  ok = test_wait_timeout(),
  ok = test_double_timeout(),
  ok = test_reschedule(),
  ok = test_recv_mark(),
  ok.

%%--------------------------------------------------------------------

test_wait_timeout() ->
  receive after 42 -> ok end.

%%--------------------------------------------------------------------

test_double_timeout() ->
  self() ! foo,
  self() ! another_foo,
  receive
    non_existent -> weird
  after 0 -> timeout
  end,
  receive
    foo -> ok
  after 1000 -> timeout
  end.

%%--------------------------------------------------------------------
%% Check that RESCHEDULE returns from BIFs work.

test_reschedule() ->
  erts_debug:set_internal_state(available_internal_state, true),
  First = self(),
  Second = spawn(fun() -> doit(First) end),
  receive
    Second -> ok
  end,
  receive
  after 42 -> ok
  end,
  erts_debug:set_internal_state(hipe_test_reschedule_resume, Second),
  ok.

doit(First) ->
  First ! self(),
  erts_debug:set_internal_state(hipe_test_reschedule_suspend, 1).

%%--------------------------------------------------------------------
%% Check that we cannot cause a recv_mark,recv_set pair to misbehave and
%% deadlock the process.

test_recv_mark() ->
  ok = test_recv_mark(fun disturber_nop/0),
  ok = test_recv_mark(fun disturber_receive/0),
  ok = test_recv_mark(fun disturber_other/0),
  ok = test_recv_mark(fun disturber_recurse/0),
  ok = test_recv_mark_after(self(), fun disturber_after_recurse/0, false),
  ok = test_recv_mark(fun disturber_other_recurse/0),
  ok = test_recv_mark(fun disturber_other_after/0),
  ok = test_recv_mark_nested().

test_recv_mark(Disturber) ->
  Ref = make_ref(),
  self() ! Ref,
  Disturber(),
  receive Ref -> ok
  after 0 -> error(failure)
  end.

disturber_nop() -> ok.

disturber_receive() ->
  self() ! message,
  receive message -> ok end.

disturber_other() ->
  Ref = make_ref(),
  self() ! Ref,
  receive Ref -> ok end.

disturber_recurse() ->
  aborted = (catch test_recv_mark(fun() -> throw(aborted) end)),
  ok.

test_recv_mark_after(Recipient, Disturber, IsInner) ->
  Ref = make_ref(),
  Recipient ! Ref,
  Disturber(),
  receive
      Ref -> ok
  after 0 ->
          case IsInner of
              true -> expected;
              false -> error(failure)
          end
  end.

disturber_after_recurse() ->
  NoOp = fun() -> ok end,
  BlackHole = spawn(NoOp),
  expected = test_recv_mark_after(BlackHole, NoOp, true),
  ok.

disturber_other_recurse() ->
  aborted = (catch disturber_other_recurse(fun() -> throw(aborted) end)),
  ok.

disturber_other_recurse(InnerD) ->
  Ref = make_ref(),
  self() ! Ref,
  InnerD(),
  receive Ref -> ok
  after 0 -> error(failure)
  end.

disturber_other_after() ->
  BlackHole = spawn(fun() -> ok end),
  Ref = make_ref(),
  BlackHole ! Ref,
  receive Ref -> error(imposible)
  after 0 -> ok
  end.

test_recv_mark_nested() ->
  Ref1 = make_ref(),
  self() ! Ref1,
  begin
    Ref2 = make_ref(),
    self() ! Ref2,
    receive Ref2 -> ok end
  end,
  receive Ref1 -> ok
  after 0 -> error(failure)
  end.

%%--------------------------------------------------------------------