Tutorial 5: Dealing With Crashes
Setup
Let’s say you want to create a NIF module from the following example C file test.c
:
#include "test.h"
#include "signal.h"
int
works()
{
return 42;
}
void
fails()
{
raise(SIGSEGV);
}
The header file test.h
looks like this:
extern int works();
extern void fails();
We can now create the NIF module as learned in Tutorial 1:
1> nifty:compile("test.h", test, [{port_specs, [{".*","$NIF",["test.c"]}]}]).
generating test.h -> test_nif.c test.erl
==> test (compile)
Compiled src/test_remote.erl
Compiled src/test.erl
Compiling c_src/test_nif.c
ok
Segfault And Other Crashes
2> test:works().
42
3> test:fails().
Segmentation fault (core dumped)
$
Now this is expected, since a segfault crashes the whole system process, but it breaks with the fault-tolerant nature of Erlang. Nifty
allows you to call the created NIF modules without crashing the process. For every NIF module, an additional module with the postfix _remote
is created. This module exports the same functions as the NIF module plus start\0
, stop\0
and restart\0
. Nifty starts a node in an external
process, which handles the NIF module:
2> test_remote:start().
ok
(p33_p0_master@cola-light)3> test_remote:works().
42
(p33_p0_master@cola-light)4> test_remote:fails().
{error,node_crashed}
(p33_p0_master@cola-light)5> test_remote:stop().
ok
6>
As you can see, fails\0
now returns {error, node_crashed}
instead of crashing Erlang. After the remote node has crashed, it is necessary to
restart it with restart\0
. Otherwise every function call will return {error, node_down}
. You can also stop the remote node with stop\0
.
Restarting the or stopping is a hard reset of the NIF module. Static C variables and allocated memory will behave as you freshly
loaded the NIF module. This means, that all pointers that you still have are invalid.
Previous Tutorial | Tutorial Files | Next Tutorial |
---|