/src/rt/sync/lock_and_signal.cpp

http://github.com/jruderman/rust · C++ · 169 lines · 118 code · 18 blank · 33 comment · 3 complexity · 81de49abf2f34bec62d3b3ee9c6a0f1e MD5 · raw file

  1. #include "../rust_globals.h"
  2. #include "lock_and_signal.h"
  3. /*
  4. * A "lock-and-signal" pair. These are necessarily coupled on pthreads
  5. * systems, and artificially coupled (by this file) on win32. Put
  6. * together here to minimize ifdefs elsewhere; you must use them as
  7. * if you're using a pthreads cvar+mutex pair.
  8. */
  9. // FIXME (#2683): This is not a portable way of specifying an invalid
  10. // pthread_t
  11. #define INVALID_THREAD 0
  12. #if defined(__WIN32__)
  13. lock_and_signal::lock_and_signal()
  14. #if defined(DEBUG_LOCKS)
  15. : _holding_thread(INVALID_THREAD)
  16. #endif
  17. {
  18. _event = CreateEvent(NULL, FALSE, FALSE, NULL);
  19. // If a CRITICAL_SECTION is not initialized with a spin count, it will
  20. // default to 0, even on multi-processor systems. MSDN suggests using
  21. // 4000. On single-processor systems, the spin count parameter is ignored
  22. // and the critical section's spin count defaults to 0.
  23. const DWORD SPIN_COUNT = 4000;
  24. CHECKED(!InitializeCriticalSectionAndSpinCount(&_cs, SPIN_COUNT));
  25. // FIXME #2893 Consider checking
  26. // GetProcAddress("InitializeCriticalSectionEx")
  27. // so Windows >= Vista we can use CRITICAL_SECTION_NO_DEBUG_INFO to avoid
  28. // allocating CRITICAL_SECTION debug info that is never released. See:
  29. // http://stackoverflow.com/questions/804848/
  30. // critical-sections-leaking-memory-on-vista-win2008#889853
  31. }
  32. #else
  33. lock_and_signal::lock_and_signal()
  34. #if defined(DEBUG_LOCKS)
  35. : _holding_thread(INVALID_THREAD)
  36. #endif
  37. {
  38. CHECKED(pthread_cond_init(&_cond, NULL));
  39. CHECKED(pthread_mutex_init(&_mutex, NULL));
  40. }
  41. #endif
  42. lock_and_signal::~lock_and_signal() {
  43. #if defined(__WIN32__)
  44. CloseHandle(_event);
  45. DeleteCriticalSection(&_cs);
  46. #else
  47. CHECKED(pthread_cond_destroy(&_cond));
  48. CHECKED(pthread_mutex_destroy(&_mutex));
  49. #endif
  50. }
  51. void lock_and_signal::lock() {
  52. must_not_have_lock();
  53. #if defined(__WIN32__)
  54. EnterCriticalSection(&_cs);
  55. #if defined(DEBUG_LOCKS)
  56. _holding_thread = GetCurrentThreadId();
  57. #endif
  58. #else
  59. CHECKED(pthread_mutex_lock(&_mutex));
  60. #if defined(DEBUG_LOCKS)
  61. _holding_thread = pthread_self();
  62. #endif
  63. #endif
  64. }
  65. void lock_and_signal::unlock() {
  66. must_have_lock();
  67. #if defined(DEBUG_LOCKS)
  68. _holding_thread = INVALID_THREAD;
  69. #endif
  70. #if defined(__WIN32__)
  71. LeaveCriticalSection(&_cs);
  72. #else
  73. CHECKED(pthread_mutex_unlock(&_mutex));
  74. #endif
  75. }
  76. /**
  77. * Wait indefinitely until condition is signaled.
  78. */
  79. void lock_and_signal::wait() {
  80. must_have_lock();
  81. #if defined(DEBUG_LOCKS)
  82. _holding_thread = INVALID_THREAD;
  83. #endif
  84. #if defined(__WIN32__)
  85. LeaveCriticalSection(&_cs);
  86. WaitForSingleObject(_event, INFINITE);
  87. EnterCriticalSection(&_cs);
  88. must_not_be_locked();
  89. #if defined(DEBUG_LOCKS)
  90. _holding_thread = GetCurrentThreadId();
  91. #endif
  92. #else
  93. CHECKED(pthread_cond_wait(&_cond, &_mutex));
  94. must_not_be_locked();
  95. #if defined(DEBUG_LOCKS)
  96. _holding_thread = pthread_self();
  97. #endif
  98. #endif
  99. }
  100. /**
  101. * Signal condition, and resume the waiting thread.
  102. */
  103. void lock_and_signal::signal() {
  104. #if defined(__WIN32__)
  105. SetEvent(_event);
  106. #else
  107. CHECKED(pthread_cond_signal(&_cond));
  108. #endif
  109. }
  110. #if defined(DEBUG_LOCKS)
  111. bool lock_and_signal::lock_held_by_current_thread()
  112. {
  113. #if defined(__WIN32__)
  114. return _holding_thread == GetCurrentThreadId();
  115. #else
  116. return pthread_equal(_holding_thread, pthread_self());
  117. #endif
  118. }
  119. #endif
  120. #if defined(DEBUG_LOCKS)
  121. void lock_and_signal::must_have_lock() {
  122. assert(lock_held_by_current_thread() && "must have lock");
  123. }
  124. void lock_and_signal::must_not_have_lock() {
  125. assert(!lock_held_by_current_thread() && "must not have lock");
  126. }
  127. void lock_and_signal::must_not_be_locked() {
  128. }
  129. #else
  130. void lock_and_signal::must_have_lock() { }
  131. void lock_and_signal::must_not_have_lock() { }
  132. void lock_and_signal::must_not_be_locked() { }
  133. #endif
  134. scoped_lock::scoped_lock(lock_and_signal &lock)
  135. : lock(lock)
  136. {
  137. lock.lock();
  138. }
  139. scoped_lock::~scoped_lock()
  140. {
  141. lock.unlock();
  142. }
  143. //
  144. // Local Variables:
  145. // mode: C++
  146. // fill-column: 78;
  147. // indent-tabs-mode: nil
  148. // c-basic-offset: 4
  149. // buffer-file-coding-system: utf-8-unix
  150. // compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
  151. // End: