sysuthrd.inc 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  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. {$ifdef FPC_HAS_FEATURE_THREADING}
  11. constructor TSimpleRWSync.Create;
  12. begin
  13. System.InitCriticalSection(Crit);
  14. end;
  15. destructor TSimpleRWSync.Destroy;
  16. begin
  17. System.DoneCriticalSection(Crit);
  18. end;
  19. function TSimpleRWSync.Beginwrite : boolean;
  20. begin
  21. System.EnterCriticalSection(Crit);
  22. result:=true;
  23. end;
  24. procedure TSimpleRWSync.Endwrite;
  25. begin
  26. System.LeaveCriticalSection(Crit);
  27. end;
  28. procedure TSimpleRWSync.Beginread;
  29. begin
  30. System.EnterCriticalSection(Crit);
  31. end;
  32. procedure TSimpleRWSync.Endread;
  33. begin
  34. System.LeaveCriticalSection(Crit);
  35. end;
  36. constructor TMultiReadExclusiveWriteSynchronizer.Create;
  37. begin
  38. System.InitCriticalSection(fwritelock);
  39. fwaitingwriterlock:=RTLEventCreate;
  40. RTLEventResetEvent(fwaitingwriterlock);
  41. { make sure all threads see the initialisation of fwritelock and
  42. freadercount (we only use atomic operation further on as well) }
  43. System.InterlockedExchange(freadercount,0);
  44. System.InterlockedExchange(fwritelocked,0);
  45. freaderqueue:=BasicEventCreate(nil,true,false,'');
  46. end;
  47. destructor TMultiReadExclusiveWriteSynchronizer.Destroy;
  48. begin
  49. System.InterlockedExchange(fwritelocked,0);
  50. System.DoneCriticalSection(fwritelock);
  51. RtlEventDestroy(fwaitingwriterlock);
  52. BasicEventDestroy(freaderqueue);
  53. end;
  54. function TMultiReadExclusiveWriteSynchronizer.Beginwrite : boolean;
  55. begin
  56. { wait for any other writers that may be in progress }
  57. System.EnterCriticalSection(fwritelock);
  58. { it is possible that earlier on we missed waiting on the
  59. fwaitingwriterlock and that it's still set (must be done
  60. after acquiring the fwritelock, because otherwise one
  61. writer could reset the fwaitingwriterlock of another one
  62. that's about to wait on it) }
  63. RTLeventResetEvent(fwaitingwriterlock);
  64. { new readers have to block from now on; writers get priority to avoid
  65. writer starvation (since they have to compete with potentially many
  66. concurrent readers and other writers) }
  67. BasicEventResetEvent(freaderqueue);
  68. { for quick checking by candidate-readers -- use interlockedincrement/
  69. decrement instead of setting 1/0, because a single thread can
  70. recursively acquire the write lock multiple times }
  71. System.InterlockedIncrement(fwritelocked);
  72. { wait until all readers are gone -- freadercount and fwritelocked are only
  73. accessed using atomic operations (that's why we use
  74. InterLockedExchangeAdd(x,0) below) -> always in-order. The writer always
  75. first sets fwritelocked and then checks freadercount, while the readers
  76. always first increase freadercount and then check fwritelocked }
  77. while (System.InterLockedExchangeAdd(freadercount,0)<>0) do
  78. RTLEventWaitFor(fwaitingwriterlock);
  79. { Make sure that out-of-order execution cannot already perform reads
  80. inside the critical section before the lock has been acquired }
  81. ReadBarrier;
  82. { we have the writer lock, and all readers are gone }
  83. result:=true;
  84. end;
  85. procedure TMultiReadExclusiveWriteSynchronizer.Endwrite;
  86. begin
  87. { Finish all writes inside the section so that everything executing
  88. afterwards will certainly see these results }
  89. WriteBarrier;
  90. { signal potential readers that the coast is clear if all recursive
  91. write locks have been freed }
  92. if System.InterlockedDecrement(fwritelocked)=0 then
  93. begin
  94. { wake up waiting readers (if any); do not check first whether freadercount
  95. is <> 0, because the InterlockedDecrement in the while loop of BeginRead
  96. can have already occurred, so a single reader may be about to wait on
  97. freaderqueue even though freadercount=0. Setting an event multiple times
  98. is no problem. }
  99. BasicEventSetEvent(freaderqueue);
  100. end;
  101. { free the writer lock so another writer can become active }
  102. System.LeaveCriticalSection(fwritelock);
  103. end;
  104. procedure TMultiReadExclusiveWriteSynchronizer.Beginread;
  105. Const
  106. wrSignaled = 0;
  107. wrTimeout = 1;
  108. wrAbandoned= 2;
  109. wrError = 3;
  110. begin
  111. System.InterlockedIncrement(freadercount);
  112. { wait until there is no more writer }
  113. while System.InterLockedExchangeAdd(fwritelocked,0)<>0 do
  114. begin
  115. { there's a writer busy or wanting to start -> wait until it's
  116. finished; a writer may already be blocked in the mean time, so
  117. wake it up if we're the last to go to sleep }
  118. if System.InterlockedDecrement(freadercount)=0 then
  119. RTLEventSetEvent(fwaitingwriterlock);
  120. if (BasicEventWaitFor(high(cardinal),freaderqueue) in [wrAbandoned,wrError]) then
  121. raise Exception.create('BasicEventWaitFor failed in TMultiReadExclusiveWriteSynchronizer.Beginread');
  122. { and try again: first increase freadercount, only then check
  123. fwritelocked }
  124. System.InterlockedIncrement(freadercount);
  125. end;
  126. { Make sure that out-of-order execution cannot perform reads
  127. inside the critical section before the lock has been acquired }
  128. ReadBarrier;
  129. end;
  130. procedure TMultiReadExclusiveWriteSynchronizer.Endread;
  131. begin
  132. { If no more readers, wake writer in the ready-queue if any. Since a writer
  133. always first atomically sets fwritelocked and then atomically checks the
  134. freadercount, first modifying freadercount and then checking fwritelock
  135. ensures that we cannot miss one of the events regardless of execution
  136. order. }
  137. if (System.InterlockedDecrement(freadercount)=0) and
  138. (System.InterLockedExchangeAdd(fwritelocked,0)<>0) then
  139. RTLEventSetEvent(fwaitingwriterlock);
  140. end;
  141. {$endif FPC_HAS_FEATURE_THREADING}