diff options
-rw-r--r-- | rtl/linux/pthread.inc | 3 | ||||
-rw-r--r-- | rtl/unix/cthreads.pp | 91 |
2 files changed, 87 insertions, 7 deletions
diff --git a/rtl/linux/pthread.inc b/rtl/linux/pthread.inc index a584fb09b7..50522c9994 100644 --- a/rtl/linux/pthread.inc +++ b/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_condattr_init(__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_delete(__key:pthread_key_t):longint;cdecl;external; function pthread_setspecific(__key:pthread_key_t; __pointer:pointer):longint;cdecl;external; @@ -228,6 +229,7 @@ Var {$ifndef ANDROID} pthread_condattr_init : 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} 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; @@ -321,6 +323,7 @@ begin {$ifndef ANDROID} Pointer(pthread_condattr_init) := dlsym(PthreadDLL,'pthread_condattr_init'); Pointer(pthread_condattr_destroy) := dlsym(PthreadDLL,'pthread_condattr_destroy'); + Pointer(pthread_condattr_setclock) := dlsym(PthreadDLL,'pthread_condattr_setclock'); {$endif} Pointer(pthread_key_create) := dlsym(PthreadDLL,'pthread_key_create'); Pointer(pthread_key_delete) := dlsym(PthreadDLL,'pthread_key_delete'); diff --git a/rtl/unix/cthreads.pp b/rtl/unix/cthreads.pp index 2aeb9414e3..0ea07e3530 100644 --- a/rtl/unix/cthreads.pp +++ b/rtl/unix/cthreads.pp @@ -67,6 +67,9 @@ Procedure SetCThreadManager; implementation Uses +{$if defined(Linux) and not defined(Android)} + Linux, +{$endif} BaseUnix, unix, unixtype, @@ -547,6 +550,10 @@ type TPthreadMutex = pthread_mutex_t; Tbasiceventstate=record FCondVar: TPthreadCondition; +{$if defined(Linux) and not defined(Android)} + FAttr: pthread_condattr_t; + FClockID: longint; +{$ifend} FEventSection: TPthreadMutex; FWaiters: longint; FIsSet, @@ -565,19 +572,67 @@ Const function IntBasicEventCreate(EventAttributes : Pointer; AManualReset,InitialState : Boolean;const Name : ansistring):pEventState; var MAttr : pthread_mutexattr_t; - res : cint; + res : cint; +{$if defined(Linux) and not defined(Android)} + timespec: ttimespec; +{$ifend} begin new(plocaleventstate(result)); plocaleventstate(result)^.FManualReset:=AManualReset; plocaleventstate(result)^.FWaiters:=0; plocaleventstate(result)^.FDestroying:=False; 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 begin + pthread_condattr_destroy(@plocaleventstate(result)^.FAttr); FreeMem(result); fpc_threaderror; 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); if res=0 then @@ -595,6 +650,9 @@ begin if res <> 0 then begin pthread_cond_destroy(@plocaleventstate(result)^.FCondVar); +{$if defined(Linux) and not defined(Android)} + pthread_condattr_destroy(@plocaleventstate(result)^.FAttr); +{$ifend} FreeMem(result); fpc_threaderror; end; @@ -616,6 +674,9 @@ begin { and clean up } 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); dispose(plocaleventstate(state)); end; @@ -646,6 +707,7 @@ var isset: boolean; tnow : timeval; begin + { safely check whether we are being destroyed, if so immediately return. } { otherwise (under the same mutex) increase the number of waiters } pthread_mutex_lock(@plocaleventstate(state)^.feventsection); @@ -668,17 +730,32 @@ begin else begin //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_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 begin inc(timespec.tv_sec); dec(timespec.tv_nsec, 1000000000); 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; isset := plocaleventstate(state)^.FIsSet; |