This seems like a good idea to me. A very simple solution I imagine is, here:
https://github.com/elixir-lang/elixir/blob/master/lib/elixir/lib/gen_server.ex#L751 Add a check if server == self() and raise. Since this delegates directly to :gen, it would be worthwhile to propose something similar for Erlang. If there's some caveat to why this needs to be allowed, I think at least documentation for GenServer.stop/3 would be worthwhile. Allen Madsen http://www.allenmadsen.com On Wed, Oct 25, 2017 at 3:28 PM, Josh B <[email protected]> wrote: > > Just ran into a nasty little bug that I thought I would share to see if > there was some reasonable warning that could be made. > > Here is an example IEx session: > > ``` > Erlang/OTP 20 [erts-9.1] [source] [64-bit] [smp:8:8] [ds:8:8:10] > [async-threads:10] [hipe] [kernel-poll:false] [dtrace] > > Interactive Elixir (1.6.0-dev) - press Ctrl+C to exit (type h() ENTER for > help) > iex(1)> defmodule MyServer do > ...(1)> use GenServer > ...(1)> > ...(1)> def handle_call(:quit, from, _) do > ...(1)> GenServer.reply(from, :ok) > ...(1)> GenServer.stop(self(), :normal) > ...(1)> end > ...(1)> > ...(1)> def handle_call(:hello, _from, _) do > ...(1)> IO.inspect :world > ...(1)> {:reply, :ok, []} > ...(1)> end > ...(1)> end > { > :module, > MyServer, > <<70, 79, 82, 49, 0, 0, 14, 0, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 1, > 189, > 0, 0, 0, 46, 15, 69, 108, 105, 120, 105, 114, 46, 77, 121, 83, 101, > 114, > 118, 101, 114, 8, 95, 95, 105, 110, 102, 111, ...>>, > {:handle_call, 3} > } > iex(2)> {:ok, pid} = GenServer.start_link(MyServer, []) > {:ok, #PID<0.103.0>} > iex(3)> GenServer.call(pid, :hello) > :world > :ok > iex(4)> GenServer.call(pid, :quit) > :ok > iex(5)> GenServer.call(pid, :hello) > ** (exit) exited in: GenServer.call(#PID<0.103.0>, :hello, 5000) > ** (EXIT) time out > (elixir) lib/gen_server.ex:790: GenServer.call/3 > iex(5)> Process.alive?(pid) > true > ``` > > Here I made a simple GenServer that responds to `:hello` and `:quit`. The > code may look innocuous at first glance, but the GenServer deadlocks on the > `:quit` call because `GenServer.stop` is synchronous and blocking by > default. The correct way to implement this is by returning a stop tuple of > course, however I was surprised that no warning or error was raised. > > By contrast, a GenServer will crash if it tries to call itself: > > ```15:23:25.018 [error] GenServer #PID<0.97.0> terminating > ** (stop) exited in: GenServer.call(#PID<0.97.0>, :call_self, 5000) > ** (EXIT) process attempted to call itself > (elixir) lib/gen_server.ex:783: GenServer.call/3 > (stdlib) gen_server.erl:636: :gen_server.try_handle_call/4 > (stdlib) gen_server.erl:665: :gen_server.handle_msg/6 > (stdlib) proc_lib.erl:247: :proc_lib.init_p_do_apply/3 > Last message (from #PID<0.84.0>): :call_self > State: [] > Client #PID<0.84.0> is alive > (stdlib) gen.erl:169: :gen.do_call/4 > (elixir) lib/gen_server.ex:787: GenServer.call/3 > (stdlib) erl_eval.erl:670: :erl_eval.do_apply/6 > (elixir) src/elixir.erl:233: :elixir.eval_forms/4 > (iex) lib/iex/evaluator.ex:245: IEx.Evaluator.handle_eval/5 > (iex) lib/iex/evaluator.ex:225: IEx.Evaluator.do_eval/3 > (iex) lib/iex/evaluator.ex:203: IEx.Evaluator.eval/3 > (iex) lib/iex/evaluator.ex:89: IEx.Evaluator.loop/1 > ``` > > `GenServer.stop` involves a middleman process from what I can see which > stops this deadlock prevention from saving us in our original case. > > Anyways, it would be nice to have Elixir (or Erlang) warn us when we are > doing this. I could see this being implemented a few different places but > wanted to put the problem out there to see what people thought > > -- > You received this message because you are subscribed to the Google Groups > "elixir-lang-core" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To view this discussion on the web visit https://groups.google.com/d/ > msgid/elixir-lang-core/09dec8bd-393c-41ba-af12- > 65cca5f71bf3%40googlegroups.com > <https://groups.google.com/d/msgid/elixir-lang-core/09dec8bd-393c-41ba-af12-65cca5f71bf3%40googlegroups.com?utm_medium=email&utm_source=footer> > . > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "elixir-lang-core" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/elixir-lang-core/CAK-y3Cv_0o2R%2BboSiqHXWS%2BkcxXDzHYbnixGgcBpMaiznuVu6g%40mail.gmail.com. For more options, visit https://groups.google.com/d/optout.
