Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Clarify gen_statem:start_link/3,4 semantics #7529

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 50 additions & 10 deletions lib/stdlib/doc/src/gen_event.xml
Original file line number Diff line number Diff line change
Expand Up @@ -861,8 +861,8 @@ gen_event:stop -----> Module:terminate/2
<v>&nbsp;&nbsp;Dbgs = [Dbg]</v>
<v>&nbsp;&nbsp;&nbsp;Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}</v>
<v>&nbsp;&nbsp;SOpts = [term()]</v>
<v>Result = {ok,Pid} | {error,{already_started,Pid}}</v>
<v>&nbsp;Pid = pid()</v>
<v>Result = {ok,Pid} | {error,{already_started,OtherPid}} | {error,timeout}</v>
<v>&nbsp;Pid = OtherPid = pid()</v>
</type>
<desc>
<p>Creates a stand-alone event manager process, that is, an event
Expand All @@ -888,14 +888,14 @@ gen_event:stop -----> Module:terminate/2
<v>&nbsp;&nbsp;Dbgs = [Dbg]</v>
<v>&nbsp;&nbsp;&nbsp;Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}</v>
<v>&nbsp;&nbsp;SOpts = [term()]</v>
<v>Result = {ok,Pid} | {error,{already_started,Pid}}</v>
<v>&nbsp;Pid = pid()</v>
<v>Result = {ok,Pid} | {error,{already_started,OtherPid}} | {error,timeout}</v>
<v>&nbsp;Pid = OtherPid = pid()</v>
</type>
<desc>
<p>Creates an event manager process as part of a supervision
tree. The function is to be called, directly or indirectly,
by the supervisor. For example, it ensures that
the event manager is linked to the supervisor.</p>
the event manager is linked to the caller (supervisor).</p>
<list type="bulleted">
<item>
<p>If <c>EventMgrName={local,Name}</c>, the event manager is
Expand Down Expand Up @@ -927,10 +927,50 @@ gen_event:stop -----> Module:terminate/2
</list>
<p>If the event manager is successfully created, the function
returns <c>{ok,Pid}</c>, where <c>Pid</c> is the pid of
the event manager. If a process with the specified
the event manager.</p>
<p>If a process with the specified
<c>EventMgrName</c> exists already, the function returns
<c>{error,{already_started,Pid}}</c>, where <c>Pid</c> is
the pid of that process.</p>
<c>{error,{already_started,OtherPid}}</c>, where <c>OtherPid</c> is
the pid of that process, and the event manager process
exits with reason <c>normal</c>.</p>
<p>
If the event manager fails to start within the specified
start timeout <c>{timeout,Time}</c>, which is very unlikely
since the start does not interact with other processes,
the function returns <c>{error,timeout}</c> and the
failed event manager is killed with
<seemfa marker="erts:erlang#exit/2"><c>exit(_, kill)</c></seemfa>.
</p>
<p>
If <c>start_link/1,2</c> returns <c>{error,_}</c>,
the started event manager process has terminated.
If an <c>'EXIT'</c> message was delivered to the calling process
(due to the process link), that message has been consumed.
</p>
<warning>
<p>
Before OTP 26.0, if the started event manager
failed to register its name, this founction could return
<c>{error,{already_started,OtherPid}}</c>
<em>before</em> the started event manager process
had terminated so starting again might fail
because the registered name was not yet unregistered,
and an <c>'EXIT'</c> message could arrive later
to the process calling this function.
</p>
<p>
But if the start timed out, this function killed
the started event manager process and returned
<c>{error,timeout}</c>, and then the process link
<c>{'EXIT',Pid,killed}</c> message <em>was</em> consumed.
</p>
<p>
The start was made synchronous in OTP 26.0
and the guarantee was implemented
that no process link <c>'EXIT'</c> message from a failed start
will linger in the caller's inbox.
</p>
</warning>
</desc>
</func>

Expand All @@ -948,8 +988,8 @@ gen_event:stop -----> Module:terminate/2
<v>&nbsp;&nbsp;Dbgs = [Dbg]</v>
<v>&nbsp;&nbsp;&nbsp;Dbg = trace | log | statistics | {log_to_file,FileName} | {install,{Func,FuncState}}</v>
<v>&nbsp;&nbsp;SOpts = [term()]</v>
<v>Result = {ok,{Pid,Mon}} | {error,{already_started,Pid}}</v>
<v>&nbsp;Pid = pid()</v>
<v>Result = {ok,{Pid,Mon}} | {error,{already_started,OtherPid}} | {error,timeout}</v>
<v>&nbsp;Pid = OtherPid = pid()</v>
</type>
<desc>
<p>Creates a stand-alone event manager process, that is, an event
Expand Down
119 changes: 92 additions & 27 deletions lib/stdlib/doc/src/gen_server.xml
Original file line number Diff line number Diff line change
Expand Up @@ -345,30 +345,48 @@ gen_server:abcast -----> Module:handle_cast/2
<p>
A process with the specified <c>ServerName</c> exists already
with the process identifier <c>OtherPid</c>.
This <c>gen_server</c> was not started.
This <c>gen_server</c> was not started,
or rather exited with reason <c>normal</c> before
calling
<seemfa marker="#Module:init/1"><c>Module:init/1</c></seemfa>.
</p>
</item>
<tag><c>{error,timeout}</c></tag>
<item>
<p>
The <c>gen_server</c> process failed to initialize since
<seemfa marker="#Module:init/1"><c>Module:init/1</c></seemfa>
did not return within the
<seetype marker="#start_opt">start timeout</seetype>.
The <c>gen_server</c> process was killed with
<seemfa marker="erts:erlang#exit/2"><c>exit(_, kill)</c></seemfa>.
</p>
</item>
<tag><c>ignore</c></tag>
<item>
<p>
The <c>gen_server</c> process failed to initialize since
<seemfa marker="#Module:init/1"><c>Module:init/1</c></seemfa>
returned <c>ignore</c>, the <c>gen_server</c> process
is terminated. An exit signal <c>normal</c> is sent
to linked processes and ports.
returned <c>ignore</c>.
</p>
</item>
<tag><c>{error,<anno>Reason</anno>}</c></tag>
<item>
<p>
The <c>gen_server</c> process failed to initialize since
<seemfa marker="#Module:init/1"><c>Module:init/1</c></seemfa>
returned <c>{stop,<anno>Reason</anno>}</c>
or failed with <c><anno>Reason</anno></c>.
The <c>gen_server</c> process is terminated and
an exit signal with the same <c><anno>Reason</anno></c>
is sent to linked processes and ports.
returned <c>{stop,<anno>Reason</anno>}</c>,
<c>{error,<anno>Reason</anno>}</c>,
or it failed with reason <c><anno>Reason</anno></c>.
</p>
</item>
</taglist>
<p>
See
<seemfa marker="#Module:init/1"><c>Module:init/1</c></seemfa>
about the exit reason for the <c>gen_server</c> process
when it fails to initialize.
</p>
</desc>
</datatype>

