Skip to content

Commit 68e282c

Browse files
author
José Valim
committed
Do not require {ref, :done}, instead allow sync removal
Signed-off-by: José Valim <[email protected]>
1 parent 403a50f commit 68e282c

File tree

2 files changed

+33
-37
lines changed

2 files changed

+33
-37
lines changed

lib/elixir/lib/gen_event.ex

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ defmodule GenEvent do
188188
@type manager :: pid | name | {atom, node}
189189

190190
@typedoc "Supported values for new handlers"
191-
@type handler :: atom | {atom, term} | pid
191+
@type handler :: atom | {atom, term} | {pid, reference}
192192

193193
@doc false
194194
defmacro __using__(_) do
@@ -612,8 +612,8 @@ defmodule GenEvent do
612612
{hib, reply, handlers} = server_add_mon_handler(handler, args, handlers, notify)
613613
reply(tag, reply)
614614
loop(parent, name, handlers, debug, hib)
615-
{_from, tag, {:add_process_handler, pid, notify}} ->
616-
{hib, reply, handlers} = server_add_process_handler(pid, handlers, notify)
615+
{_from, tag, {:add_process_handler, pid, notify, ref}} ->
616+
{hib, reply, handlers} = server_add_process_handler(pid, handlers, notify, ref)
617617
reply(tag, reply)
618618
loop(parent, name, handlers, debug, hib)
619619
{_from, tag, {:delete_handler, handler, args}} ->
@@ -761,9 +761,9 @@ defmodule GenEvent do
761761
do_add_handler(module, handler, args, handlers, :ok)
762762
end
763763

