What is the "use case" of learning about async-signal-safety

It's more of a "don't use" case than a use case.

If you write code that makes use of signals, and you ignore async-signal-safety, then you are likely to produce code that is faulty: it'll deadlock or corrupt your application. Just ask the textbook authors.

For POSIX, it was necessary to define the behavior of any and all functions an application may use in the presence of signals: namely, to answer the question of what happens

  • if a signal arrives while function X is in progress (has been entered, but hasn't returned)
  • and now the signal handler calls function X

X could be printf. Many functions can deal with this situation just fine. For instance, functions that just operate on their arguments have no trouble. But consider this function:

void f(int a) {
  static int counter; 
  int temp = counter + a; 
  // suppose signal arrives here 
  counter = temp;
}

If f() is in progress, and interrupted with a signal after the assignment to temp, and now calls f(), a wrong answer would result since once the signal handler returns the previously computed value of temp would be written.

Such a function would be an example of a function that's not async-signal-safe. Whether a function is or is not highly depends on its implementation.

But if the issue is ignored, it would be impossible to write robust code in the presence of signals.

So POSIX declared that, by default, none of its functions is async-signal-safe, unless it's on a list of functions that are. See the list. This is a decision that favors implementors over users: implementors now have to worry only about those functions (most of which are system calls) whereas users of signals now have a lot to worry about. As a result, this highly restricts the useful uses of signal handlers.

Note that we're studying signals here in this class mainly for 2 reasons

  • they're a main element in Unix's process management mechanism for terminating misbehaving processes or user job control

  • they're an example of the complexity introduced when you have asynchronous control flow where the actual control flow contains "diversions" as in this case when a signal handler is spontaneously invoked while a program is in progress.