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.

167 lines
5.0KB

  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. readerThreads.ensureStorageAllocated (16);
  26. }
  27. ReadWriteLock::~ReadWriteLock() noexcept
  28. {
  29. jassert (readerThreads.size() == 0);
  30. jassert (numWriters == 0);
  31. }
  32. //==============================================================================
  33. void ReadWriteLock::enterRead() const noexcept
  34. {
  35. const Thread::ThreadID threadId = Thread::getCurrentThreadId();
  36. const SpinLock::ScopedLockType sl (accessLock);
  37. for (;;)
  38. {
  39. jassert (readerThreads.size() % 2 == 0);
  40. int i;
  41. for (i = 0; i < readerThreads.size(); i += 2)
  42. if (readerThreads.getUnchecked(i) == threadId)
  43. break;
  44. if (i < readerThreads.size()
  45. || numWriters + numWaitingWriters == 0
  46. || (threadId == writerThreadId && numWriters > 0))
  47. {
  48. if (i < readerThreads.size())
  49. {
  50. readerThreads.set (i + 1, (Thread::ThreadID) (1 + (pointer_sized_int) readerThreads.getUnchecked (i + 1)));
  51. }
  52. else
  53. {
  54. readerThreads.add (threadId);
  55. readerThreads.add ((Thread::ThreadID) 1);
  56. }
  57. return;
  58. }
  59. const SpinLock::ScopedUnlockType ul (accessLock);
  60. waitEvent.wait (100);
  61. }
  62. }
  63. void ReadWriteLock::exitRead() const noexcept
  64. {
  65. const Thread::ThreadID threadId = Thread::getCurrentThreadId();
  66. const SpinLock::ScopedLockType sl (accessLock);
  67. for (int i = 0; i < readerThreads.size(); i += 2)
  68. {
  69. if (readerThreads.getUnchecked(i) == threadId)
  70. {
  71. const pointer_sized_int newCount = ((pointer_sized_int) readerThreads.getUnchecked (i + 1)) - 1;
  72. if (newCount == 0)
  73. {
  74. readerThreads.removeRange (i, 2);
  75. waitEvent.signal();
  76. }
  77. else
  78. {
  79. readerThreads.set (i + 1, (Thread::ThreadID) newCount);
  80. }
  81. return;
  82. }
  83. }
  84. jassertfalse; // unlocking a lock that wasn't locked..
  85. }
  86. //==============================================================================
  87. void ReadWriteLock::enterWrite() const noexcept
  88. {
  89. const Thread::ThreadID threadId = Thread::getCurrentThreadId();
  90. const SpinLock::ScopedLockType sl (accessLock);
  91. for (;;)
  92. {
  93. if (readerThreads.size() + numWriters == 0
  94. || threadId == writerThreadId
  95. || (readerThreads.size() == 2
  96. && readerThreads.getUnchecked(0) == threadId))
  97. {
  98. writerThreadId = threadId;
  99. ++numWriters;
  100. break;
  101. }
  102. ++numWaitingWriters;
  103. accessLock.exit();
  104. waitEvent.wait (100);
  105. accessLock.enter();
  106. --numWaitingWriters;
  107. }
  108. }
  109. bool ReadWriteLock::tryEnterWrite() const noexcept
  110. {
  111. const Thread::ThreadID threadId = Thread::getCurrentThreadId();
  112. const SpinLock::ScopedLockType sl (accessLock);
  113. if (readerThreads.size() + numWriters == 0
  114. || threadId == writerThreadId
  115. || (readerThreads.size() == 2
  116. && readerThreads.getUnchecked(0) == threadId))
  117. {
  118. writerThreadId = threadId;
  119. ++numWriters;
  120. return true;
  121. }
  122. return false;
  123. }
  124. void ReadWriteLock::exitWrite() const noexcept
  125. {
  126. const SpinLock::ScopedLockType sl (accessLock);
  127. // check this thread actually had the lock..
  128. jassert (numWriters > 0 && writerThreadId == Thread::getCurrentThreadId());
  129. if (--numWriters == 0)
  130. {
  131. writerThreadId = 0;
  132. waitEvent.signal();
  133. }
  134. }
  135. END_JUCE_NAMESPACE