Pārlūkot izejas kodu

Initialize the heap lock in DLL_PROCESS_ATTACH and finalize in DLL_PROCESS_DETACH.

Rika Ichinose 2 nedēļas atpakaļ
vecāks
revīzija
78f7d0bd1e
5 mainītis faili ar 57 papildinājumiem un 23 dzēšanām
  1. 32 10
      rtl/inc/heap.inc
  2. 5 1
      rtl/inc/heaph.inc
  3. 5 11
      rtl/inc/oldheap.inc
  4. 9 1
      rtl/win/systlsdir.inc
  5. 6 0
      rtl/win/syswin.inc

+ 32 - 10
rtl/inc/heap.inc

@@ -452,7 +452,10 @@ type
     {$endif FPC_HAS_FEATURE_THREADING}
     {$endif FPC_HAS_FEATURE_THREADING}
     end;
     end;
 
 
-    GlobalState = record
+    GlobalState = object
+    const
+      LockInitializedProcessWide = -1; { Special lockUse value to support DLL_PROCESS_ATTACH / DLL_PROCESS_DETACH-like mechanism. }
+    var
       hugeUsed: SizeUint; { Same as non-existing “hugeAllocated” as huge chunks don’t have free space.
       hugeUsed: SizeUint; { Same as non-existing “hugeAllocated” as huge chunks don’t have free space.
                             Atomic, but can be read unprotected if unreliability is tolerable.
                             Atomic, but can be read unprotected if unreliability is tolerable.
                             Huge chunks don’t have thread affinity, so are tracked here. Presently, this value is added to all memory statistics.
                             Huge chunks don’t have thread affinity, so are tracked here. Presently, this value is added to all memory statistics.
@@ -461,6 +464,7 @@ type
     {$ifdef FPC_HAS_FEATURE_THREADING}
     {$ifdef FPC_HAS_FEATURE_THREADING}
       lock: TRTLCriticalSection;
       lock: TRTLCriticalSection;
       lockUse: int32;
       lockUse: int32;
+      askedForProcessWideLockInitialization: boolean;
 
 
       { Like ThreadState.varFree but over orphaned OS chunks. Protected by gs.lock. }
       { Like ThreadState.varFree but over orphaned OS chunks. Protected by gs.lock. }
       varFree: VarFreeMap;
       varFree: VarFreeMap;
@@ -1629,7 +1633,7 @@ type
     lastFree, nextFree: pFreeOSChunk;
     lastFree, nextFree: pFreeOSChunk;
   {$endif not HAS_SYSOSFREE}
   {$endif not HAS_SYSOSFREE}
   begin
   begin
-    if gs.lockUse > 0 then
+    if gs.lockUse <> 0 then
       EnterCriticalSection(HeapInc.gs.lock);
       EnterCriticalSection(HeapInc.gs.lock);
     FlushToFree; { Performing it under gs.lock guarantees there will be no new toFree requests. }
     FlushToFree; { Performing it under gs.lock guarantees there will be no new toFree requests. }
     FreeEmptyArenas; { Has to free all empty arenas, otherwise the chunk that contains only empty arenas can leak. }
     FreeEmptyArenas; { Has to free all empty arenas, otherwise the chunk that contains only empty arenas can leak. }
@@ -1666,7 +1670,7 @@ type
       vOs := vOs^.next;
       vOs := vOs^.next;
     end;
     end;
     varOS := nil;
     varOS := nil;
-    if gs.lockUse > 0 then
+    if gs.lockUse <> 0 then
       LeaveCriticalSection(gs.lock);
       LeaveCriticalSection(gs.lock);
 
 
 {$ifdef HAS_SYSOSFREE}
 {$ifdef HAS_SYSOSFREE}
@@ -1923,15 +1927,34 @@ end;
                                  InitHeap
                                  InitHeap
 *****************************************************************************}
 *****************************************************************************}
 
 
