6 Sys and Proc_Lib

The module sys contains functions for simple debugging of
processes implemented using behaviours.

There are also functions that, together with functions in
the module proc_lib, can be used to implement a
special process, a process which comply to the OTP design
principles without making use of a standard behaviour. They can
also be used to implement user defined (non-standard) behaviours.

System messages are messages with special meaning, used in
the supervision tree. Typical system messages are requests for
trace output, and requests to suspend or resume process execution
(used during release handling). Processes implemented using
standard behaviours automatically understand these messages.

Example

The simple server from
the Overview chapter,
implemented using sys and proc_lib so it fits into
a supervision tree:

Starting the Process

A function in the proc_lib module should be used to
start the process. There are several possible functions, for
example spawn_link/3,4 for asynchronous start and
start_link/3,4,5 for synchronous start.

A process started using one of these functions will store
information that is needed for a process in a supervision tree,
for example about the ancestors and initial call.

Also, if the process terminates with another reason than
normal or shutdown, a crash report (see SASL
User's Guide) is generated.

In the example, synchronous start is used. The process is
started by calling ch4:start_link():

start_link() ->
proc_lib:start_link(ch4, init, [self()]).

ch4:start_link calls the function
proc_lib:start_link. This function takes a module name,
a function name and an argument list as arguments and spawns
and links to a new process. The new process starts by executing
the given function, in this case ch4:init(Pid), where
Pid is the pid (self()) of the first process, that
is the parent process.

In init, all initialization including name registration
is done. The new process must also acknowledge that it has been
started to the parent:

Debugging

sys:debug_options/1 takes a list of options as argument.
Here the list is empty, which means no debugging is enabled
initially. See sys(3) for information about possible
options.

Then for each system event that we want to be logged
or traced, the following function should be called.

sys:handle_debug(Deb, Func, Info, Event) => Deb1

Deb is the debug structure.

Func is a tuple {Module, Name} (or a fun) and
should specify a (user defined) function used to format
trace output. For each system event, the format function is
called as Module:Name(Dev, Event, Info), where:

Dev is the IO device to which the output should
be printed. See io(3).

Event and Info are passed as-is from
handle_debug.

Info is used to pass additional information to
Func, it can be any term and is passed as-is.

Event is the system event. It is up to the user to
define what a system event is and how it should be
represented, but typically at least incoming and outgoing
messages are considered system events and represented by
the tuples {in,Msg[,From]} and {out,Msg,To},
respectively.

handle_debug returns an updated debug structure
Deb1.

In the example, handle_debug is called for each incoming
and outgoing message. The format function Func is
the function ch4:write_debug/3 which prints the message
using io:format/3.

To implement a user-defined behaviour, write code similar to
code for a special process but calling functions in a callback
module for handling specific tasks.

If it is desired that the compiler should warn for missing
callback functions, as it does for the OTP behaviours, implement
and export the function:

behaviour_info(callbacks) ->
[{Name1,Arity1},...,{NameN,ArityN}].

where each {Name,Arity} specifies the name and arity of
a callback function.

When the compiler encounters the module attribute
-behaviour(Behaviour). in a module Mod, it will call
Behaviour:behaviour_info(callbacks) and compare the result
with the set of functions actually exported from Mod, and
issue a warning if any callback function is missing.