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.

Reply via email to