Skip to content

fish's Fork and Pthread Manifesto

ridiculousfish edited this page Jan 6, 2013 · 1 revision

Async safe functions are functions which are safe to call from a signal handler. An async-safe function must be prepared to be invoked re-entrantly at any point in its execution, which makes it very limited in how it can manipulate global state. Locks do not help because the function is invoked on the same thread, and pthread_mutex_lock isn't itself async-safe anyways. In its current state, fish does not call any async-unsafe functions from signal handlers.

There's a different but related concept that, as far as I know, has no name: functions which are safe to call after forking in a multithreaded process. Let's call them multifork-safe. Multifork-safe functions must be prepared to deal with the following issues:

  1. Only the forking thread exists in the child process. The other threads simply never get created. Thus if the forking thread is waiting on another thread, it will deadlock.
  2. mutexes are in an unspecified state after fork, and must be re-initialized with pthread_mutex_init.

Heavyweight systems like malloc are hopelessly async-unsafe, but can be made multifork-safe, as follows:

  1. Use pthread_atfork to register a "before-fork" handler that takes a mutex. Once this succeeds, malloc knows that no other threads are in malloc, so its state is sound.
  2. Use pthread_atfork to register an "after-fork" handler that re-initializes the malloc mutexes, and any state.

Remarkably, modern mallocs actually do this. So malloc is usually safe to call after fork, and my guess is that this cascades to wperror. fish has a function test_fork which tries to force malloc to fail after fork in the presence of pthreads; I have never seen a failure.

However, this is certainly a fragile area so bugs here are likely. fish has no long-running threads, and so fish can also be put into a mode where it waits for its threads to exit before calling fork. This should improve safety, but may re-introduce fish 1.x's slowdowns on slow filesystems.