forked from ahausladen/WeakObjectReferences
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathCritSectMonitor.pas
More file actions
99 lines (83 loc) · 2.69 KB
/
CritSectMonitor.pas
File metadata and controls
99 lines (83 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
unit CritSectMonitor;
interface
uses
Windows;
type
PCritSectMonitor = ^TCritSectMonitor;
TCritSectMonitor = record
private
FCriticalSection: TRTLCriticalSection;
FInitialized: Integer;
procedure Initialize;
class procedure DestroyCritSect(Data: Pointer); static;
class function GetCriticalSection(const AObject: TObject): PCritSectMonitor; static;
public
class procedure Enter(const AObject: TObject); static;
class function TryEnter(const AObject: TObject): Boolean; static;
class procedure Exit(const AObject: TObject); static;
class procedure SetSpinCount(const AObject: TObject; ASpinCount: Integer); static;
end;
implementation
uses
WeakObjectReferences;
var
CritSectMonitorOffset: Integer;
CPUCount: Integer;
class procedure TCritSectMonitor.DestroyCritSect(Data: Pointer);
begin
if PCritSectMonitor(Data).FInitialized <> 0 then
begin
while PCritSectMonitor(Data).FInitialized > 0 do // wait till the initialiation is over
if CPUCount = 1 then
SwitchToThread;
DeleteCriticalSection(PCritSectMonitor(Data).FCriticalSection);
end;
end;
procedure TCritSectMonitor.Initialize;
begin
try
if InterlockedIncrement(FInitialized) = 1 then
InitializeCriticalSectionAndSpinCount(FCriticalSection, 4000)
else
begin
while FInitialized > 0 do // spinning
if CPUCount = 1 then
SwitchToThread;
end;
finally
FInitialized := -1; // release the lock and mark as initialized
end;
end;
class function TCritSectMonitor.GetCriticalSection(const AObject: TObject): PCritSectMonitor;
begin
Result := PCritSectMonitor(TInternalWeakReferenceHelper.GetAdditionalData(AObject, CritSectMonitorOffset));
if Result.FInitialized >= 0 then
Result.Initialize;
end;
class procedure TCritSectMonitor.SetSpinCount(const AObject: TObject; ASpinCount: Integer);
begin
SetCriticalSectionSpinCount(GetCriticalSection(AObject).FCriticalSection, DWORD(ASpinCount));
end;
class procedure TCritSectMonitor.Enter(const AObject: TObject);
begin
EnterCriticalSection(GetCriticalSection(AObject).FCriticalSection);
end;
class function TCritSectMonitor.TryEnter(const AObject: TObject): Boolean;
begin
Result := TryEnterCriticalSection(GetCriticalSection(AObject).FCriticalSection);
end;
class procedure TCritSectMonitor.Exit(const AObject: TObject);
begin
LeaveCriticalSection(GetCriticalSection(AObject).FCriticalSection);
end;
procedure Init;
var
SystemInfo: TSystemInfo;
begin
GetSystemInfo(SystemInfo);
CPUCount := SystemInfo.dwNumberOfProcessors;
CritSectMonitorOffset := TInternalWeakReferenceHelper.RegisterAdditionalData(SizeOf(TCritSectMonitor), TCritSectMonitor.DestroyCritSect);
end;
initialization
Init;
end.