3 ms·
Hmm, consider we'd want to keep fork(), then the only safe way to deal with this would be, that critical sections were actually transactions implemented on the
by datenwolf 10y ago
Hmm, consider we'd want to keep fork(), then the only safe way to deal with this would be, that critical sections were actually transactions implemented on the OS level and at after fork() in the child all transactions in flight get rolled back before returning from fork().
I see two implementation challenges with that suggestion:
1.) implementing that transaction mechanism as a kernel feature: When entering a CS mark all pages CoW, upon leaving the CS merge modified pages (problem: Whole pages are then mutual exclusive, dealing with this is the challenge)
2.) battling with user space implemented locks that use atomics.
-----
An immediate mitigation I see is, that fork() itself is a CS on _all_ the locks of a process. If we consider that only the standard locking mechanisms are used, then whenever a CS is entered (which includes the creation process of a locking primitive) it raises/posts a global fork-lock semaphore. And upon leaving that semaphore is lowered.
This still leaves the DIY-locking primitives problem open. But it should be more or less straightforward to add this to the system libc/pthread libraries' locking primitive implementation and fork() syscall wrappers.
Or did I miss something essential here? Talk is cheap, so if nobody has any obvious objections I'd actually go ahead implement it.
EDIT: Okay, one immediate problem I see is, that this would pose a challenge for calling fork inside a CS. Technically this is a situation where thread recursive locks would help, but as we all know, recursive locks are highly problematic.
- the_why_of_y 10y agoSounds like you are trying to re-invent Software Transactional Memory - was a nice idea 10 years ago, but after lots of research it is still not available in common runtimes... Some more problems to consider: 1. how do you roll back IO that happens in a critical section? 2. your global semaphore will be highly contended and basically destroy scalability
- datenwolf 10y agore 1) good point, didn't think of that re 2) the fork global lock satisfies every requirement for a multiple-readers/single-writer, with fork() being the only writer. Unless the program does a lot of fork()-ing it should hardly ever run into contention. The moment fork() waits on the lock, further attempts on read-lock are delayed until after fork() completes and the existing reads are waited for, before fork()-ing.