+{$ifdef FPC_HAS_FEATURE_THREADING}
+{ DeferInitHeapProcessWide / DoneHeapProcessWide are meant to support DLL_PROCESS_ATTACH / DLL_PROCESS_DETACH.
+  Otherwise InitHeapThread + FinalizeHeap called per thread do their best with refcounting... }
+procedure DeferInitHeapProcessWide;
+begin
+  HeapInc.gs.askedForProcessWideLockInitialization := true; { Called before InitSystemThreads, cannot initialize the lock... }
+end;
+
+procedure DoneHeapProcessWide;
+begin
+  if HeapInc.gs.lockUse = HeapInc.gs.LockInitializedProcessWide then
+  begin
+    HeapInc.gs.lockUse := 0;
+    DoneCriticalSection(HeapInc.gs.lock);
+  end;
+end;
+
 { This function will initialize the Heap manager and need to be called from
 { This function will initialize the Heap manager and need to be called from
   the initialization of the system unit }
   the initialization of the system unit }
-{$ifdef FPC_HAS_FEATURE_THREADING}
 procedure InitHeapThread;
 procedure InitHeapThread;
 begin
 begin
-  if HeapInc.gs.lockUse>0 then
-    InterlockedIncrement(HeapInc.gs.lockUse);
+  if (HeapInc.gs.lockUse = 0) and HeapInc.gs.askedForProcessWideLockInitialization then
+    HeapInc.gs.lockUse := HeapInc.gs.LockInitializedProcessWide
+  else if not ((HeapInc.gs.lockUse >= 0) and ({$ifdef VER3_2} InterlockedIncrement {$else} AtomicIncrement {$endif} (HeapInc.gs.lockUse) = 1)) then
+    exit;
+  InitCriticalSection(HeapInc.gs.lock);
 end;
 end;
-{$endif}
+{$endif FPC_HAS_FEATURE_THREADING}
 
 
 procedure InitHeap; public name '_FPC_InitHeap';
 procedure InitHeap; public name '_FPC_InitHeap';
 begin
 begin
@@ -1942,10 +1965,9 @@ end;
 procedure RelocateHeap;
 procedure RelocateHeap;
 begin
 begin
 {$ifdef FPC_HAS_FEATURE_THREADING}
 {$ifdef FPC_HAS_FEATURE_THREADING}
-  if HeapInc.gs.lockUse > 0 then
+  if HeapInc.gs.lockUse <> 0 then
     exit;
     exit;
