Multithreaded Programming Guide

Signal Handlers and Async-Signal Safety

A concept that is 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(3C), and a signal occurs whose handler calls printf(). In this case, the output of the two printf() statements would be intertwined. To avoid the intertwined output, the handler should not directly call printf() when printf() might be interrupted by a signal.

This problem cannot be solved by using synchronization primitives. Any attempt to synchronize between the signal handler and the operation being synchronized would produce an 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 calls printf(), the thread that holds the lock on the mutex attempts to take the mutex again. Attempting to take the mutex results in an instant deadlock.

To avoid interference between the handler and the operation, ensure that the situation never arises. Perhaps you can mask off signals at critical moments, or invoke only Async-Signal-Safe operations from inside signal handlers.

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()

fpathconf()

read()

sigset()

_exit()

fstat()

readlink()

sigsuspend()

abort()

fsync()

recv()

sockatmark()

accept()

ftruncate()

recvfrom()

socket()

access()

getegid()

recvmsg()

socketpair()

aio_error()

geteuid()

rename()

stat()

aio_return()

getgid()

rmdir()

symlink()

aio_suspend()

getgroups()

select()

sysconf()

alarm()

getpeername()

sem_post()

tcdrain()

bind()

getpgrp()

send()

tcflow()

cfgetispeed()

getpid()

sendmsg()

tcflush()

cfgetospeed()

getppid()

sendto()

tcgetattr()

cfsetispeed()

getsockname()

setgid()

tcgetattr()

cfsetospeed()

getsockopt()

setpgid()

tcsendbreak()

chdir()

getuid()

setsid()

tcsetattr()

chmod()

kill()

setsockopt()

tcsetpgrp()

chown()

link()

setuid()

time()

clock_gettime()

listen()

shutdown()

timer_getoverrun()

close()

lseek()

sigaction()

timer_gettime()

connect()

lstat()

sigaddset()

timer_settime()

creat()

mkdir()

sigdelset()

times()

dup()

mkfifo()

sigemptyset()

umask()

dup2()

open()

sigfillset()

uname()

execle()

pathconf()

sigismember()

ulink()

execve()

pause()

sleep()

utime()

fchmod()

pipe()

signal()

wait()

fchown()

poll()

sigpause()

waitpid()

fcntl()

posix_trace_event()

sigpending()

write()

fdatasync()

pselect()

sigprocmask()

 

fork()

raise()

sigqueue()