[Erlang Systems]

4 Supervising C Programs

This section describes the supervision of C programs and includes the following topics:

4.1 Supervision Principles and C

This section assumes a knowledge of the System Architecture Support Libraries (SASL) and readers who do not plan to use SASL features may choose to skip this material.

The Open Telecom Platform (OTP) Erlang system includes some built-in software management routines and supervision structures which are titled the Systems Architecture Support Libraries (SASL). The SASL supervision principles include supervision trees where supervisors keep track of workers, and release handlers which make it possible to update a running system in an ordered way. IG generated stubs can automatically conform to the supervision principles of SASL. However, the support is not as soft, or nice, or powerful as in Erlang, mainly because C is a much rougher language than Erlang. All supervision actions result in a function call to the C side and this is called a hook.

The supervision tree and the release handler are managed by a set of messages. For example, the messages order workers to change code or to return information about their state. Erlang programs generated from IG understand these messages and they can be used in supervision trees as normal Erlang workers. The Erlang stub propagates these messages in the form of hooks to the C program. This implies that the C side must listen to the Erlang side at all times. The provided igmain and the sample igsock_server both do this.

Warning!

However, there are other difficulties when using sockets and the supervision hooks. Code change does not work for socket communication because the C program is not started from within Erlang, and we discourage the user from using them together. In general, the C side should act as a server and subordinate itself under the command of Erlang.

4.2 The Supervision Hooks

The SASL supervision hooks are accessed by declaring them in the interface header file, just like any normal interface C function. All hooks are listed below along with their signatures. The hooks are triggered by the functions in the module sys in the standard SASL manner.

The hooks are optional and empty default behaviour is provided for all of them. If the C program is a simple program then no hooks need to be declared, and if hooks are desired they can be declared in any combination. For example, if the C program must preserve its state in a system upgrade from one version to another version, then two hooks must be defined:

The following hooks are available:

erl_c_init
This hook is declared as IG_fun void erl_c_init(IG_binaryPtr state);.
This hook is called just when the C program has started. The state argument is the state returned from a previous call to erl_c_get_state, or a binary of size zero. The default behaviour is to ignore the input parameter and do absolutely nothing.
erl_c_terminate
This hook is declared as IG_fun void erl_c_terminate(void);.
This hook is called when the C program should terminate. This function stops the C program and does not return a value, the EXIT signal is sufficient. The default behaviour executes an exit(0).
erl_get_state
This hook is declared as IG_fun IG_binaryPtr erl_c_get_state(void);.
This hook is called just after code has been changed on the Erlang side. The intention is that the C program should have a chance to pass whatever vital information it needs to the next version of itself. The default behaviour is to return the empty string ("") which shows up as the empty list on the Erlang side ([]). Do not confuse this hook with the erl_c_get_status hook which returns the status of the C program.
erl_c_suspend
This hook is declared as IG_fun void erl_c_suspend(void);.
This hook is called immediately before the IG stub suspends itself and enters a safe loop. A safe loop is a loop which is guaranteed to survive a code change, even if the internal data structures have changed. The hook signifies that the C program shall become inactive in the same way as the Erlang side. The Erlang code is in a safe state when suspended and it will only process other system messages. The default behaviour is to do nothing.
erl_c_resume
This hook is declared as IG_fun void erl_c_resume(void);.
This hook is called when the IG stub returns from its suspended state and resumes execution. The default behaviour is to do nothing.
erl_c_trace
This hook is declared as IG_fun void erl_c_trace(int onoff);.
This hook is called when trace is switched on or off at the Erlang side. The onoff parameter is 1 if trace is turned on, otherwise it is 0. Be aware that these hooks do not include any tracing facilities for C in runtime other than those put there by the user. The default behaviour is to do nothing.
erl_c_get_status
This hook is declared a: IG_fun IG_string erl_c_get_status();.
This hook is called when the status of the process is requested. The status is a null terminated string and is printed in a standardized way on the Erlang side. The default behaviour is to return the empty string ("") which shows up as the empty list on the Erlang side ([]).
erl_c_log
This hook is declared a: IG_fun void erl_c_log(int onoff);.
This hook is called when logging starts or stops. Note the relation to the erl_c_log_to_file hook. The parameter onoff is 0 when logging stops, and 1 when it starts. The default behaviour is to do nothing.
erl_c_log_to_file
This hook is declared as: IG_fun void erl_c_log_to_file(IG_string filename);.
This hook is called when logging to a file. Both the Erlang side and the C side is asked to log at the same time but only one file name is provided (to conform to the rest of the SASL routines). Therefore, precautions must be taken to ensure that the C hook does not to overwrite the Erlang logging file by using another file name. The default behaviour is to do nothing.
erl_c_no_debug
This hook is declared as IG_fun void erl_c_no_debug(void);.
This hook disables all debugging and logging. The default behaviour is to do nothing.

