Skip to content

Instantly share code, notes, and snippets.

@potatosalad
Last active August 25, 2018 19:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save potatosalad/05f5189790cda6c966cf1dac73eab25a to your computer and use it in GitHub Desktop.
Save potatosalad/05f5189790cda6c966cf1dac73eab25a to your computer and use it in GitHub Desktop.
Possible race condition in Concuerror with ETS

Concuerror (version 0.20.0+build.2149.refc040b0d):

./concuerror --pa "$(exenv prefix)/lib/elixir/ebin" -m registry_example -t test --treat_as_normal=killed --treat_as_normal=shutdown --show_races=true --graph=registry_example.dot

Example failure:

* Stop testing on first error. (Check '-h keep_going').
* On step 58, replaying a built-in returned a different result than expected:
  original:
    <0.146.0>: true = ets:insert_new(#Ref<0.3679684042.689831937.49405>, {<<116,101,115,116>>,{<0.146.0>,nil}})
    in registry.ex line 911
  new:
    <0.146.0>: false = ets:insert_new(#Ref<0.3679684042.689831937.49405>, {<<116,101,115,116>>,{<0.146.0>,nil}})
    in registry.ex line 911

Please notify the developers, as this is a bug of Concuerror.
Concuerror 0.20.0+build.2149.refc040b0d started at 25 Aug 2018 13:51:10
Options:
[{after_timeout,infinity},
{assertions_only,false},
{assume_racing,true},
{depth_bound,500},
{disable_sleep_sets,false},
{dpor,optimal},
{entry_point,{registry_example,test,[]}},
{exclude_module,[]},
{first_process_errors_only,false},
{ignore_error,[]},
{instant_delivery,true},
{interleaving_bound,infinity},
{keep_going,false},
{non_racing_system,[]},
{pa,"/Users/andrew.bennett/.exenv/versions/1.7.3/lib/elixir/ebin"},
{print_depth,20},
{scheduling,round_robin},
{scheduling_bound_type,none},
{show_races,true},
{strict_scheduling,false},
{symbolic_names,true},
{timeout,5000},
{treat_as_normal,[killed,shutdown]},
{use_receive_patterns,true}]
################################################################################
Interleaving #1
--------------------------------------------------------------------------------
New races found:
* 28: <P.2>: true = ets:insert_new(#Ref<0.3679684042.689831937.49405>, {<<116,101,115,116>>,{<P.2>,nil}})
33: <P.3>: false = ets:insert_new(#Ref<0.3679684042.689831937.49405>, {<<116,101,115,116>>,{<P.3>,nil}})
* 29: <P.2>: {#Ref<0.3679684042.689700865.48780>,<P.2>,yes} = erlang:send(<P>, {#Ref<0.3679684042.689700865.48780>,<P.2>,yes})
39: <P.3>: {#Ref<0.3679684042.689700865.48780>,<P.3>,no} = erlang:send(<P>, {#Ref<0.3679684042.689700865.48780>,<P.3>,no})
* 54: <P.1.1>: 1 = ets:internal_select_delete(#Ref<0.3679684042.689831937.49405>, [{{<<116,101,115,116>>,{<P.2>,'_'}},[],[true]}])
63: <P>: {<P.3>,nil} = ets:lookup_element(#Ref<0.3679684042.689831937.49405>, <<116,101,115,116>>, 2)
* 69: <P.3>: true = erlang:exit(<P.1.1>, normal)
79: <P.1/Elixir.Registry.ViaTest>: true = erlang:exit(<P.1.1>, kill)
* 79: <P.1/Elixir.Registry.ViaTest>: true = erlang:exit(<P.1.1>, kill)
80: <P.1.1>: exits abnormally (killed)
################################################################################
Interleaving #2
--------------------------------------------------------------------------------
New races found:
* 69: <P.3>: true = erlang:exit(<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>, normal)
77: <P.1/Elixir.Registry.ViaTest>: true = erlang:exit(<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>, shutdown)
* 78: <P.1>: receive timeout expired after 5000 ms
89: <P.1.1>: {'DOWN',#Ref<0.3679684042.689700865.49662>,process,<P.1.1>,shutdown} = erlang:send(<P.1>, {'DOWN',#Ref<0.3679684042.689700865.49662>,process,<P.1.1>,shutdown})
* 84: <P.1.1>: exits abnormally (shutdown)
90: <P.1>: true = erlang:exit(<P.1.1>, kill)
################################################################################
Interleaving #3
--------------------------------------------------------------------------------
New races found:
* 82: <P.1.1/Elixir.Registry.ViaTest.PIDPartition0>: receives message ({'EXIT',<P.1/Elixir.Registry.ViaTest>,shutdown})
84: <P.1/Elixir.Registry.ViaTest>: true = erlang:exit(<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>, kill)
################################################################################
Interleaving #4
--------------------------------------------------------------------------------
New races found:
* 81: <P.1.1/Elixir.Registry.ViaTest.PIDPartition0>: 1 = ets:internal_select_delete(#Ref<0.3679684042.689831937.49405>, [{{<<116,101,115,116>>,{<P.3>,'_'}},[],[true]}])
82: <P.1/Elixir.Registry.ViaTest>: true = erlang:exit(<P.1.1>, kill)
################################################################################
Interleaving #5
--------------------------------------------------------------------------------
New races found:
* 80: <P.1.1>: [{<P.3>,<<116,101,115,116>>,#Ref<0.3679684042.689831937.49405>}] = ets:take(#Ref<0.3679684042.689831937.49408>, <P.3>)
81: <P.1>: true = erlang:exit(<P.1.1>, kill)
################################################################################
Interleaving #9
--------------------------------------------------------------------------------
New races found:
* 77: <P.1/Elixir.Registry.ViaTest>: receive timeout expired after 5000 ms
86: <P.1.1/Elixir.Registry.ViaTest.PIDPartition0>: {'DOWN',#Ref<0.3679684042.689700865.49662>,process,<P.1.1>,shutdown} = erlang:send(<P.1/Elixir.Registry.ViaTest>, {'DOWN',#Ref<0.3679684042.689700865.49662>,process,<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>,shutdown})
* 81: <P.1.1>: exits abnormally (shutdown)
87: <P.1>: true = erlang:exit(<P.1.1>, kill)
################################################################################
Interleaving #10
--------------------------------------------------------------------------------
New races found:
* 78: <P.3>: true = erlang:exit(<P.1.1>, normal)
81: <P.1/Elixir.Registry.ViaTest>: true = erlang:exit(<P.1.1>, kill)
################################################################################
Interleaving #13
--------------------------------------------------------------------------------
Errors found:
* Concuerror crashed
--------------------------------------------------------------------------------
Event trace:
1: <P>: false = erlang:process_flag(trap_exit, true)
2: <P>: #Ref<0.3679684042.689700865.48780> = erlang:make_ref()
in registry_example.ex line 14
3: <P>: undefined = erlang:whereis('Elixir.Registry.ViaTest')
in gen.erl line 266
4: <P>: [] = erlang:process_info(<P>, registered_name)
in proc_lib.erl line 736
5: <P>: <P.1/Elixir.Registry.ViaTest> = erlang:spawn_opt({proc_lib,init_p,[<P>,[],gen,init_it,[gen_server,<P>,<P>,{local,'Elixir.Registry.ViaTest'},supervisor,{{local,'Elixir.Registry.ViaTest'},'Elixir.Registry.Supervisor',{unique,'Elixir.Registry.ViaTest',...}},[]]],[link]})
in erlang.erl line 2963
6: <P.1/Elixir.Registry.ViaTest>: true = erlang:register('Elixir.Registry.ViaTest', <P.1/Elixir.Registry.ViaTest>)
in gen.erl line 269
7: <P.1/Elixir.Registry.ViaTest>: false = erlang:process_flag(trap_exit, true)
in supervisor.erl line 294
8: <P.1/Elixir.Registry.ViaTest>: 'Elixir.Registry.ViaTest' = ets:new('Elixir.Registry.ViaTest', [set,public,named_table,{read_concurrency,true}])
in registry.ex line 1179
9: <P.1/Elixir.Registry.ViaTest>: true = ets:insert('Elixir.Registry.ViaTest', [{-1,{unique,1,nil,nil,[]}},{-2,{unique,1,nil}}])
in registry.ex line 1180
10: <P.1/Elixir.Registry.ViaTest>: undefined = erlang:whereis('Elixir.Registry.ViaTest.PIDPartition0')
in gen.erl line 266
11: <P.1/Elixir.Registry.ViaTest>: {registered_name,'Elixir.Registry.ViaTest'} = erlang:process_info(<P.1/Elixir.Registry.ViaTest>, registered_name)
in proc_lib.erl line 736
12: <P.1/Elixir.Registry.ViaTest>: <P.1.1/Elixir.Registry.ViaTest.PIDPartition0> = erlang:spawn_opt({proc_lib,init_p,['Elixir.Registry.ViaTest',[<P>],gen,init_it,[gen_server,<P.1/Elixir.Registry.ViaTest>,<P.1/Elixir.Registry.ViaTest>,{local,'Elixir.Registry.ViaTest.PIDPartition0'},'Elixir.Registry.Partition',{unique,'Elixir.Registry.ViaTest',0,1,'Elixir.Registry.ViaTest.KeyPartition0',...},[]]],[link]})
in erlang.erl line 2963
13: <P.1.1/Elixir.Registry.ViaTest.PIDPartition0>: true = erlang:register('Elixir.Registry.ViaTest.PIDPartition0', <P.1.1/Elixir.Registry.ViaTest.PIDPartition0>)
in gen.erl line 269
14: <P.1.1/Elixir.Registry.ViaTest.PIDPartition0>: false = erlang:process_flag(trap_exit, true)
in registry.ex line 1243
15: <P.1.1/Elixir.Registry.ViaTest.PIDPartition0>: #Ref<0.3679684042.689831937.49405> = ets:new('Elixir.Registry.ViaTest.KeyPartition0', [set,public,{read_concurrency,true},{write_concurrency,true}])
in registry.ex line 1266
16: <P.1.1/Elixir.Registry.ViaTest.PIDPartition0>: #Ref<0.3679684042.689831937.49408> = ets:new('Elixir.Registry.ViaTest.PIDPartition0', [duplicate_bag,public,{read_concurrency,true},{write_concurrency,true}])
in registry.ex line 1281
17: <P.1.1/Elixir.Registry.ViaTest.PIDPartition0>: true = ets:insert('Elixir.Registry.ViaTest', [{-2,{unique,1,#Ref<0.3679684042.689831937.49405>}},{-1,{unique,1,#Ref<0.3679684042.689831937.49405>,{<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>,#Ref<0.3679684042.689831937.49408>},[]}}])
in registry.ex line 1255
18: <P.1.1/Elixir.Registry.ViaTest.PIDPartition0>: {ack,<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>,{ok,<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>}} = <P.1/Elixir.Registry.ViaTest> ! {ack,<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>,{ok,<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>}}
in proc_lib.erl line 394
19: <P.1/Elixir.Registry.ViaTest>: receives message ({ack,<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>,{ok,<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>}})
in proc_lib.erl line 350
20: <P.1/Elixir.Registry.ViaTest>: [{supervisor,{5,cached}}] = ets:lookup(logger, supervisor)
in logger_config.erl line 42
21: <P.1/Elixir.Registry.ViaTest>: {ack,<P.1/Elixir.Registry.ViaTest>,{ok,<P.1/Elixir.Registry.ViaTest>}} = <P> ! {ack,<P.1/Elixir.Registry.ViaTest>,{ok,<P.1/Elixir.Registry.ViaTest>}}
in proc_lib.erl line 394
22: <P>: receives message ({ack,<P.1/Elixir.Registry.ViaTest>,{ok,<P.1/Elixir.Registry.ViaTest>}})
in proc_lib.erl line 350
23: <P>: <P.2> = erlang:spawn_link(erlang, apply, [#Fun<registry_example.1.11980870>,[]])
in erlang.erl line 2803
24: <P>: <P.3> = erlang:spawn_link(erlang, apply, [#Fun<registry_example.2.11980870>,[]])
in erlang.erl line 2803
25: <P.2>: {unique,1,#Ref<0.3679684042.689831937.49405>,{<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>,#Ref<0.3679684042.689831937.49408>},[]} = ets:lookup_element('Elixir.Registry.ViaTest', -1, 2)
in registry.ex line 1113
26: <P.2>: true = erlang:link(<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>)
in registry.ex line 884
27: <P.2>: true = ets:insert(#Ref<0.3679684042.689831937.49408>, {<P.2>,<<116,101,115,116>>,#Ref<0.3679684042.689831937.49405>})
in registry.ex line 885
28: <P.2>: true = ets:insert_new(#Ref<0.3679684042.689831937.49405>, {<<116,101,115,116>>,{<P.2>,nil}})
in registry.ex line 911
29: <P.2>: {#Ref<0.3679684042.689700865.48780>,<P.2>,yes} = erlang:send(<P>, {#Ref<0.3679684042.689700865.48780>,<P.2>,yes})
30: <P.3>: {unique,1,#Ref<0.3679684042.689831937.49405>,{<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>,#Ref<0.3679684042.689831937.49408>},[]} = ets:lookup_element('Elixir.Registry.ViaTest', -1, 2)
in registry.ex line 1113
31: <P.3>: true = erlang:link(<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>)
in registry.ex line 884
32: <P.3>: true = ets:insert(#Ref<0.3679684042.689831937.49408>, {<P.3>,<<116,101,115,116>>,#Ref<0.3679684042.689831937.49405>})
in registry.ex line 885
33: <P.3>: false = ets:insert_new(#Ref<0.3679684042.689831937.49405>, {<<116,101,115,116>>,{<P.3>,nil}})
in registry.ex line 911
34: <P.3>: [{<<116,101,115,116>>,{<P.2>,nil}}] = ets:lookup(#Ref<0.3679684042.689831937.49405>, <<116,101,115,116>>)
in registry.ex line 916
35: <P.3>: true = erlang:is_process_alive(<P.2>)
in registry.ex line 918
36: <P.3>: true = ets:delete_object(#Ref<0.3679684042.689831937.49408>, {<P.3>,<<116,101,115,116>>,#Ref<0.3679684042.689831937.49405>})
in registry.ex line 899
37: <P.3>: false = ets:member(#Ref<0.3679684042.689831937.49408>, <P.3>)
in registry.ex line 1163
38: <P.3>: true = erlang:unlink(<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>)
in registry.ex line 1164
39: <P.3>: {#Ref<0.3679684042.689700865.48780>,<P.3>,no} = erlang:send(<P>, {#Ref<0.3679684042.689700865.48780>,<P.3>,no})
40: <P>: receives message ({#Ref<0.3679684042.689700865.48780>,<P.2>,yes})
in registry_example.ex line 196
41: <P>: {unique,1,#Ref<0.3679684042.689831937.49405>} = ets:lookup_element('Elixir.Registry.ViaTest', -2, 2)
in registry.ex line 1122
42: <P>: {<P.2>,nil} = ets:lookup_element(#Ref<0.3679684042.689831937.49405>, <<116,101,115,116>>, 2)
in registry.ex line 1147
43: <P>: true = erlang:is_process_alive(<P.2>)
in registry.ex line 194
44: <P>: receives message ({#Ref<0.3679684042.689700865.48780>,<P.3>,no})
in registry_example.ex line 196
45: <P>: {#Ref<0.3679684042.689700865.48780>,stop} = erlang:send(<P.2>, {#Ref<0.3679684042.689700865.48780>,stop})
46: <P.2>: receives message ({#Ref<0.3679684042.689700865.48780>,stop})
in registry_example.ex line 196
47: <P.2>: exits normally
48: <P.2>: true = erlang:exit(<P>, normal)
(while exiting)
49: <P.2>: true = erlang:exit(<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>, normal)
(while exiting)
50: <P>: receives message ({'EXIT',<P.2>,normal})
in registry_example.ex line 196
51: <P>: {#Ref<0.3679684042.689700865.48780>,<P>,register} = erlang:send(<P.3>, {#Ref<0.3679684042.689700865.48780>,<P>,register})
52: <P.1.1/Elixir.Registry.ViaTest.PIDPartition0>: receives message ({'EXIT',<P.2>,normal})
in gen_server.erl line 403
53: <P.1.1/Elixir.Registry.ViaTest.PIDPartition0>: [{<P.2>,<<116,101,115,116>>,#Ref<0.3679684042.689831937.49405>}] = ets:take(#Ref<0.3679684042.689831937.49408>, <P.2>)
in registry.ex line 1294
54: <P.3>: receives message ({#Ref<0.3679684042.689700865.48780>,<P>,register})
in registry_example.ex line 196
55: <P.3>: {unique,1,#Ref<0.3679684042.689831937.49405>,{<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>,#Ref<0.3679684042.689831937.49408>},[]} = ets:lookup_element('Elixir.Registry.ViaTest', -1, 2)
in registry.ex line 1113
56: <P.3>: true = erlang:link(<P.1.1/Elixir.Registry.ViaTest.PIDPartition0>)
in registry.ex line 884
57: <P.3>: true = ets:insert(#Ref<0.3679684042.689831937.49408>, {<P.3>,<<116,101,115,116>>,#Ref<0.3679684042.689831937.49405>})
in registry.ex line 885
################################################################################
Exploration completed!
################################################################################
Errors:
--------------------------------------------------------------------------------
* Stop testing on first error. (Check '-h keep_going').
* On step 58, replaying a built-in returned a different result than expected:
original:
<0.146.0>: true = ets:insert_new(#Ref<0.3679684042.689831937.49405>, {<<116,101,115,116>>,{<0.146.0>,nil}})
in registry.ex line 911
new:
<0.146.0>: false = ets:insert_new(#Ref<0.3679684042.689831937.49405>, {<<116,101,115,116>>,{<0.146.0>,nil}})
in registry.ex line 911
Please notify the developers, as this is a bug of Concuerror.
################################################################################
Warnings:
--------------------------------------------------------------------------------
* Some abnormal exit reasons were treated as normal ('--treat_as_normal').
################################################################################
Tips:
--------------------------------------------------------------------------------
* Running without a scheduling_bound corresponds to verification and may take a long time.
* Increase '--print_depth' if output/graph contains "...".
* An abnormal exit signal killed a process. This is probably the worst thing that can happen race-wise, as any other side-effecting operation races with the arrival of the signal. If the test produces too many interleavings consider refactoring your code.
################################################################################
Info:
--------------------------------------------------------------------------------
* Showing progress (-h progress, for details)
* Writing results in concuerror_report.txt
* Writing graph in registry_example.dot
* Automatically instrumented module io_lib
* Showing PIDs as "<symbolic name(/last registered name)>" ('-h symbolic_names').
* Automatically instrumented module registry_example
* Automatically instrumented module 'Elixir.Registry'
* Automatically instrumented module 'Elixir.Keyword'
* Automatically instrumented module 'Elixir.Enum'
* Automatically instrumented module 'Elixir.Registry.Supervisor'
* Automatically instrumented module 'Elixir.Supervisor'
* Automatically instrumented module supervisor
* Automatically instrumented module gen_server
* Automatically instrumented module gen
* Automatically instrumented module proc_lib
* Automatically instrumented module erlang
* Automatically instrumented module 'Elixir.Range'
* Automatically instrumented module 'Elixir.Registry.Partition'
* Automatically instrumented module 'Elixir.Module'
* Automatically instrumented module elixir_aliases
* Automatically instrumented module 'Elixir.Supervisor.Spec'
* Automatically instrumented module lists
* Automatically instrumented module 'Elixir.Access'
* Automatically instrumented module 'Elixir.GenServer'
* Automatically instrumented module logger
* Automatically instrumented module logger_config
* Automatically instrumented module ets
* Automatically instrumented module logger_backend
* Automatically instrumented module maps
* Automatically instrumented module error_logger
################################################################################
Done at 25 Aug 2018 13:53:13 (Exit status: fail)
Summary: 1 errors, 13/15 interleavings explored
defmodule :registry_example do
def testn(0) do
:ok
end
def testn(n) when is_integer(n) and n > 0 do
:ok = test()
testn(n - 1)
end
def test() do
_ = :erlang.process_flag(:trap_exit, true)
parent = self()
tag = make_ref()
{:ok, registry_pid} = Registry.start_link(keys: :unique, name: Registry.ViaTest)
child1_pid =
spawn_link(fn ->
# NOTE: remove this line when testing with Concuerror
# :erlang.yield()
case Registry.register_name({Registry.ViaTest, "test"}, self()) do
:yes ->
_ = send(parent, {tag, self(), :yes})
# NOTE: remove this line when testing with Concuerror
# :io.format('~p child 1 yes~n', [tag])
case receive_once() do
{^tag, :stop} ->
exit(:normal)
end
:no ->
_ = send(parent, {tag, self(), :no})
case receive_once() do
{^tag, ^parent, :register} ->
:yes = Registry.register_name({Registry.ViaTest, "test"}, self())
_ = send(parent, {tag, self(), :yes})
case receive_once() do
{^tag, :stop} ->
exit(:normal)
end
end
end
end)
child2_pid =
spawn_link(fn ->
# NOTE: remove this line when testing with Concuerror
# :erlang.yield()
case Registry.register_name({Registry.ViaTest, "test"}, self()) do
:yes ->
_ = send(parent, {tag, self(), :yes})
# NOTE: remove this line when testing with Concuerror
# :io.format('~p child 2 yes~n', [tag])
case receive_once() do
{^tag, :stop} ->
exit(:normal)
end
:no ->
_ = send(parent, {tag, self(), :no})
case receive_once() do
{^tag, ^parent, :register} ->
:yes = Registry.register_name({Registry.ViaTest, "test"}, self())
_ = send(parent, {tag, self(), :yes})
case receive_once() do
{^tag, :stop} ->
exit(:normal)
end
end
end
end)
case receive_once() do
{^tag, ^child1_pid, :yes} ->
^child1_pid = Registry.whereis_name({Registry.ViaTest, "test"})
case receive_once() do
{^tag, ^child2_pid, :no} ->
_ = send(child1_pid, {tag, :stop})
case receive_once() do
{:EXIT, ^child1_pid, :normal} ->
_ = send(child2_pid, {tag, self(), :register})
case receive_once() do
{^tag, ^child2_pid, :yes} ->
^child2_pid = Registry.whereis_name({Registry.ViaTest, "test"})
_ = send(child2_pid, {tag, :stop})
case receive_once() do
{:EXIT, ^child2_pid, :normal} ->
_ = :erlang.exit(registry_pid, :shutdown)
case receive_once() do
{:EXIT, ^registry_pid, :shutdown} ->
:ok
end
end
end
end
end
{^tag, ^child1_pid, :no} ->
case receive_once() do
{^tag, ^child2_pid, :yes} ->
^child2_pid = Registry.whereis_name({Registry.ViaTest, "test"})
_ = send(child2_pid, {tag, :stop})
case receive_once() do
{:EXIT, ^child2_pid, :normal} ->
_ = send(child1_pid, {tag, self(), :register})
case receive_once() do
{^tag, ^child1_pid, :yes} ->
^child1_pid = Registry.whereis_name({Registry.ViaTest, "test"})
_ = send(child1_pid, {tag, :stop})
case receive_once() do
{:EXIT, ^child1_pid, :normal} ->
_ = :erlang.exit(registry_pid, :shutdown)
case receive_once() do
{:EXIT, ^registry_pid, :shutdown} ->
:ok
end
end
end
end
end
{^tag, ^child2_pid, :yes} ->
^child2_pid = Registry.whereis_name({Registry.ViaTest, "test"})
case receive_once() do
{^tag, ^child1_pid, :no} ->
_ = send(child2_pid, {tag, :stop})
case receive_once() do
{:EXIT, ^child2_pid, :normal} ->
_ = send(child1_pid, {tag, self(), :register})
case receive_once() do
{^tag, ^child1_pid, :yes} ->
^child1_pid = Registry.whereis_name({Registry.ViaTest, "test"})
_ = send(child1_pid, {tag, :stop})
case receive_once() do
{:EXIT, ^child1_pid, :normal} ->
_ = :erlang.exit(registry_pid, :shutdown)
case receive_once() do
{:EXIT, ^registry_pid, :shutdown} ->
:ok
end
end
end
end
end
{^tag, ^child2_pid, :no} ->
case receive_once() do
{^tag, ^child1_pid, :yes} ->
^child1_pid = Registry.whereis_name({Registry.ViaTest, "test"})
_ = send(child1_pid, {tag, :stop})
case receive_once() do
{:EXIT, ^child1_pid, :normal} ->
_ = send(child2_pid, {tag, self(), :register})
case receive_once() do
{^tag, ^child2_pid, :yes} ->
^child2_pid = Registry.whereis_name({Registry.ViaTest, "test"})
_ = send(child2_pid, {tag, :stop})
case receive_once() do
{:EXIT, ^child2_pid, :normal} ->
_ = :erlang.exit(registry_pid, :shutdown)
case receive_once() do
{:EXIT, ^registry_pid, :shutdown} ->
:ok
end
end
end
end
end
end
end
@doc false
defp receive_once() do
receive do
msg ->
msg
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment