I'm looking into some code that essentially implements a multithreaded daemon that also calls fork
and I'm convinced that it's not doing so safely. A rewrite is the ideal scenario, but I'm also investigating the best way to modify it make it safe, the idea is pretty simple:
- Create a read-write lock
- Grab the write lock before forking
- Grab the read lock before doing anything "unsafe" (which might grab a lock etc...)
I can find out what's unsafe in our own code, but I have no clue what's unsafe in system code. To that end, I'm wondering if there is an exhaustive list somewhere of standard libc and syscalls which implicitly grab mutexes under the hood.
There is a list of system calls in the signal(2)
manpage which are safe to call in signal handlers:
_Exit() _exit() abort() accept() access() aio_error() aio_return()
aio_suspend() alarm() bind() cfgetispeed() cfgetospeed() cfsetispeed()
cfsetospeed() chdir() chmod() chown() clock_gettime() close() connect()
creat() dup() dup2() execle() execve() fchmod() fchown() fcntl() fdata-
sync() fork() fpathconf() fstat() fsync() ftruncate() getegid()
geteuid() getgid() getgroups() getpeername() getpgrp() getpid() getp-
pid() getsockname() getsockopt() getuid() kill() link() listen()
lseek() lstat() mkdir() mkfifo() open() pathconf() pause() pipe()
poll() posix_trace_event() pselect() raise() read() readlink() recv()
recvfrom() recvmsg() rename() rmdir() select() sem_post() send()
sendmsg() sendto() setgid() setpgid() setsid() setsockopt() setuid()
shutdown() sigaction() sigaddset() sigdelset() sigemptyset() sig-
fillset() sigismember() signal() sigpause() sigpending() sigprocmask()
sigqueue() sigset() sigsuspend() sleep() socket() socketpair() stat()
symlink() sysconf() tcdrain() tcflow() tcflush() tcgetattr() tcgetp-
grp() tcsendbreak() tcsetattr() tcsetpgrp() time() timer_getoverrun()
timer_gettime() timer_settime() times() umask() uname() unlink()
utime() wait() waitpid() write()
And I presume that since these are safe to call in a signal handler, they won't try to grab any mutexes or do something non-reentrant.
Am I just to assume that all other system calls are unsafe? What about libc, I know from other threads that malloc for example does some locking under the hood, is there a definitive list somewhere?
Edit: Provide some background to why I'm asking this question.