Multithreaded Programming Guide

Signal Handlers and Async-Signal Safety

A concept similar to thread safety is Async-Signal safety. Async-Signal-Safe operations are guaranteed not to interfere with operations that are being interrupted.

The problem of Async-Signal safety arises when the actions of a signal handler can interfere with the operation that is being interrupted.

For example, suppose a program is in the middle of a call to printf(3S) and a signal occurs whose handler itself calls printf(). In this case, the output of the two printf() statements would be intertwined. To avoid this, the handler should not call printf() itself when printf() might be interrupted by a signal.

This problem cannot be solved by using synchronization primitives because any attempted synchronization between the signal handler and the operation being synchronized would produce immediate deadlock.

Suppose that printf() is to protect itself by using a mutex. Now suppose that a thread that is in a call to printf(), and so holds the lock on the mutex, is interrupted by a signal.

If the handler (being called by the thread that is still inside of printf()) itself calls printf(), the thread that holds the lock on the mutex will attempt to take it again, resulting in an instant deadlock.

To avoid interference between the handler and the operation, either ensure that the situation never arises (perhaps by masking off signals at critical moments) or invoke only Async-Signal-Safe operations from inside signal handlers.

Because setting a thread's mask is an inexpensive user-level operation, you can inexpensively make functions or sections of code fit in the Async-Signal-Safe category.

The only routines that POSIX guarantees to be Async-Signal-Safe are listed in Table 5-2. Any signal handler can safely call in to one of these functions.

Table 5-2 Async-Signal-Safe Functions

_exit()

fstat()

read()

sysconf()

access()

getegid()

rename()

tcdrain()

alarm()

geteuid()

rmdir()

tcflow()

cfgetispeed()

getgid()

setgid()

tcflush()

cfgetospeed()

getgroups()

setpgid()

tcgetattr()

cfsetispeed()

getpgrp()

setsid()

tcgetpgrp()

cfsetospeed()

getpid()

setuid()

tcsendbreak()

chdir()

getppid()

sigaction()

tcsetattr()

chmod()

getuid()

sigaddset()

tcsetpgrp()

chown()

kill()

sigdelset()

time()

close()

link()

sigemptyset()

times()

creat()

lseek()

sigfillset()

umask()

dup2()

mkdir()

sigismember()

uname()

dup()

mkfifo()

sigpending()

unlink()

execle()

open()

sigprocmask()

utime()

execve()

pathconf()

sigsuspend()

wait()

fcntl()

pause()

sleep()

waitpid()

fork()

pipe()

stat()

write()