cond.cc 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. #include "cond.h"
  2. #include "os_compat.h"
  3. #include <unistd.h>
  4. #include <sys/syscall.h>
  5. #include <linux/futex.h>
  6. #include <asm/errno.h> // For EINTR on older kernels
  7. #include <limits.h>
  8. ConditionVariable::ConditionVariable()
  9. : m_futx(0)
  10. {
  11. #ifdef TIME_LOCKS
  12. _timer = TotalTimer::getTimerByStacktrace("cond@" + itostr(this));
  13. #endif
  14. }
  15. ConditionVariable::~ConditionVariable()
  16. {
  17. #ifdef TIME_LOCKS
  18. delete _timer;
  19. #endif
  20. }
  21. void ConditionVariable::wait(Lock& lock, UInt64 timeout_ns)
  22. {
  23. m_lock.acquire();
  24. // Wait
  25. m_futx = 0;
  26. m_lock.release();
  27. lock.release();
  28. #ifdef TIME_LOCKS
  29. ScopedTimer tt(*_timer);
  30. #endif
  31. struct timespec timeout = { time_t(timeout_ns / 1000000000), time_t(timeout_ns % 1000000000) };
  32. int res;
  33. do {
  34. res = syscall(SYS_futex, (void*) &m_futx, FUTEX_WAIT | FUTEX_PRIVATE_FLAG, 0, timeout_ns > 0 ? &timeout : NULL, NULL, 0);
  35. // Restart futex_wait if it was interrupted by a signal
  36. }
  37. while (res == -EINTR);
  38. lock.acquire();
  39. }
  40. void ConditionVariable::signal()
  41. {
  42. m_lock.acquire();
  43. m_futx = 1;
  44. syscall(SYS_futex, (void*) &m_futx, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, 1, NULL, NULL, 0);
  45. m_lock.release();
  46. }
  47. void ConditionVariable::broadcast()
  48. {
  49. m_lock.acquire();
  50. m_futx = 1;
  51. syscall(SYS_futex, (void*) &m_futx, FUTEX_WAKE | FUTEX_PRIVATE_FLAG, INT_MAX, NULL, NULL, 0);
  52. m_lock.release();
  53. }