764-
defp server_add_process_handler(pid, handlers, notify) do
765-
ref = Process.monitor(pid)
766-
handler = handler(module: GenEvent.Stream, id: pid,
764+
defp server_add_process_handler(pid, handlers, notify, ref) do
765+
ref = ref || Process.monitor(pid)
766+
handler = handler(module: GenEvent.Stream, id: {self(), ref},
767767
pid: notify, ref: ref)
768768
do_add_handler(GenEvent.Stream, handler, {pid, ref}, handlers, {self(), ref})
769769
end
@@ -796,7 +796,7 @@ defmodule GenEvent do
796796

797797
defp server_split_process_handlers(mode, event, [handler|t], handlers, streams) do
798798
case handler(handler, :id) do
799-
pid when is_pid(pid) ->
799+
{pid, _ref} when is_pid(pid) ->
800800
server_process_notify(mode, event, handler)
801801
server_split_process_handlers(mode, event, t, handlers, [handler|streams])
802802
_ ->
@@ -858,16 +858,17 @@ defmodule GenEvent do
858858
end
859859

860860
defp server_collect_process_handlers(mode, event, [handler|t], handlers, name) when mode in [:sync, :ack] do
861-
handler(ref: ref) = handler
861+
handler(ref: ref, id: id) = handler
862862

863863
receive do
864864
{^ref, :ok} ->
865865
server_collect_process_handlers(mode, event, t, [handler|handlers], name)
866-
{^ref, :done} ->
867-
do_terminate(handler, :remove_handler, event, name, :normal)
866+
{_from, tag, {:delete_handler, ^id, args}} ->
867+
do_terminate(handler, args, :remove, name, :normal)
868+
reply(tag, :ok)
868869
server_collect_process_handlers(mode, event, t, handlers, name)
869870
{:DOWN, ^ref, _, _, reason} ->
870-
do_terminate(handler, {:stop, reason}, :remove, name, :shutdown)
871+
do_terminate(handler, {:stop, reason}, :DOWN, name, :shutdown)
871872
server_collect_process_handlers(mode, event, t, handlers, name)
872873
end
873874
end
@@ -939,7 +940,7 @@ defmodule GenEvent do
939940
case :lists.keyfind(ref, handler(:ref) + 1, handlers) do
940941
false -> :error
941942
handler ->
942-
do_terminate(handler, {:stop, reason}, :remove, name, :shutdown)
943+
do_terminate(handler, {:stop, reason}, :DOWN, name, :shutdown)
943944
{:ok, :lists.keydelete(ref, handler(:ref) + 1, handlers)}
944945
end
945946
end

lib/elixir/lib/gen_event/stream.ex

Lines changed: 20 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,8 @@ defimpl Enumerable, for: GenEvent.Stream do
8080

8181
defp start(%{manager: manager} = stream) do
8282
try do
83-
{:ok, {pid, ref}} = :gen.call(manager, self(), {:add_process_handler, self(), self()}, :infinity)
83+
{:ok, {pid, ref}} = :gen.call(manager, self(),
84+
{:add_process_handler, self(), self(), nil}, :infinity)
8485
mon_ref = Process.monitor(pid)
8586
{pid, ref, mon_ref}
8687
catch
@@ -92,19 +93,6 @@ defimpl Enumerable, for: GenEvent.Stream do
9293
self = self()
9394

9495
receive do
95-
# The handler was removed. Stop iteration, resolve the
96-
# event later. We need to demonitor now, otherwise DOWN
97-
# appears with higher priority in the shutdown process.
98-
{:gen_event_EXIT, ^self, _reason} = event ->
99-
Process.demonitor(mon_ref, [:flush])
100-
send(self, event)
101-
{:halt, {:removed, acc}}
102-
103-
# The manager died. Stop iteration, resolve the event later.
104-
{:DOWN, ^mon_ref, _, _, _} = event ->
105-
send(self, event)
106-
{:halt, {:removed, acc}}
107-
10896
# Got an async event.
10997
{_from, {^pid, ^ref}, {:notify, event}} ->
11098
{[{:async, pid, ref, event}], acc}
@@ -116,6 +104,19 @@ defimpl Enumerable, for: GenEvent.Stream do
116104
# Got an ack event.
117105
{_from, {^pid, ^ref}, {:ack_notify, event}} ->
118106
{[{:ack, pid, ref, event}], acc}
107+
108+
# The handler was removed. Stop iteration, resolve the
109+
# event later. We need to demonitor now, otherwise DOWN
110+
# appears with higher priority in the shutdown process.
111+
{:gen_event_EXIT, {^pid, ^ref}, _reason} = event ->
112+
Process.demonitor(mon_ref, [:flush])
113+
send(self, event)
114+
{:halt, {:removed, acc}}
115+
116+
# The manager died. Stop iteration, resolve the event later.
117+
{:DOWN, ^mon_ref, _, _, _} = event ->
118+
send(self, event)
119+
{:halt, {:removed, acc}}
119120
after
120121
timeout ->
121122
exit({:timeout, {__MODULE__, :next, [stream, acc]}})
@@ -135,26 +136,20 @@ defimpl Enumerable, for: GenEvent.Stream do
135136

136137
# If we reach this branch, the handler was not removed yet,
137138
# so we trigger a request for doing so.
138-
defp stop(stream, {pid, _, _} = acc) do
139-
parent = self()
140-
_ = Task.start(fn -> GenEvent.remove_handler(pid, parent, :shutdown) end)
139+
defp stop(stream, {pid, ref, _} = acc) do
140+
_ = GenEvent.remove_handler(pid, {pid, ref}, :shutdown)
141141
stop(stream, {:removed, acc})
142142
end
143143

144144
defp wait_for_handler_removal(pid, ref, mon_ref) do
145-
self = self()
146-
147145
receive do
148-
{_from, {^pid, ^ref}, {notify, _event}} when notify in [:ack_notify, :sync_notify] ->
149-
send pid, {ref, :done}
150-
wait_for_handler_removal(pid, ref, mon_ref)
151-
{:gen_event_EXIT, ^self, reason}
146+
{:gen_event_EXIT, {^pid, ^ref}, reason}
152147
when reason == :normal
153148
when reason == :shutdown
154149
when tuple_size(reason) == 3 and elem(reason, 0) == :swapped ->
155150
Process.demonitor(mon_ref, [:flush])
156151
:ok
157-
{:gen_event_EXIT, ^self, reason} ->
152+
{:gen_event_EXIT, {^pid, ^ref}, reason} ->
158153
Process.demonitor(mon_ref, [:flush])
159154
{:error, reason}
160155
{:DOWN, ^mon_ref, _, _, reason} ->
@@ -164,7 +159,7 @@ defimpl Enumerable, for: GenEvent.Stream do
164159

165160
defp flush_events(ref) do
166161
receive do
167-
{_from, {_pid, ^ref}, {:notify, _event}} ->
162+
{_from, {_pid, ^ref}, {notify, _event}} when notify in [:notify, :ack_notify, :sync_notify] ->
168163
flush_events(ref)
169164
after
170165
0 -> :ok

0 commit comments

Comments
 (0)