System.trap_signal
trap_signal
, go back to System module for more information.
Specs
trap_signal(signal(), id, (() -> :ok)) :: {:ok, id} | {:error, :already_registered} | {:error, :not_sup} when id: term()
Traps the given signal
to execute the fun
.
Important: Trapping signals may have strong implications
on how a system shuts down and behave in production and
therefore it is extremely discouraged for libraries to
set their own traps. Instead, they should redirect users
to configure them themselves. The only cases where it is
acceptable for libraries to set their own traps is when
using Elixir in script mode, such as in .exs
files and
via Mix tasks.
An optional id
that uniquely identifies the function
can be given, otherwise a unique one is automatically
generated. If a previously registered id
is given,
this function returns an error tuple. The id
can be
used to remove a registered signal by calling
untrap_signal/2
.
The given fun
receives no arguments and it must return
:ok
.
It returns {:ok, id}
in case of success,
{:error, :already_registered}
in case the id has already
been registered for the given signal, or {:error, :not_sup}
in case trapping exists is not supported by the current OS.
The first time a signal is trapped, it will override the
default behaviour from the operating system. If the same
signal is trapped multiple times, subsequent functions
given to trap_signal
will execute first. In other
words, you can consider each function is prepended to
the signal handler.
By default, the Erlang VM register traps to the three signals:
:sigstop
- gracefully shuts down the VM withstop/0
:sigquit
- halts the VM viahalt/0
:sigusr1
- halts the VM via status code of 1
Therefore, if you add traps to the signals above, the default behaviour above will be executed after all user signals.
Implementation notes
All signals run from a single process. Therefore, blocking the
fun
will block subsequent traps. It is also not possible to add
or remove traps from within a trap itself.
Internally, this functionality is built on top of :os.set_signal/2
.
When you register a trap, Elixir automatically sets it to :handle
and it reverts it back to :default
once all traps are removed
(except for :sigquit
, :sigterm
, and :sigusr1
which are always
handled). If you or a library call :os.set_signal/2
directly,
it may disable Elixir traps (or Elixir may override your configuration).