sysuthrd.inc 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. {
  2. This file is part of the Free Pascal run time library.
  3. Copyright (c) 2005,2009 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. constructor TSimpleRWSync.Create;
  11. begin
  12. System.InitCriticalSection(Crit);
  13. end;
  14. destructor TSimpleRWSync.Destroy;
  15. begin
  16. System.DoneCriticalSection(Crit);
  17. end;
  18. function TSimpleRWSync.Beginwrite : boolean;
  19. begin
  20. System.EnterCriticalSection(Crit);
  21. result:=true;
  22. end;
  23. procedure TSimpleRWSync.Endwrite;
  24. begin
  25. System.LeaveCriticalSection(Crit);
  26. end;
  27. procedure TSimpleRWSync.Beginread;
  28. begin
  29. System.EnterCriticalSection(Crit);
  30. end;
  31. procedure TSimpleRWSync.Endread;
  32. begin
  33. System.LeaveCriticalSection(Crit);
  34. end;
  35. constructor TMultiReadExclusiveWriteSynchronizer.Create;
  36. begin
  37. System.InitCriticalSection(fwritelock);
  38. fwaitingwriterlock:=RTLEventCreate;
  39. RTLEventResetEvent(fwaitingwriterlock);
  40. fwritelocked:=0;
  41. freadercount:=0;
  42. freaderqueue:=BasicEventCreate(nil,true,false,'');
  43. end;
  44. destructor TMultiReadExclusiveWriteSynchronizer.Destroy;
  45. begin
  46. System.InterlockedExchange(fwritelocked,0);
  47. System.DoneCriticalSection(fwritelock);
  48. RtlEventDestroy(fwaitingwriterlock);
  49. BasicEventDestroy(freaderqueue);
  50. end;
  51. function TMultiReadExclusiveWriteSynchronizer.Beginwrite : boolean;
  52. begin
  53. { if IsMultiThread is false, no thread manager may be installed
  54. under unix and hence the event routines may throw an error }
  55. if IsMultiThread then
  56. begin
  57. { wait for any other writers that may be in progress }
  58. System.EnterCriticalSection(fwritelock);
  59. { it is possible that we earlier on missed waiting on the
  60. fwaitingwriterlock and that it's still set (must be done
  61. after aquiring the fwritelock, because otherwise one
  62. writer could reset the fwaitingwriterlock of another one
  63. that's about to wait on it) }
  64. RTLeventResetEvent(fwaitingwriterlock);
  65. { new readers have to block from now on; writers get priority to avoid
  66. writer starvation (since they have to compete with potentially many
  67. concurrent readers) }
  68. BasicEventResetEvent(freaderqueue);
  69. { for quick checking by candidate-readers }
  70. System.InterlockedExchange(fwritelocked,1);
  71. { wait until all readers are gone -- freadercount and fwritelocked are only
  72. accessed using atomic operations (that's why we use
  73. InterLockedExchangeAdd(x,0) below) -> always in-order. The writer always
  74. first sets fwritelocked and then checks freadercount, while the readers
  75. always first increase freadercount and then check fwritelocked }
  76. while (System.InterLockedExchangeAdd(freadercount,0)<>0) do
  77. RTLEventWaitFor(fwaitingwriterlock);
  78. { Make sure that out-of-order execution cannot already perform reads
  79. inside the critical section before the lock has been acquired }
  80. ReadBarrier;
  81. end;
  82. { we have the writer lock, and all readers are gone }
  83. result:=true;
  84. end;
  85. procedure TMultiReadExclusiveWriteSynchronizer.Endwrite;
  86. begin
  87. { if IsMultiThread is false, no thread manager may be installed
  88. under unix and hence the event routines may throw an error }
  89. if IsMultiThread then
  90. begin
  91. { Finish all writes inside the section so that everything executing
  92. afterwards will certainly see these results }
  93. WriteBarrier;
  94. { signal potential readers that the coast is clear }
  95. System.InterlockedExchange(fwritelocked,0);
  96. { wake up waiting readers (if any); do not check first whether freadercount
  97. is <> 0, because the InterlockedDecrement in the while loop of BeginRead
  98. can have already occurred, so a single reader may be about to wait on
  99. freaderqueue even though freadercount=0. Setting an event multiple times
  100. is no problem. }
  101. BasicEventSetEvent(freaderqueue);
  102. { free the writer lock so another writer can become active }
  103. System.LeaveCriticalSection(fwritelock);
  104. end;
  105. end;
  106. procedure TMultiReadExclusiveWriteSynchronizer.Beginread;
  107. Const
  108. wrSignaled = 0;
  109. wrTimeout = 1;
  110. wrAbandoned= 2;
  111. wrError = 3;
  112. begin
  113. { if IsMultiThread is false, no thread manager may be installed
  114. under unix and hence the event routines may throw an error }
  115. if IsMultiThread then
  116. begin
  117. System.InterlockedIncrement(freadercount);
  118. { wait until there is no more writer }
  119. while System.InterLockedExchangeAdd(fwritelocked,0)<>0 do
  120. begin
  121. { there's a writer busy or wanting to start -> wait until it's
  122. finished; a writer may already be blocked in the mean time, so
  123. wake it up if we're the last to go to sleep }
  124. if System.InterlockedDecrement(freadercount)=0 then
  125. RTLEventSetEvent(fwaitingwriterlock);
  126. if (BasicEventWaitFor(high(cardinal),freaderqueue) in [wrAbandoned,wrError]) then
  127. raise Exception.create('BasicEventWaitFor failed in TMultiReadExclusiveWriteSynchronizer.Beginread');
  128. { and try again: first increase freadercount, only then check
  129. fwritelocked }
  130. System.InterlockedIncrement(freadercount);
  131. end;
  132. { Make sure that out-of-order execution cannot perform reads
  133. inside the critical section before the lock has been acquired }
  134. ReadBarrier;
  135. end;
  136. end;
  137. procedure TMultiReadExclusiveWriteSynchronizer.Endread;
  138. begin
  139. { if IsMultiThread is false, no thread manager may be installed
  140. under unix and hence the event routines may throw an error }
  141. if IsMultiThread then
  142. begin
  143. { If no more readers, wake writer in the ready-queue if any. Since a writer
  144. always first atomically sets the fwritelocked and then atomically checks
  145. the freadercount, first modifying freadercount and then checking fwritelock
  146. ensures that we cannot miss one of the events regardless of execution
  147. order. }
  148. if (System.InterlockedDecrement(freadercount)=0) and
  149. (System.InterLockedExchangeAdd(fwritelocked,0)<>0) then
  150. RTLEventSetEvent(fwaitingwriterlock);
  151. end;
  152. end;