Expand Down Expand Up @@ -1260,15 +1278,16 @@ gen_server:abcast -----> Module:handle_cast/2
Creates a <c>gen_server</c> process as part of a supervision tree.
This function is to be called, directly or indirectly, by
the supervisor. For example, it ensures that
the <c>gen_server</c> process is linked to the supervisor.
the <c>gen_server</c> process is spawned as linked
to the caller (supervisor).
</p>
<p>
The <c>gen_server</c> process calls
<seemfa marker="#Module:init/1"><c>Module:init/1</c></seemfa>
to initialize.
To ensure a synchronized startup procedure,
<c>start_link/3,4</c> does not return until
<c>Module:init/1</c> has returned.
<c>Module:init/1</c> has returned or failed.
</p>
<p>
Using the argument <c><anno>ServerName</anno></c>
Expand Down Expand Up @@ -1298,6 +1317,48 @@ gen_server:abcast -----> Module:handle_cast/2
<seetype marker="#start_ret"><c>start_ret()</c></seetype>
for a description this function's return values.
</p>
<p>
If <c>start_link/3,4</c> returns <c>ignore</c> or <c>{error,_}</c>,
the started <c>gen_server</c> process has terminated.
If an <c>'EXIT'</c> message was delivered to the calling process
(due to the process link), that message has been consumed.
</p>
<warning>
<p>
Before OTP 26.0, if the started <c>gen_server</c> process
returned e.g. <c>{stop,Reason}</c> from
<seemfa marker="#Module:init/1"><c>Module:init/1</c></seemfa>,
this function could return <c>{error,Reason}</c>
<em>before</em> the started <c>gen_statem</c> process
had terminated so starting again might fail
because VM resources such as the registered name
was not yet unregistered. An <c>'EXIT'</c> message
could arrive later to the process calling this function.
</p>
<p>
But if the started <c>gen_server</c> process instead
failed during
<seemfa marker="#Module:init/1"><c>Module:init/1</c></seemfa>,
a process link <c>{'EXIT',Pid,Reason}</c> message
caused this function to return <c>{error,Reason}</c>
so the <c>'EXIT'</c> message had been consumed
and the started <c>gen_statem</c> process had terminated.
</p>
<p>
Since it was impossible to tell the difference
between these two cases from
<c>start_link/3,4</c>'s return value,
this inconsistency was cleaned up in OTP 26.0.
</p>
</warning>
<p>
The difference between returning
<c>{stop,_}</c> and <c>{error,_}</c> from
<seemfa marker="#Module:init/1"><c>Module:init/1</c></seemfa>,
is that <c>{error,_}</c> results in a graceful ("silent")
termination since the <c>gen_server</c> process
exits with reason <c>normal</c>.
</p>
</desc>
</func>

Expand Down Expand Up @@ -1964,30 +2025,34 @@ format_status(Status) ->
</item>
<tag>
<c>{stop,Reason}</c><br/>
</tag>
<item>
<p>
Initialization failed. The <c>gen_server</c> process
exits with reason <c>Reason</c>.
</p>
</item>
<tag>
<c>{error,Reason}</c><br/>
<c>ignore</c>
</tag>
<item>
<p>
Initialization failed.
An exit signal with reason</p>
<taglist>
<tag>stop:</tag>
<item><c>Reason</c></item>
<tag>error:</tag>
<item><c>normal</c></item>
<tag>ignore:</tag>
<item><c>normal</c></item>
</taglist>
<p>is sent to linked processes and ports,
notably to the process starting the gen_server when
<seemfa marker="#start_link/3">
<c>start_link/3,4</c>
</seemfa>
is used.
Initialization failed. The <c>gen_server</c> process
exits with reason <c>normal</c>.
</p>
<p>
<c>{error,Reason}</c> was introduced in OTP 26.0.
</p>
</item>
</taglist>
<p>
See function
<seemfa marker="#start_link/3"><c>start_link/3,4</c></seemfa>'s
return value
<seetype marker="#start_ret"><c>start_ret()</c></seetype>
in these different cases.
</p>
</desc>
</func>

Expand Down
Loading