|
@@ -67,6 +67,9 @@ Procedure SetCThreadManager;
|
|
implementation
|
|
implementation
|
|
|
|
|
|
Uses
|
|
Uses
|
|
|
|
+{$if defined(Linux) and not defined(Android)}
|
|
|
|
+ Linux,
|
|
|
|
+{$endif}
|
|
BaseUnix,
|
|
BaseUnix,
|
|
unix,
|
|
unix,
|
|
unixtype,
|
|
unixtype,
|
|
@@ -547,6 +550,10 @@ type
|
|
TPthreadMutex = pthread_mutex_t;
|
|
TPthreadMutex = pthread_mutex_t;
|
|
Tbasiceventstate=record
|
|
Tbasiceventstate=record
|
|
FCondVar: TPthreadCondition;
|
|
FCondVar: TPthreadCondition;
|
|
|
|
+{$if defined(Linux) and not defined(Android)}
|
|
|
|
+ FAttr: pthread_condattr_t;
|
|
|
|
+ FClockID: longint;
|
|
|
|
+{$ifend}
|
|
FEventSection: TPthreadMutex;
|
|
FEventSection: TPthreadMutex;
|
|
FWaiters: longint;
|
|
FWaiters: longint;
|
|
FIsSet,
|
|
FIsSet,
|
|
@@ -565,19 +572,67 @@ Const
|
|
function IntBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
|
|
function IntBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState;
|
|
var
|
|
var
|
|
MAttr : pthread_mutexattr_t;
|
|
MAttr : pthread_mutexattr_t;
|
|
- res : cint;
|
|
|
|
|
|
+ res : cint;
|
|
|
|
+{$if defined(Linux) and not defined(Android)}
|
|
|
|
+ timespec: ttimespec;
|
|
|
|
+{$ifend}
|
|
begin
|
|
begin
|
|
new(plocaleventstate(result));
|
|
new(plocaleventstate(result));
|
|
plocaleventstate(result)^.FManualReset:=AManualReset;
|
|
plocaleventstate(result)^.FManualReset:=AManualReset;
|
|
plocaleventstate(result)^.FWaiters:=0;
|
|
plocaleventstate(result)^.FWaiters:=0;
|
|
plocaleventstate(result)^.FDestroying:=False;
|
|
plocaleventstate(result)^.FDestroying:=False;
|
|
plocaleventstate(result)^.FIsSet:=InitialState;
|
|
plocaleventstate(result)^.FIsSet:=InitialState;
|
|
- res := pthread_cond_init(@plocaleventstate(result)^.FCondVar, nil);
|
|
|
|
|
|
+{$if defined(Linux) and not defined(Android)}
|
|
|
|
+ res := pthread_condattr_init(@plocaleventstate(result)^.FAttr);
|
|
|
|
+ if (res <> 0) then
|
|
|
|
+ begin
|
|
|
|
+ FreeMem(result);
|
|
|
|
+ fpc_threaderror;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if clock_gettime(CLOCK_MONOTONIC_RAW, @timespec) = 0 then
|
|
|
|
+ begin
|
|
|
|
+ res := pthread_condattr_setclock(@plocaleventstate(result)^.FAttr, CLOCK_MONOTONIC_RAW);
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ res := -1; // No support for CLOCK_MONOTONIC_RAW
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ if (res = 0) then
|
|
|
|
+ begin
|
|
|
|
+ plocaleventstate(result)^.FClockID := CLOCK_MONOTONIC_RAW;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ res := pthread_condattr_setclock(@plocaleventstate(result)^.FAttr, CLOCK_MONOTONIC);
|
|
|
|
+ if (res = 0) then
|
|
|
|
+ begin
|
|
|
|
+ plocaleventstate(result)^.FClockID := CLOCK_MONOTONIC;
|
|
|
|
+ end
|
|
|
|
+ else
|
|
|
|
+ begin
|
|
|
|
+ pthread_condattr_destroy(@plocaleventstate(result)^.FAttr);
|
|
|
|
+ FreeMem(result);
|
|
|
|
+ fpc_threaderror;
|
|
|
|
+ end;
|
|
|
|
+ end;
|
|
|
|
+
|
|
|
|
+ res := pthread_cond_init(@plocaleventstate(result)^.FCondVar, @plocaleventstate(result)^.FAttr);
|
|
if (res <> 0) then
|
|
if (res <> 0) then
|
|
begin
|
|
begin
|
|
|
|
+ pthread_condattr_destroy(@plocaleventstate(result)^.FAttr);
|
|
FreeMem(result);
|
|
FreeMem(result);
|
|
fpc_threaderror;
|
|
fpc_threaderror;
|
|
end;
|
|
end;
|
|
|
|
+{$else}
|
|
|
|
+ res := pthread_cond_init(@plocaleventstate(result)^.FCondVar, nil);
|
|
|
|
+ if (res <> 0) then
|
|
|
|
+ begin
|
|
|
|
+ FreeMem(result);
|
|
|
|
+ fpc_threaderror;
|
|
|
|
+ end;
|
|
|
|
+{$ifend}
|
|
|
|
|
|
res:=pthread_mutexattr_init(@MAttr);
|
|
res:=pthread_mutexattr_init(@MAttr);
|
|
if res=0 then
|
|
if res=0 then
|
|
@@ -595,6 +650,9 @@ begin
|
|
if res <> 0 then
|
|
if res <> 0 then
|
|
begin
|
|
begin
|
|
pthread_cond_destroy(@plocaleventstate(result)^.FCondVar);
|
|
pthread_cond_destroy(@plocaleventstate(result)^.FCondVar);
|
|
|
|
+{$if defined(Linux) and not defined(Android)}
|
|
|
|
+ pthread_condattr_destroy(@plocaleventstate(result)^.FAttr);
|
|
|
|
+{$ifend}
|
|
FreeMem(result);
|
|
FreeMem(result);
|
|
fpc_threaderror;
|
|
fpc_threaderror;
|
|
end;
|
|
end;
|
|
@@ -616,6 +674,9 @@ begin
|
|
|
|
|
|
{ and clean up }
|
|
{ and clean up }
|
|
pthread_cond_destroy(@plocaleventstate(state)^.Fcondvar);
|
|
pthread_cond_destroy(@plocaleventstate(state)^.Fcondvar);
|
|
|
|
+{$if defined(Linux) and not defined(Android)}
|
|
|
|
+ pthread_condattr_destroy(@plocaleventstate(state)^.FAttr);
|
|
|
|
+{$ifend}
|
|
pthread_mutex_destroy(@plocaleventstate(state)^.FEventSection);
|
|
pthread_mutex_destroy(@plocaleventstate(state)^.FEventSection);
|
|
dispose(plocaleventstate(state));
|
|
dispose(plocaleventstate(state));
|
|
end;
|
|
end;
|
|
@@ -646,6 +707,7 @@ var
|
|
isset: boolean;
|
|
isset: boolean;
|
|
tnow : timeval;
|
|
tnow : timeval;
|
|
begin
|
|
begin
|
|
|
|
+
|
|
{ safely check whether we are being destroyed, if so immediately return. }
|
|
{ safely check whether we are being destroyed, if so immediately return. }
|
|
{ otherwise (under the same mutex) increase the number of waiters }
|
|
{ otherwise (under the same mutex) increase the number of waiters }
|
|
pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
|
|
pthread_mutex_lock(@plocaleventstate(state)^.feventsection);
|
|
@@ -668,17 +730,32 @@ begin
|
|
else
|
|
else
|
|
begin
|
|
begin
|
|
//Wait with timeout using pthread_cond_timedwait
|
|
//Wait with timeout using pthread_cond_timedwait
|
|
- fpgettimeofday(@tnow,nil);
|
|
|
|
|
|
+{$if defined(Linux) and not defined(Android)}
|
|
|
|
+ if clock_gettime(plocaleventstate(state)^.FClockID, @timespec) <> 0 then
|
|
|
|
+ begin
|
|
|
|
+ Result := Ord(wrError);
|
|
|
|
+ Exit;
|
|
|
|
+ end;
|
|
|
|
+ timespec.tv_sec := timespec.tv_sec + (clong(timeout) div 1000);
|
|
|
|
+ timespec.tv_nsec := ((clong(timeout) mod 1000) * 1000000) + (timespec.tv_nsec);
|
|
|
|
+{$else}
|
|
|
|
+ // TODO: FIX-ME: Also use monotonic clock for other *nix targets
|
|
|
|
+ fpgettimeofday(@tnow, nil);
|
|
timespec.tv_sec := tnow.tv_sec + (clong(timeout) div 1000);
|
|
timespec.tv_sec := tnow.tv_sec + (clong(timeout) div 1000);
|
|
- timespec.tv_nsec := (clong(timeout) mod 1000)*1000000 + tnow.tv_usec*1000;
|
|
|
|
|
|
+ timespec.tv_nsec := ((clong(timeout) mod 1000) * 1000000) + (tnow.tv_usec * 1000);
|
|
|
|
+{$ifend}
|
|
if timespec.tv_nsec >= 1000000000 then
|
|
if timespec.tv_nsec >= 1000000000 then
|
|
begin
|
|
begin
|
|
inc(timespec.tv_sec);
|
|
inc(timespec.tv_sec);
|
|
dec(timespec.tv_nsec, 1000000000);
|
|
dec(timespec.tv_nsec, 1000000000);
|
|
end;
|
|
end;
|
|
- errres:=0;
|
|
|
|
- while (not plocaleventstate(state)^.FDestroying) and (not plocaleventstate(state)^.FIsSet) and (errres<>ESysETIMEDOUT) do
|
|
|
|
- errres:=pthread_cond_timedwait(@plocaleventstate(state)^.Fcondvar, @plocaleventstate(state)^.feventsection, @timespec);
|
|
|
|
|
|
+ errres := 0;
|
|
|
|
+ while (not plocaleventstate(state)^.FDestroying) and
|
|
|
|
+ (not plocaleventstate(state)^.FIsSet) and
|
|
|
|
+ (errres<>ESysETIMEDOUT) do
|
|
|
|
+ errres := pthread_cond_timedwait(@plocaleventstate(state)^.Fcondvar,
|
|
|
|
+ @plocaleventstate(state)^.feventsection,
|
|
|
|
+ @timespec);
|
|
end;
|
|
end;
|
|
|
|
|
|
isset := plocaleventstate(state)^.FIsSet;
|
|
isset := plocaleventstate(state)^.FIsSet;
|