-  HeapInc.gs.lockUse := 1;
-  InitCriticalSection(HeapInc.gs.lock);
+  InitHeapThread; { Initializes the lock and sets lockUse = 1 (or maybe LockInitializedProcessWide). }
 {$ifndef FPC_SECTION_THREADVARS}
 {$ifndef FPC_SECTION_THREADVARS}
   { threadState pointers still point to main thread's thisTs, but they
   { threadState pointers still point to main thread's thisTs, but they
     have a reference to the global main thisTs, fix them to point
     have a reference to the global main thisTs, fix them to point

+ 5 - 1
rtl/inc/heaph.inc

@@ -99,5 +99,9 @@ function ReAllocMem(var p:pointer;Size:ptruint):pointer; inline;
 function ReAllocMemory(p:pointer;Size:ptruint):pointer; cdecl;
 function ReAllocMemory(p:pointer;Size:ptruint):pointer; cdecl;
 function GetHeapStatus:THeapStatus;
 function GetHeapStatus:THeapStatus;
 function GetFPCHeapStatus:TFPCHeapStatus;
 function GetFPCHeapStatus:TFPCHeapStatus;
-{$endif FPC_HAS_FEATURE_HEAP}
 
 
+{$if defined(FPC_HAS_FEATURE_THREADING) and not defined(FPC_NO_DEFAULT_HEAP) and not defined(LEGACYHEAP)}
+procedure DeferInitHeapProcessWide; inline; { for Windows sysinit.pp... }
+procedure DoneHeapProcessWide; inline;
+{$endif FPC_HAS_FEATURE_THREADING and not FPC_NO_DEFAULT_HEAP and not LEGACYHEAP}
+{$endif FPC_HAS_FEATURE_HEAP}

+ 5 - 11
rtl/inc/oldheap.inc

@@ -1578,12 +1578,11 @@ procedure InitHeapThread;
 var
 var
   loc_freelists: pfreelists;
   loc_freelists: pfreelists;
 begin
 begin
-  if heap_lock_use > 0 then
-  begin
-    EnterCriticalSection(heap_lock);
-    inc(heap_lock_use);
-    LeaveCriticalSection(heap_lock);
-  end;
+  if heap_lock_use = 0 then
+    InitCriticalSection(heap_lock);
+  EnterCriticalSection(heap_lock);
+  inc(heap_lock_use);
+  LeaveCriticalSection(heap_lock);
   loc_freelists := @freelists;
   loc_freelists := @freelists;
   fillchar(loc_freelists^,sizeof(tfreelists),0);
   fillchar(loc_freelists^,sizeof(tfreelists),0);
   { initialise the local blocksize for allocating oschunks for fixed
   { initialise the local blocksize for allocating oschunks for fixed
@@ -1600,17 +1599,12 @@ procedure InitHeap; public name '_FPC_InitHeap';
 var
 var
   loc_freelists: pfreelists;
   loc_freelists: pfreelists;
 begin
 begin
-{$ifdef FPC_HAS_FEATURE_THREADING}
   { we cannot initialize the locks here yet, thread support is
   { we cannot initialize the locks here yet, thread support is
     not loaded yet }
     not loaded yet }
-  heap_lock_use := 0;
-{$endif}
   loc_freelists := @freelists;
   loc_freelists := @freelists;
-  fillchar(loc_freelists^,sizeof(tfreelists),0);
   { initialise the local blocksize for allocating oschunks for fixed
   { initialise the local blocksize for allocating oschunks for fixed
     freelists with the default starting value }
     freelists with the default starting value }
   loc_freelists^.locgrowheapsizesmall:=growheapsizesmall;
   loc_freelists^.locgrowheapsizesmall:=growheapsizesmall;
-  fillchar(orphaned_freelists,sizeof(orphaned_freelists),0);
 end;
 end;
 
 
 procedure RelocateHeap;
 procedure RelocateHeap;

+ 9 - 1
rtl/win/systlsdir.inc

@@ -84,9 +84,17 @@ procedure Exec_Tls_callback(Handle : pointer; reason : Dword; Reserved : pointer
            SetupEntryInformation(SysInitEntryInformation);
            SetupEntryInformation(SysInitEntryInformation);
            {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
            {$endif FPC_HAS_INDIRECT_ENTRY_INFORMATION}
            InitHeap;
            InitHeap;
+         {$ifndef LEGACYHEAP}
+           DeferInitHeapProcessWide;
+         {$endif ndef LEGACYHEAP}
            InitSystemThreads;
            InitSystemThreads;
          end;
          end;
-
+       DLL_PROCESS_DETACH :
+         begin
+         {$ifndef LEGACYHEAP}
+           DoneHeapProcessWide;
+         {$endif ndef LEGACYHEAP}
+         end;
        DLL_THREAD_ATTACH :
        DLL_THREAD_ATTACH :
          begin
          begin
          {  !!! SysInitMultithreading must NOT be called here. Windows guarantees that
          {  !!! SysInitMultithreading must NOT be called here. Windows guarantees that

+ 6 - 0
rtl/win/syswin.inc

@@ -408,6 +408,9 @@ function Dll_entry{$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}(constref info : TE
 {$ifdef FPC_USE_SEH}
 {$ifdef FPC_USE_SEH}
                try
                try
 {$endif}
 {$endif}
+{$ifndef LEGACYHEAP}
+               DeferInitHeapProcessWide;
+{$endif ndef LEGACYHEAP}
 {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
 {$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}
                EntryInformation.PascalMain();
                EntryInformation.PascalMain();
 {$else FPC_HAS_INDIRECT_ENTRY_INFORMATION}
 {$else FPC_HAS_INDIRECT_ENTRY_INFORMATION}
@@ -460,6 +463,9 @@ function Dll_entry{$ifdef FPC_HAS_INDIRECT_ENTRY_INFORMATION}(constref info : TE
            SysReleaseThreadVars;
            SysReleaseThreadVars;
            { Free TLS resources used by ThreadVars }
            { Free TLS resources used by ThreadVars }
            SysFiniMultiThreading;
            SysFiniMultiThreading;
+{$ifndef LEGACYHEAP}
+           DoneHeapProcessWide;
+{$endif ndef LEGACYHEAP}
            MainThreadIDWin32:=0;
            MainThreadIDWin32:=0;
          end;
          end;
      end;
      end;