The JUCE cross-platform C++ framework, with DISTRHO/KXStudio specific changes
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

166 lines
4.9KB

  1. /*
  2. ==============================================================================
  3. This file is part of the JUCE library - "Jules' Utility Class Extensions"
  4. Copyright 2004-11 by Raw Material Software Ltd.
  5. ------------------------------------------------------------------------------
  6. JUCE can be redistributed and/or modified under the terms of the GNU General
  7. Public License (Version 2), as published by the Free Software Foundation.
  8. A copy of the license is included in the JUCE distribution, or can be found
  9. online at www.gnu.org/licenses.
  10. JUCE is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
  12. A PARTICULAR PURPOSE. See the GNU General Public License for more details.
  13. ------------------------------------------------------------------------------
  14. To release a closed-source product which uses JUCE, commercial licenses are
  15. available: visit www.rawmaterialsoftware.com/juce for more information.
  16. ==============================================================================
  17. */
  18. BEGIN_JUCE_NAMESPACE
  19. //==============================================================================
  20. ReadWriteLock::ReadWriteLock() noexcept
  21. : numWaitingWriters (0),
  22. numWriters (0),
  23. writerThreadId (0)
  24. {
  25. }
  26. ReadWriteLock::~ReadWriteLock() noexcept
  27. {
  28. jassert (readerThreads.size() == 0);
  29. jassert (numWriters == 0);
  30. }
  31. //==============================================================================
  32. void ReadWriteLock::enterRead() const noexcept
  33. {
  34. const Thread::ThreadID threadId = Thread::getCurrentThreadId();
  35. const SpinLock::ScopedLockType sl (accessLock);
  36. for (;;)
  37. {
  38. jassert (readerThreads.size() % 2 == 0);
  39. int i;
  40. for (i = 0; i < readerThreads.size(); i += 2)
  41. if (readerThreads.getUnchecked(i) == threadId)
  42. break;
  43. if (i < readerThreads.size()
  44. || numWriters + numWaitingWriters == 0
  45. || (threadId == writerThreadId && numWriters > 0))
  46. {
  47. if (i < readerThreads.size())
  48. {
  49. readerThreads.set (i + 1, (Thread::ThreadID) (1 + (pointer_sized_int) readerThreads.getUnchecked (i + 1)));
  50. }
  51. else
  52. {
  53. readerThreads.add (threadId);
  54. readerThreads.add ((Thread::ThreadID) 1);
  55. }
  56. return;
  57. }
  58. const SpinLock::ScopedUnlockType ul (accessLock);
  59. waitEvent.wait (100);
  60. }
  61. }
  62. void ReadWriteLock::exitRead() const noexcept
  63. {
  64. const Thread::ThreadID threadId = Thread::getCurrentThreadId();
  65. const SpinLock::ScopedLockType sl (accessLock);
  66. for (int i = 0; i < readerThreads.size(); i += 2)
  67. {
  68. if (readerThreads.getUnchecked(i) == threadId)
  69. {
  70. const pointer_sized_int newCount = ((pointer_sized_int) readerThreads.getUnchecked (i + 1)) - 1;
  71. if (newCount == 0)
  72. {
  73. readerThreads.removeRange (i, 2);
  74. waitEvent.signal();
  75. }
  76. else
  77. {
  78. readerThreads.set (i + 1, (Thread::ThreadID) newCount);
  79. }
  80. return;
  81. }
  82. }
  83. jassertfalse; // unlocking a lock that wasn't locked..
  84. }
  85. //==============================================================================
  86. void ReadWriteLock::enterWrite() const noexcept
  87. {
  88. const Thread::ThreadID threadId = Thread::getCurrentThreadId();
  89. const SpinLock::ScopedLockType sl (accessLock);
  90. for (;;)
  91. {
  92. if (readerThreads.size() + numWriters == 0
  93. || threadId == writerThreadId
  94. || (readerThreads.size() == 2
  95. && readerThreads.getUnchecked(0) == threadId))
  96. {
  97. writerThreadId = threadId;
  98. ++numWriters;
  99. break;
  100. }
  101. ++numWaitingWriters;
  102. accessLock.exit();
  103. waitEvent.wait (100);
  104. accessLock.enter();
  105. --numWaitingWriters;
  106. }
  107. }
  108. bool ReadWriteLock::tryEnterWrite() const noexcept
  109. {
  110. const Thread::ThreadID threadId = Thread::getCurrentThreadId();
  111. const SpinLock::ScopedLockType sl (accessLock);
  112. if (readerThreads.size() + numWriters == 0
  113. || threadId == writerThreadId
  114. || (readerThreads.size() == 2
  115. && readerThreads.getUnchecked(0) == threadId))
  116. {
  117. writerThreadId = threadId;
  118. ++numWriters;
  119. return true;
  120. }
  121. return false;
  122. }
  123. void ReadWriteLock::exitWrite() const noexcept
  124. {
  125. const SpinLock::ScopedLockType sl (accessLock);
  126. // check this thread actually had the lock..
  127. jassert (numWriters > 0 && writerThreadId == Thread::getCurrentThreadId());
  128. if (--numWriters == 0)
  129. {
  130. writerThreadId = 0;
  131. waitEvent.signal();
  132. }
  133. }
  134. END_JUCE_NAMESPACE