The complete hook calling sequence during a code change is as follows (refer to the erl_get_state hook, which is the most important hook in this sequence):

  1. erl_c_suspend is called to stop normal operation
  2. the code is changed in Erlang
  3. erl_c_get_state is called and the C state is saved and passed back to Erlang
  4. erl_c_terminate
  5. the port is closed
  6. a new port is opened and the new version of the program is started
  7. erl_c_init is called and the saved state is passed, allowing the C program to restore its previous internal state
  8. erl_c_resume is called to signal the start of normal operations.

4.3 Supervision Example

There are two differences between supervised C programs and unsupervised C programs:

The following example assumes that the reader is familiar with the first example in this section (see Hands-on Example). In order to execute this example, we also assume that the previous example has been worked through and that all necessary files have been fully compiled and linked.

The first step is to assure that the C program is put into a directory that will be recognized as an application directory. We first create the required directory structure in the same directory as the first example. We then move the ex1 executable to the correct place in the structure.

UNIX> mkdir apps
UNIX> mkdir apps/lib
UNIX> mkdir apps/lib/my_app
UNIX> mkdir apps/lib/my_app/ebin
UNIX> mkdir apps/lib/my_app/priv
UNIX> mkdir apps/lib/my_app/priv/bin
UNIX> mv ex1 apps/lib/my_app/priv/bin
    

We are now ready to start ex1 in supervised mode using the sup_start/1 function. This function takes the application name as input so that the C program can be found. We also start the Erlang shell with the path to the application ebin directory in order to simulate a real application.

UNIX> erl -pa apps/lib/my_app/ebin
Erlang (JAM) emulator version 4.4.2
 
Eshell V4.4.2  (abort with ^G)
1> {ok,P} = ex1:sup_start(my_app).
{ok,<0.22.0>}
2> ex1:foo(P, "Kalle", 96).
foo: name='Kalle', age=96
                         {ok,96}
3>
    

The attentive reader might find it difficult to notice any difference in this run of the sample ex1 program. Indeed, there is no difference except for the starting method. In fact, readers may claim that we have not as yet proved conformance to the supervision principles. To this end, we will switch on the SASL trace facility, which is a higher level trace than simple Erlang raw trace.

3> sys:trace(P, true).
ok
4> ex1:foo(P, "Kalle", 96).
*DBG* <0.22.0> got call {10,{"Kalle",96}} from <0.21.0>
*DBG* <0.22.0> sent #Bin to {port,#Port}
foo: name='Kalle', age=96
                         *DBG* <0.22.0> got port data 96 from #Port
*DBG* <0.22.0> sent {<0.22.0>,{data,96}} to <0.21.0>
{ok,96}
5> 
    

The sys:trace function call propagates to the erl_c_trace hook. If we had defined the hook we would have the opportunity to turn on some trace flags in the C code. Note that we did not have to recompile anything for this example to work.


Copyright © 1991-98 Ericsson Telecom AB