Thread cancellation on GNU/Linux


#1

The announcement that unwinding through FFI boundaries now aborts (on some platforms?) made me wonder how Rust approaches the GNU/Linux implementation of thread cancellation.

pthread_cancel uses unwind tables, based on the same mechanism as C++ exception handling. GNU C also supports destructors which run during stack unwinding (using the cleanup variable attribute). Furthermore, the x86-64 ABI mandates that unwind tables are emitted, so a precise stack trace can be obtained at all times. (Other ABIs have this by construction, the usual outlier is Aarch64, where some distributions carry custom GCC patches to enable unwind tables by default.)

This means that on GNU/Linux, unwinding is usually possible through FFI boundaries, but obviously, the foreign code has to be structured in a certain way to support unwinding reliably. A few libraries explicitly do the right thing (supporting it is pretty much like providing longjmp-safe callback hooks), and some more will just work, and many will just have minor memory leaks if unwinding proceeds through their code.

pthread_cancel already causes issues with C++, particularly due the more pervasive use of the noexcept attribute, and cannot be used to cancel threads spawned using C++ library facilities (because the thread routine is generally specified to be noexcept).

Note that POSIX thread cancellation is generally synchronous. It’s more like Thread.interrupt(), and not Thread.stop(). A pretty close approximation of the GNU/Linux implementation is that certain libc functions (cancellation points) throw a C++ exception when the thread has been or is being canceled, and this exception is automatically rethrown if a C++ exception handler attempts to completely swallow the exception.