[erlang-questions] clarify: gen_server:start_link/3 return values?

Aggelos Giantsios aggelgian@REDACTED
Thu Apr 25 11:04:20 CEST 2013


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
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://erlang.org/pipermail/erlang-questions/attachments/20130425/3a5bcf9f/attachment.htm>


More information about the erlang-questions mailing list