GNOME Bugzilla – Bug 660561
small/fast/simple-abi synchronisation primitives
Last modified: 2011-10-03 01:02:57 UTC
We now have: GMutex, GCond, GRWLock, GRecMutex They are typedefed to structs containing: pthread_mutex_t, pthread_cond_t, pthread_rwlock_t, gpointer This is causing problems -- particularly in the case of pthread_rwlock_t. This type doesn't get declared under certain combinations of compiler defines (mostly involving _XOPEN_SOURCE). The obvious solution to this is to replace the structures with padding bytes and sample the byte value of the _INITIALIZER macro at ./configure type to be used as our own macro. I'd really like to avoid these awful hacks, though, so I've been thinking about an alternative. In essence, we would replace each of the above with a small (pointer-sized?) fixed structure type. GMutex - one pointer size: - Linux: we do the same as bitlocks except we avoid the contention counter madness by using a second bit within the lock itself - Windows: SRWLock fits into one pointer, so use it - other: allocate a pointer to a pthread_mutex_t on first use GCond - one pointer size: - Linux: I think it should be possible to implement a condition variable directly on futex(2) only using the pointer as a sequence counter to detect the race between unlocking the mutex and sleeping on the futex. We may have spurious wakeups, though. - Windows: CONDITION_VARIABLE fits into one pointer, so use it - other: allocate a pointer to a pthread_cond_t on first use GRWLock - one pointer size (maybe more): - Linux: I think it's possible to implement a reader/writer lock in one 32bit value, since Windows appears to do exactly this with SRWLock but I'm not sure about how fast it will be. I have some ideas that I'm playing with. - Windows: SRWLock again - other: allocate a pointer to a pthread_rwlock_t GRecMutex - one pointer size and/or two ints: - Linux: we would need one int for storing the thread ID and one for the recursion count. We could sneak a contended bit into the high order bit of the TID field for performance reasons. - Windows: allocate a pointer to a CONDITION_VARIABLE or try to do something clever with a semaphore object? - other: allocate a pointer to a pthread_mutex_t and initialize it for recursion I've taken a look at the glibc code and I've really come to the conclusion that our implementation could be _substantially_ faster. Most of these need only a single atomic integer operation in the uncontended case. The structures are also much smaller, which is nice. It's also nicer from an easy-to-maintain ABI standpoint: the structure size is exactly one pointer (or one pointer and two ints, or so on). Nothing from system headers needs to be involved. Some concerns: - we slightly regress the situation on bsd/solaris/mac by forcing them to use pointers to memory that would have to be allocated. - it was at least possible to imagine putting a GMutex into shared memory and having it work before -- that is a more distant possibility now (due to the pointer indirection being a reference to local virtual memory) - can we support adaptive mutexes this way? In all cases, I think yes. - will our new Linux implementation be able to handle priority inversion? With the new futex 'PI' API, the answer is yes for at least the normal mutex and the recursive mutex. Less sure about the reader/writer lock.
Worth noting that on OpenBSD and FreeBSD, at least, pthread_mutex_t and friends are just NULL-initialised pointers -- we should obviously special-case that situation. NetBSD is more similar to Linux, but it also has a futex(ish) interface in the form of _lwp_park/unpark(). Not sure I want to get into doing that for every platform, though.
*** This bug has been marked as a duplicate of bug 659866 ***