|
@@ -26,7 +26,7 @@ uses
|
|
{$ELSE}{$IFDEF LINUX} {$linklib c} ctypes, {$ENDIF LINUX}
|
|
{$ELSE}{$IFDEF LINUX} {$linklib c} ctypes, {$ENDIF LINUX}
|
|
{$IFDEF WINDOWS} Windows, {$ENDIF WINDOWS}
|
|
{$IFDEF WINDOWS} Windows, {$ENDIF WINDOWS}
|
|
{$IF DEFINED(DARWIN) OR DEFINED(FREEBSD)} ctypes, sysctl, {$ENDIF}
|
|
{$IF DEFINED(DARWIN) OR DEFINED(FREEBSD)} ctypes, sysctl, {$ENDIF}
|
|
- {$ENDIF} Variants, math, typinfo, UMemory;
|
|
|
|
|
|
+ {$ENDIF} Variants, math, typinfo, UMemory, syncobjs;
|
|
|
|
|
|
{ CONSTANTS }
|
|
{ CONSTANTS }
|
|
|
|
|
|
@@ -302,18 +302,37 @@ type
|
|
|
|
|
|
{ Event Support}
|
|
{ Event Support}
|
|
|
|
|
|
- TNotifyEventEx = procedure (sender : TObject; const args: array of Pointer) of object;
|
|
|
|
- TNotifyManyEvent = TArray<TNotifyEvent>;
|
|
|
|
- TNotifyManyEventEx = TArray<TNotifyEventEx>;
|
|
|
|
|
|
+ TNotifyManyEvent = record
|
|
|
|
+ Handlers: TArray<TNotifyEvent>;
|
|
|
|
+ MainThreadHandlers : TArray<TNotifyEvent>;
|
|
|
|
+ end;
|
|
|
|
+
|
|
TNotifyManyEventHelper = record helper for TNotifyManyEvent
|
|
TNotifyManyEventHelper = record helper for TNotifyManyEvent
|
|
- procedure Add(listener : TNotifyEvent);
|
|
|
|
- procedure Remove(listener : TNotifyEvent);
|
|
|
|
|
|
+ procedure Add(AHandler : TNotifyEvent; ExecuteMainThread : Boolean = False);
|
|
|
|
+ procedure Remove(AHandler : TNotifyEvent);
|
|
procedure Invoke(sender : TObject);
|
|
procedure Invoke(sender : TObject);
|
|
end;
|
|
end;
|
|
- TNotifyManyEventExHelper = record helper for TNotifyManyEventEx
|
|
|
|
- procedure Add(listener : TNotifyEventEx);
|
|
|
|
- procedure Remove(listener : TNotifyEventEx);
|
|
|
|
- procedure Invoke(sender : TObject; const args: array of Pointer);
|
|
|
|
|
|
+
|
|
|
|
+ { TThreadNotify }
|
|
|
|
+
|
|
|
|
+ TThreadNotify = class
|
|
|
|
+ type
|
|
|
|
+ TPendingNotifyManyEvent = record
|
|
|
|
+ Sender : TObject;
|
|
|
|
+ Handlers : TArray<TNotifyEvent>;
|
|
|
|
+ end;
|
|
|
|
+ private
|
|
|
|
+ FTargetThread : TThread;
|
|
|
|
+ FLock : TCriticalSection;
|
|
|
|
+ FPendingNotifications : TList<TPendingNotifyManyEvent>;
|
|
|
|
+ procedure InvokePendingOnTargetThread;
|
|
|
|
+ public
|
|
|
|
+ constructor Create(ATargetThread : TThread);
|
|
|
|
+ destructor Destroy; override;
|
|
|
|
+ procedure Invoke(Sender: TObject; Handler : TNotifyEvent); overload;
|
|
|
|
+ procedure Invoke(Sender: TObject; const Handlers: TArray<TNotifyEvent>); overload;
|
|
|
|
+ class procedure InvokeMainThread(Sender: TObject; Handler : TNotifyEvent); overload;
|
|
|
|
+ class procedure InvokeMainThread(Sender: TObject; const Handlers: TArray<TNotifyEvent>); overload;
|
|
end;
|
|
end;
|
|
|
|
|
|
{ TArrayTool }
|
|
{ TArrayTool }
|
|
@@ -384,14 +403,11 @@ type
|
|
class procedure AppendText(const AFileName: string; const AText: string);
|
|
class procedure AppendText(const AFileName: string; const AText: string);
|
|
end;
|
|
end;
|
|
|
|
|
|
- { TLogicalCPUCount }
|
|
|
|
|
|
+ { TCPUTool }
|
|
|
|
|
|
- TLogicalCPUCount = class sealed(TObject)
|
|
|
|
-
|
|
|
|
- public
|
|
|
|
|
|
+ TCPUTool = class
|
|
//returns number of cores: a computer with two hyperthreaded cores will report 4
|
|
//returns number of cores: a computer with two hyperthreaded cores will report 4
|
|
class function GetLogicalCPUCount(): Int32; static;
|
|
class function GetLogicalCPUCount(): Int32; static;
|
|
-
|
|
|
|
end;
|
|
end;
|
|
|
|
|
|
resourcestring
|
|
resourcestring
|
|
@@ -428,11 +444,12 @@ const
|
|
{$ENDIF LINUX}
|
|
{$ENDIF LINUX}
|
|
{$ENDIF}
|
|
{$ENDIF}
|
|
|
|
|
|
|
|
+
|
|
var
|
|
var
|
|
MinTimeStampDateTime : TDateTime = 0;
|
|
MinTimeStampDateTime : TDateTime = 0;
|
|
VarTrue : Variant;
|
|
VarTrue : Variant;
|
|
VarFalse : Variant;
|
|
VarFalse : Variant;
|
|
-
|
|
|
|
|
|
+ GMainThreadNotify : TThreadNotify;
|
|
|
|
|
|
{ Global helper functions }
|
|
{ Global helper functions }
|
|
|
|
|
|
@@ -1396,44 +1413,105 @@ end;
|
|
|
|
|
|
{ TNotifyManyEventHelper }
|
|
{ TNotifyManyEventHelper }
|
|
|
|
|
|
-procedure TNotifyManyEventHelper.Add(listener : TNotifyEvent);
|
|
|
|
|
|
+procedure TNotifyManyEventHelper.Add(AHandler : TNotifyEvent; ExecuteMainThread : Boolean = False);
|
|
begin
|
|
begin
|
|
- if TArrayTool<TNotifyEvent>.IndexOf(self, listener) = -1 then begin
|
|
|
|
- TArrayTool<TNotifyEvent>.Add(self, listener);
|
|
|
|
|
|
+ if NOT ExecuteMainThread then begin
|
|
|
|
+ if TArrayTool<TNotifyEvent>.IndexOf(self.Handlers, AHandler) = -1 then
|
|
|
|
+ TArrayTool<TNotifyEvent>.Add(self.Handlers, AHandler)
|
|
|
|
+ end else begin
|
|
|
|
+ if TArrayTool<TNotifyEvent>.IndexOf(self.MainThreadHandlers, AHandler) = -1 then
|
|
|
|
+ TArrayTool<TNotifyEvent>.Add(self.MainThreadHandlers, AHandler);
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TNotifyManyEventHelper.Remove(listener : TNotifyEvent);
|
|
|
|
|
|
+procedure TNotifyManyEventHelper.Remove(AHandler : TNotifyEvent);
|
|
begin
|
|
begin
|
|
- TArrayTool<TNotifyEvent>.Remove(self, listener);
|
|
|
|
|
|
+ TArrayTool<TNotifyEvent>.Remove(self.Handlers, AHandler);
|
|
|
|
+ TArrayTool<TNotifyEvent>.Remove(self.MainThreadHandlers, AHandler);
|
|
end;
|
|
end;
|
|
|
|
|
|
procedure TNotifyManyEventHelper.Invoke(sender : TObject);
|
|
procedure TNotifyManyEventHelper.Invoke(sender : TObject);
|
|
var i : Integer;
|
|
var i : Integer;
|
|
begin
|
|
begin
|
|
- for i := low(self) to high(self) do
|
|
|
|
- self[i](sender);
|
|
|
|
|
|
+ for i := low(self.Handlers) to high(self.Handlers) do
|
|
|
|
+ self.Handlers[i](sender);
|
|
|
|
+
|
|
|
|
+ if Length(self.MainThreadHandlers) > 0 then
|
|
|
|
+ TThreadNotify.InvokeMainThread(sender, self.MainThreadHandlers);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+{ TThreadNotify }
|
|
|
|
+
|
|
|
|
+constructor TThreadNotify.Create(ATargetThread : TThread);
|
|
|
|
+begin
|
|
|
|
+ FTargetThread := ATargetThread;
|
|
|
|
+ FLock := TCriticalSection.Create;
|
|
|
|
+ FPendingNotifications := TList<TPendingNotifyManyEvent>.Create;
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TNotifyManyEventHelperEx }
|
|
|
|
|
|
+destructor TThreadNotify.Destroy;
|
|
|
|
+begin
|
|
|
|
+ FTargetThread := nil;
|
|
|
|
+ FLock.Acquire;
|
|
|
|
+ try
|
|
|
|
+ FPendingNotifications.Destroy;
|
|
|
|
+ finally
|
|
|
|
+ FLock.Release;
|
|
|
|
+ FLock.Destroy;
|
|
|
|
+ end;
|
|
|
|
+end;
|
|
|
|
|
|
-procedure TNotifyManyEventExHelper.Add(listener : TNotifyEventEx);
|
|
|
|
|
|
+procedure TThreadNotify.InvokePendingOnTargetThread;
|
|
|
|
+var
|
|
|
|
+ LPendings : TArray<TPendingNotifyManyEvent>;
|
|
|
|
+ LPending : TPendingNotifyManyEvent;
|
|
|
|
+ LNotify : TNotifyEvent;
|
|
|
|
+begin
|
|
|
|
+ if (NOT Assigned(FTargetThread)) OR (NOT Assigned(FLock)) OR (NOT Assigned(FPendingNotifications)) then
|
|
|
|
+ exit;
|
|
|
|
+
|
|
|
|
+ if TThread.CurrentThread.ThreadID = FTargetThread.ThreadID then begin
|
|
|
|
+ FLock.Acquire;
|
|
|
|
+ try
|
|
|
|
+ LPendings := FPendingNotifications.ToArray;
|
|
|
|
+ FPendingNotifications.Clear;
|
|
|
|
+ finally
|
|
|
|
+ FLock.Release;
|
|
|
|
+ end;
|
|
|
|
+ for LPending in LPendings do
|
|
|
|
+ for LNotify in LPending.Handlers do
|
|
|
|
+ LNotify(LPending.Sender);
|
|
|
|
+ end else TThread.Queue(FTargetThread, InvokePendingOnTargetThread);
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TThreadNotify.Invoke(Sender: TObject; Handler : TNotifyEvent);
|
|
|
|
+begin
|
|
|
|
+ Invoke(Sender, TArrayTool<TNotifyEvent>.Create(Handler));
|
|
|
|
+end;
|
|
|
|
+
|
|
|
|
+procedure TThreadNotify.Invoke(Sender: TObject; const Handlers: TArray<TNotifyEvent>);
|
|
|
|
+var
|
|
|
|
+ LPending : TPendingNotifyManyEvent;
|
|
begin
|
|
begin
|
|
- if TArrayTool<TNotifyEventEx>.IndexOf(self, listener) = -1 then begin
|
|
|
|
- TArrayTool<TNotifyEventEx>.Add(self, listener);
|
|
|
|
|
|
+ FLock.Acquire;
|
|
|
|
+ try
|
|
|
|
+ LPending.Sender := Sender;
|
|
|
|
+ LPending.Handlers := Handlers;
|
|
|
|
+ FPendingNotifications.Add(LPending);
|
|
|
|
+ finally
|
|
|
|
+ FLock.Release;
|
|
end;
|
|
end;
|
|
|
|
+ InvokePendingOnTargetThread;
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TNotifyManyEventExHelper.Remove(listener : TNotifyEventEx);
|
|
|
|
|
|
+class procedure TThreadNotify.InvokeMainThread(Sender: TObject; Handler : TNotifyEvent);
|
|
begin
|
|
begin
|
|
- TArrayTool<TNotifyEventEx>.Remove(self, listener);
|
|
|
|
|
|
+ InvokeMainThread(Sender, TArrayTool<TNotifyEvent>.Create(Handler));
|
|
end;
|
|
end;
|
|
|
|
|
|
-procedure TNotifyManyEventExHelper.Invoke(sender : TObject; const args: array of Pointer);
|
|
|
|
-var i : Integer;
|
|
|
|
|
|
+class procedure TThreadNotify.InvokeMainThread(Sender: TObject; const Handlers: TArray<TNotifyEvent>);
|
|
begin
|
|
begin
|
|
- for i := Low(Self) to high(Self) do
|
|
|
|
- self[i](sender, args);
|
|
|
|
|
|
+ GMainThreadNotify.Invoke(Sender, Handlers);
|
|
end;
|
|
end;
|
|
|
|
|
|
{ TArrayTool }
|
|
{ TArrayTool }
|
|
@@ -1861,9 +1939,9 @@ begin
|
|
end;
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
|
|
-{ TLogicalCPUCount }
|
|
|
|
|
|
+{ TCPUTool }
|
|
|
|
|
|
-class function TLogicalCPUCount.GetLogicalCPUCount(): Int32;
|
|
|
|
|
|
+class function TCPUTool.GetLogicalCPUCount(): Int32;
|
|
{$IFDEF FPC}
|
|
{$IFDEF FPC}
|
|
{$IFDEF WINDOWS}
|
|
{$IFDEF WINDOWS}
|
|
var
|
|
var
|
|
@@ -1930,7 +2008,9 @@ initialization
|
|
MinTimeStampDateTime:= StrToDateTime('1980-01-01 00:00:000', IntlDateTimeFormat);
|
|
MinTimeStampDateTime:= StrToDateTime('1980-01-01 00:00:000', IntlDateTimeFormat);
|
|
VarTrue := True;
|
|
VarTrue := True;
|
|
VarFalse := False;
|
|
VarFalse := False;
|
|
|
|
+ GMainThreadNotify := TThreadNotify.Create ( TThread.CurrentThread ); // unit initialization runs in main thread
|
|
|
|
|
|
finalization
|
|
finalization
|
|
|
|
+ FreeAndNil(GMainThreadNotify);
|
|
|
|
|
|
end.
|
|
end.
|