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.

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