Restartable Sequences in Glibc 2.35
lwn.net
lwn.net
Seems like interesting tradeoffs with an approach where the kernel manages a scheduling generation number in shared memory with each thread that gets incremented each scheduling, and having the user code responsible for checking at the end of the critical section whether it matches the value at the beginning. Probably an instruction or three less (and less pointer chasing) per scheduling event, but it eats a register during the critical section and grows the critical section by a few instructions, which also (for very tight critical sections) increases the chances they need a restart...
This is an alternative to cmpxchg-style solutions, which you can implement entirely in user space with no kernel collarboration. As I mentioned in another thread, the restartable sequence approach seems very limited in applicability, since it only offers you something in cases where it is specifically preemption, not multithreaded access to the data, that you need to protect against.
--
For this use case, I don't think the approach I mentioned requires an atomic cmpxchg.
Fast path (no pre-emption):
- Read generation number shared memory location (GNSML) to register
- Perform atomic operation
- Compare (non-atomic) *GNSML to register [OOPS]
- Equal, so continue
Slow path (pre-emption): - Read generation number shared memory location (GNSML) to register
- Perform (part of) atomic operation
-- Pre-emption occurs -- kernel updates GNSML, already has plenty of memory barriers with mode transitions
- Perform (rest of) atomic operation
- Compare (non-atomic) *GNSML to register -- because we're reading on the far side of the barrier, see new value
- Different, so jump to restartFrom the LWN article:
> The first rule is that the critical section cannot make any changes to the protected data structure that are visible to other threads until the final instruction in that section.
This makes me fairly certain that you cannot use this approach to deal with multi-core systems with data shared between threads, since the data could be modified without any preemption taking place.
This narrows the use case even further. To be clear I write software that could nominally benefit from stuff like this, but the tradeoffs (requiring pinning, in particular, which may not be available on all platforms) mean that it seems better to use approaches (e.g. RCU) that will work without restartable sequences.
Special purpose allocators maybe. Agree that this mechanism overall is rather niche, but that niche (malloc) is a rather important one.
> As the article says at the beginning, this is intended for per-CPU data structures, not shared ones.
Their design document (https://google.github.io/tcmalloc/rseq.html) might be of interest to you.
An actual use case where restartable windows are useful is when writing a data entry to a per-core buffer where the entire acquire-write-release sequence can be fit into the restartable window. This guarantees that the entirety of the write will occur on a single core even if it is preempted or moved as the sequence will restart on the new core if you get moved. The advantages of this approach are that you are guaranteed the buffer will be in the cache of the core being executed on guaranteeing excellent cache locality. The disadvantages are that you may have to redo the writes if you get preempted, but that should be very unlikely if your write is not too long.
In terms of the general case, restartable windows can be thought of as having a disable_preemption() or disable_core_migration() similar to how you might have a way of disabling interrupts except with some more constraints on what you can do while things are disabled.
What workloads are high thread count? Mainly servers, I think (at least I don't know if any others offhand). So OSes aimed for embedded use or desktop use don't gain much from this sort of thing. Linux dominates the server market.
librseq generates a section describing the possible critical sections, so it would be possible to make GDB read it and skip critical sections when single stepping.