System.trap_signal

You're seeing just the function trap_signal, go back to System module for more information.
Link to this function

trap_signal(signal, id \\ make_ref(), fun)

View Source (since 1.12.0)

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 with stop/0
  • :sigquit - halts the VM via halt/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).