ProFTPD Developer's Guide: Signals

ProFTPD Version 1.2


Table of Contents

Signal Processing
As of version 1.2.6rc1, the way in which the daemon processes received signals changed. Signal handlers are notorious for introducing race conditions[1]; it is a consequence of running code asynchronously, as signal handlers do. The core code was significantly changed to avoid the actual processing of signals so that such processing is run synchronously. This means that a signal handler merely sets a bit in a value, and exits swiftly, when a signal is delivered to the process. A call to a core signal processing function, pr_signals_handle(), is done frequently in order to act, synchronously, on any received signals.

This also means that signals do not, for the most part, interrupt the core code. For example, a while() loop that can potentially loop endlessly, and which does not call pr_signals_handle(), will not be interrupted by most signals (SIGKILL being an obvious exception). Please keep this in mind when developing your module; feel free to call pr_signals_handle() often, especially if a system or library call has been interrupted by a signal (i.e. the call returns -1, and errno is EINTR, or when writing long loops or recursive functions. Here's an example that can be seen often in the core code:

  while (syscall() < 0) {
    if (errno == EINTR) {
      pr_signals_handle();
      continue;
    }

    break;
  }
Alternatively, one could block signals before invoking the system call, and unblock signals after the call, to prevent such interruptions. Keep in mind that any signals received while they are masked are silently ignored; they are not queued by the kernel and redelivered to the process once they are unmasked. A process can use the sigpending(2) system call to examine pending signals (i.e. signals that have been raised while blocked), but this is different from queueing; a process can see which signals are pending, but not how many of each particular signal have been raised. The lack of kernel-level support for queueing of blocked signals is, I suspect, a design decision, possibly because of the possibility of having to queue an infinite number of signals.

Signal Blocking and Masking
The following functions operate on the signals TERM, CHLD, USR1, INT, QUIT, ALRM, IO, BUS and HUP:

For blocking only SIGALRM, use these two functions:

The SIGKILL signal cannot be caught or ignored.

Signal Handlers
The core code implements handlers for the following signals:


[1] Michal Zalewsi, "Delivering Signals for Fun and Profit"

Table of Contents



Author: $Author: castaglia $
Last Updated: $Date: 2003/10/01 06:39:05 $


© Copyright 2000-2003 TJ Saunders
All Rights Reserved