Created
April 16, 2015 22:43
-
-
Save simonwagner/1c029272905371be852b to your computer and use it in GitHub Desktop.
Broken recursive_timed_mutex in libstdc++ for GCC 4.8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <cstdint> | |
#ifdef MAKE_IT_WORK | |
#undef _GLIBCXX_USE_CLOCK_MONOTONIC //if this is undefined, the 'correct' clock will be used | |
#endif | |
#include <mutex> | |
extern "C" { | |
using mutex = std::recursive_timed_mutex; | |
mutex* make_lock() { | |
return new mutex(); | |
} | |
void lock_lock(mutex* lock) { | |
lock->lock(); | |
} | |
void lock_unlock(mutex* lock) { | |
lock->unlock(); | |
} | |
uint32_t lock_try_lock(mutex* lock) { | |
return lock->try_lock(); | |
} | |
uint32_t lock_try_lock_for(mutex* lock, uint32_t us) { | |
return lock->try_lock_for(std::chrono::microseconds(us)); | |
} | |
} | |
#include <thread> | |
#include <chrono> | |
#include <iostream> | |
int main() { | |
//print which clock we are using | |
#ifdef _GLIBCXX_USE_CLOCK_MONOTONIC | |
std::cout << "using chrono::steady_clock" << std::endl; | |
#else | |
std::cout << "using chrono::high_resolution_clock" << std::endl; | |
#endif | |
//try_lock_for basically will call pthread_mutex_timedlock behind the scenes | |
//now, because of the code introduced in https://github.com/gcc-mirror/gcc/commit/ec0b1c28a851cf10f39624709487fbdb5e4c8505 | |
//pthread_mutex_timedlock would basically be called with the wrong clock | |
//This was fixed with https://github.com/gcc-mirror/gcc/commit/4ca82f859dc0bfda63f5bcc16d0219ae25b5e351 | |
//(As far as I can wrap my head around it, it is fixed with https://github.com/gcc-mirror/gcc/commit/4ca82f859dc0bfda63f5bcc16d0219ae25b5e351#diff-a8a8079e66b9d73a8c1c74a4bfa7ed8cL246 which will do the clock conversion) | |
//The really bad thing is that it is assumed that time_since_epoch would return UNIX time - this is not guaranteed and just works by chance | |
auto now_hrc = std::chrono::high_resolution_clock::now(); | |
auto now_steady = std::chrono::steady_clock::now(); | |
auto diff = std::chrono::duration_cast<std::chrono::seconds>(now_hrc.time_since_epoch() - now_steady.time_since_epoch()); | |
std::cout << "pthread_mutex_timedlock does use CLOCK_REALTIME, not monotonic" << std::endl; | |
std::cout << "The difference is " << diff.count() << " seconds" << std::endl; | |
auto mutex = make_lock(); | |
lock_lock(mutex); | |
std::thread([&mutex]() { | |
auto start = std::chrono::system_clock::now(); | |
auto locked = lock_try_lock_for(mutex, 1000 * 1000 * 5); | |
auto elapsed = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::system_clock::now() - start); | |
std::cout << locked << " " << elapsed.count() << std::endl; | |
}).join(); | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment