Ver Fonte

Fix for webtbs/tw11006.pp and test/tbs/tb0632.pp instability.
* Add ThreadQueueLockCounter variable to
postpone call to DoneCriticlSection to the last thread
that decrements back the counter to zero.
* CommonCleanup:
Protect ThreadQueue emptying within
a Enter/Leave-CriticalSection to avoid access y other
threads at the same time.

git-svn-id: trunk@38626 -

pierre há 7 anos atrás
pai
commit
921b406c05
1 ficheiros alterados com 25 adições e 7 exclusões
  1. 25 7
      rtl/objpas/classes/classes.inc

+ 25 - 7
rtl/objpas/classes/classes.inc

@@ -80,6 +80,8 @@ var
   ThreadQueueTail: TThread.PThreadQueueEntry;
   { used for serialized access to the queue }
   ThreadQueueLock: TRtlCriticalSection;
+  { usage counter for ThreadQueueLock }
+  ThreadQueueLockCounter : longint;
   { this list holds all instances of external threads that need to be freed at
     the end of the program }
   ExternalThreads: TThreadList;
@@ -224,6 +226,9 @@ constructor TThread.Create(CreateSuspended: Boolean;
                            const StackSize: SizeUInt);
 begin
   inherited Create;
+{$ifdef FPC_HAS_FEATURE_THREADING}
+    InterlockedIncrement(ThreadQueueLockCounter);
+{$endif}
   if FExternalThread then
 {$ifdef FPC_HAS_FEATURE_THREADING}
     FThreadID := GetCurrentThreadID
@@ -246,6 +251,10 @@ begin
   end;
   RemoveQueuedEvents(Self);
   DoneSynchronizeEvent;
+{$ifdef FPC_HAS_FEATURE_THREADING}
+  if InterlockedDecrement(ThreadQueueLockCounter)=0 then
+    DoneCriticalSection(ThreadQueueLock);
+{$endif}
   { set CurrentThreadVar to Nil? }
   inherited Destroy;
 end;
@@ -2454,6 +2463,7 @@ procedure CommonInit;
 begin
 {$ifdef FPC_HAS_FEATURE_THREADING}
   SynchronizeTimeoutEvent:=RtlEventCreate;
+  InterlockedIncrement(ThreadQueueLockCounter);
   InitCriticalSection(ThreadQueueLock);
   MainThreadID:=GetCurrentThreadID;
 {$else}
@@ -2522,17 +2532,25 @@ begin
   FreeAndNil(ExternalThreads);
 {$ifdef FPC_HAS_FEATURE_THREADING}
   RtlEventDestroy(SynchronizeTimeoutEvent);
+  try
+    System.EnterCriticalSection(ThreadQueueLock);
 {$endif}
   { clean up the queue, but keep in mind that the entries used for Synchronize
     are owned by the corresponding TThread }
-  while Assigned(ThreadQueueHead) do begin
-    tmpentry := ThreadQueueHead;
-    ThreadQueueHead := tmpentry^.Next;
-    if not Assigned(tmpentry^.SyncEvent) then
-      Dispose(tmpentry);
-  end;
+    while Assigned(ThreadQueueHead) do begin
+      tmpentry := ThreadQueueHead;
+      ThreadQueueHead := tmpentry^.Next;
+      if not Assigned(tmpentry^.SyncEvent) then
+        Dispose(tmpentry);
+    end;
+    { We also need to reset ThreadQueueTail }
+    ThreadQueueTail := nil;
 {$ifdef FPC_HAS_FEATURE_THREADING}
-  DoneCriticalSection(ThreadQueueLock);
+  finally
+    System.LeaveCriticalSection(ThreadQueueLock);
+  end;
+  if InterlockedDecrement(ThreadQueueLockCounter)=0 then
+    DoneCriticalSection(ThreadQueueLock);
 {$endif}
 end;