Browse Source

--- Merging r43589 into '.':
U rtl/linux/pthread.inc
U rtl/unix/cthreads.pp
--- Recording mergeinfo for merge of r43589 into '.':
U .

# revisions: 43589
r43589 | florian | 2019-11-25 21:58:18 +0100 (Mon, 25 Nov 2019) | 1 line
Changed paths:
M /trunk/rtl/linux/pthread.inc
M /trunk/rtl/unix/cthreads.pp

* patch by Benjamin Rosseaux: TEvent.WaitFor on *nix uses Monotonic Clock now

git-svn-id: branches/fixes_3_2@45460 -

marco 5 years ago
parent
commit
42a7ca2a92
2 changed files with 87 additions and 7 deletions
  1. 3 0
      rtl/linux/pthread.inc
  2. 84 7
      rtl/unix/cthreads.pp

+ 3 - 0
rtl/linux/pthread.inc

@@ -153,6 +153,7 @@ Type
     function pthread_cond_timedwait(__cond:ppthread_cond_t; __mutex:ppthread_mutex_t; __abstime:ptimespec):longint;cdecl;external;
     function pthread_cond_timedwait(__cond:ppthread_cond_t; __mutex:ppthread_mutex_t; __abstime:ptimespec):longint;cdecl;external;
     function pthread_condattr_init(__attr:ppthread_condattr_t):longint;cdecl;external;
     function pthread_condattr_init(__attr:ppthread_condattr_t):longint;cdecl;external;
     function pthread_condattr_destroy(__attr:ppthread_condattr_t):longint;cdecl;external;
     function pthread_condattr_destroy(__attr:ppthread_condattr_t):longint;cdecl;external;
+    function pthread_condattr_setclock(__attr:ppthread_condattr_t; __clock_id: longint):longint;cdecl;external;
     function pthread_key_create(__key:ppthread_key_t; __destr_function:__destr_function_t):longint;cdecl;external;
     function pthread_key_create(__key:ppthread_key_t; __destr_function:__destr_function_t):longint;cdecl;external;
     function pthread_key_delete(__key:pthread_key_t):longint;cdecl;external;
     function pthread_key_delete(__key:pthread_key_t):longint;cdecl;external;
     function pthread_setspecific(__key:pthread_key_t; __pointer:pointer):longint;cdecl;external;
     function pthread_setspecific(__key:pthread_key_t; __pointer:pointer):longint;cdecl;external;
@@ -228,6 +229,7 @@ Var
 {$ifndef ANDROID}
 {$ifndef ANDROID}
     pthread_condattr_init : Function(__attr:ppthread_condattr_t):longint;cdecl;
     pthread_condattr_init : Function(__attr:ppthread_condattr_t):longint;cdecl;
     pthread_condattr_destroy : Function(__attr:ppthread_condattr_t):longint;cdecl;
     pthread_condattr_destroy : Function(__attr:ppthread_condattr_t):longint;cdecl;
+    pthread_condattr_setclock: Function(__attr:ppthread_condattr_t; __clock_id: longint):longint;cdecl;
 {$endif}
 {$endif}
     pthread_key_create : Function(__key:ppthread_key_t; __destr_function:__destr_function_t):longint;cdecl;
     pthread_key_create : Function(__key:ppthread_key_t; __destr_function:__destr_function_t):longint;cdecl;
     pthread_key_delete : Function(__key:pthread_key_t):longint;cdecl;
     pthread_key_delete : Function(__key:pthread_key_t):longint;cdecl;
@@ -321,6 +323,7 @@ begin
 {$ifndef ANDROID}
 {$ifndef ANDROID}
   Pointer(pthread_condattr_init) := dlsym(PthreadDLL,'pthread_condattr_init');
   Pointer(pthread_condattr_init) := dlsym(PthreadDLL,'pthread_condattr_init');
   Pointer(pthread_condattr_destroy) := dlsym(PthreadDLL,'pthread_condattr_destroy');
   Pointer(pthread_condattr_destroy) := dlsym(PthreadDLL,'pthread_condattr_destroy');
+  Pointer(pthread_condattr_setclock) := dlsym(PthreadDLL,'pthread_condattr_setclock');
 {$endif}
 {$endif}
   Pointer(pthread_key_create) := dlsym(PthreadDLL,'pthread_key_create');
   Pointer(pthread_key_create) := dlsym(PthreadDLL,'pthread_key_create');
   Pointer(pthread_key_delete) := dlsym(PthreadDLL,'pthread_key_delete');
   Pointer(pthread_key_delete) := dlsym(PthreadDLL,'pthread_key_delete');

+ 84 - 7
rtl/unix/cthreads.pp

@@ -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;