[erlang-questions] clarify: gen_server:start_link/3 return values?
Bengt Kleberg
bengt.kleberg@REDACTED
Thu Apr 25 14:45:11 CEST 2013
Would it not be consistent with the documentation if the return values
{stop, Reason} or ignore, from init/1, would not cause a call to
erlang:exit/1 ?
bengt
On Thu, 2013-04-25 at 12:04 +0300, Aggelos Giantsios wrote:
>
> On Thu, Apr 25, 2013 at 11:19 AM, Bengt Kleberg
> <bengt.kleberg@REDACTED> wrote:
>
> Under what circumstances will gen_server:start_link/3 return
> {error,
> Reason}?
>
> You are right, there is an inconsistency in the documentation.
> So let's have a look at the code of gen_server:start_link/3.
>
> In gen_server.erl
> ------------------------
> start_link(Mod, Args, Options) ->
> gen:start(?MODULE, link, Mod, Args, Options).
>
> In gen.erl
> --------------
> start(GenMod, LinkP, Mod, Args, Options) ->
> do_spawn(GenMod, LinkP, Mod, Args, Options).
>
> %% We only need this clause as LinkP =:= link in our case
> do_spawn(GenMod, link, Mod, Args, Options) ->
> Time = timeout(Options),
> proc_lib:start_link(?MODULE, init_it,
> [GenMod, self(), self(), Mod, Args,
> Options],
> Time,
> spawn_opts(Options));
>
> init_it(GenMod, Starter, Parent, Mod, Args, Options) ->
> init_it2(GenMod, Starter, Parent, self(), Mod, Args, Options).
>
> init_it2(GenMod, Starter, Parent, Name, Mod, Args, Options) ->
> %% So in our case will call gen_server:init_it/6 where Parent will
> be the a PID
> GenMod:init_it(Starter, Parent, Name, Mod, Args, Options).
>
> In gen_server.erl
> ------------------------
> init_it(Starter, Parent, Name0, Mod, Args, Options) ->
> Name = name(Name0),
> Debug = debug_options(Name, Options),
> %% The actual call of our module's init function
> case catch Mod:init(Args) of
> {ok, State} ->
> proc_lib:init_ack(Starter, {ok, self()}),
> loop(Parent, Name, State, Mod, infinity, Debug);
> {ok, State, Timeout} ->
> proc_lib:init_ack(Starter, {ok, self()}),
> loop(Parent, Name, State, Mod, Timeout, Debug);
> {stop, Reason} ->
> unregister_name(Name0),
> proc_lib:init_ack(Starter, {error, Reason}),
> exit(Reason);
> ignore ->
> unregister_name(Name0),
> proc_lib:init_ack(Starter, ignore),
> exit(normal);
> {'EXIT', Reason} ->
> unregister_name(Name0),
> proc_lib:init_ack(Starter, {error, Reason}),
> exit(Reason);
> Else ->
> Error = {bad_return_value, Else},
> proc_lib:init_ack(Starter, {error, Error}),
> exit(Error)
> end.
>
> So we see that if our module's init function returns {stop, Reason} or
> exits with Reason then proc_lib:init_ack(Starter, {error, Reason})
> will make proc_lib:start_link return {error, Reason}, but then
> exit(Reason) will actually cause the spawned server process to crash
> and subsequently the process that called gen_server:start_link.
> The behaviour you notice is thus completely justified and the only way
> that the behaviour the documentation describes is accurate is when
> your process traps exits and not allows exit(Reason) to crash it.
>
> Sorry for the long post! I hope this cleared things up!
>
> Aggelos
>
More information about the erlang-questions
mailing list