4

I read Learn Some Erlang about supervisors and completely lost. They have stop and terminate functions

Whenever you want to terminate an application, you have the top supervisor of the VM shut down (this is done for you with functions like init:stop/1). Then that supervisor asks each of its children to terminate. If some of the children are supervisors, they do the same:

which seem to send shutdown message to recceive 'EXIT' confirmation

So, stop is called to shut processes down. But, later in the text however, they say that exit function (a new fruit!) must be called instead

When the top-level supervisor is asked to terminate, it calls exit(ChildPid, shutdown) on each of the Pids. If the child is a worker and trapping exits, it'll call its own terminate function. Otherwise, it's just going to die. When a supervisor gets the shutdown signal, it will forward it to its own children the same way.

Finally, they define stop function in the child module

-module(musicians).
-behaviour(gen_server).

-export([start_link/2, stop/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, code_change/3, terminate/2]).

stop(Role) -> gen_server:call(Role, stop).

where is that init:stop defined?

They also send a stop message

handle_call(stop, _From, S=#state{}) -> {stop, normal, ok, S};

Their handle_info

handle_info(timeout, S = #state{name=N, skill=bad}) ->
case random:uniform(5) of
  1 -> io:format("~s played a false note. Uh oh~n",[N]),
    {stop, bad_note, S};
  _ -> io:format("~s produced sound!~n",[N]),
    {noreply, S, ?DELAY}
end;

sheds some light upon the connection between its reply and terminate

terminate(normal, S) ->
  io:format("~s left the room (~s)~n",[S#state.name, S#state.role]);
terminate(bad_note, S) ->
  io:format("~s sucks! kicked that member out of the band! (~s)~n",
    [S#state.name, S#state.role]);
terminate(shutdown, S) ->
  io:format("The manager is mad and fired the whole band! "
    "~s just got back to playing in the subway~n", [S#state.name]);

Yet, it all looks a mess. Can you tie up the things together?

Nissa
  • 4,636
  • 8
  • 29
  • 37
Val
  • 1
  • 8
  • 40
  • 64

1 Answers1

5

init:stop() means a call to the function stop() in the module init. This tells the Erlang system to shut down all running applications nicely and then exit. It is like shutting down an operating system. The call application:stop(AppName) will then be executed for every running application. These will in their turn tell the top level supervisor of the application to shut down.

A "shutdown signal" refers to a signal from a supervisor to a child. If the supervisor wants to shut down everything below it, it sends these signals to its children.

An "exit signal" is what a process sends out when it terminates (stops or crashes) to any other processes that are linked to it. The supervisor is linked to its children, and after it has sent shutdown signals to the children, it will wait for their exit signals ('EXIT') to be sure that they have terminated.

When a child process (typically implemented using an OTP behaviour like gen_server gets a shutdown signal from above, it first calls its own terminate(...) callback function, where you can do any necessary cleanup - it's like a destructor method in OOP.

The stop(Role) function in the gen_server above is just a helper function providing an API for asking this server to stop nicely (without involving the supervisor). You could use gen_server:call(Role, stop) directly but you'd have to know that the internal implementation also uses the atom stop as the stop message. Hiding such details behind an API is good practice.

Finally, the built-in function (BIF) exit(Pid, shutdown) is poorly named, because what it does is that it sends a signal to another process and doesn't affect the process that executes the call. Think of it as send_exit_signal(Pid, shutdown). It should not be confused with the BIF exit(Info) which terminates the process that executes it (by raising an exception). Both these BIFs belong to the erlang module.

Also, in an informal text like this, a signal might be referred to as a "message" but it's not - it doesn't end up in the receiver's mailbox unless the receiver is "trapping exits" (has the trap_exit process flag set). Ordinary messages are really a special kind of signal that always go to the mailbox; exit signals (except for normal) cause receivers to also die unless they trap exits, so that groups of linked processes can be brought down together.

RichardC
  • 10,412
  • 1
  • 23
  • 24
  • Great! I just did not get the relationship between init/app:stop function and stop message/signal and between this signal and shutdown/'Exit' signals. Are they related? – Val Feb 09 '17 at 07:52
  • init:stop() is a system-level function. It talks to all running apps. The stop() function of the gen_server is just a local convenience function and its message is just an implementation detail. The shutdown signals are an internal detail of the OTP supervisor/child implementation. The exit signals are a standard thing that apply to all Erlang processes. – RichardC Feb 10 '17 at 14:07
  • @RichardC sorry, but may you look at https://stackoverflow.com/questions/57871313/erlang-node-still-runnif-after-initstop-ok – Alexander Shavelev Sep 10 '19 at 13:02