unit ps4_time; {$mode objfpc}{$H+} interface uses sys_types; const CLOCK_REALTIME =0; CLOCK_VIRTUAL =1; CLOCK_PROF =2; CLOCK_MONOTONIC =4; CLOCK_UPTIME =5; // FreeBSD-specific. CLOCK_UPTIME_PRECISE =7; // FreeBSD-specific. CLOCK_UPTIME_FAST =8; // FreeBSD-specific. CLOCK_REALTIME_PRECISE =9; // FreeBSD-specific. CLOCK_REALTIME_FAST =10; // FreeBSD-specific. CLOCK_MONOTONIC_PRECISE=11; // FreeBSD-specific. CLOCK_MONOTONIC_FAST =12; // FreeBSD-specific. CLOCK_SECOND =13; // FreeBSD-specific. CLOCK_THREAD_CPUTIME_ID=14; CLOCK_PROCTIME =15; // ORBIS only CLOCK_EXT_NETWORK =16; // ORBIS only CLOCK_EXT_DEBUG_NETWORK=17; // ORBIS only CLOCK_EXT_AD_NETWORK =18; // ORBIS only CLOCK_EXT_RAW_NETWORK =19; // ORBIS only function _pthread_time_in_ms:QWORD; //Milisecond function _pthread_rel_time_in_ms(const ts:timespec):QWORD; //Milisecond function _pthread_time_in_ns:QWORD; //Nanosecond function _pthread_rel_time_in_ns(const ts:timespec):QWORD; //Nanosecond function ps4_gettimeofday(tv:Ptimeval;tz:Ptimezone):Integer; SysV_ABI_CDecl; function ps4_clock_getres(clock_id:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl; function ps4_clock_gettime(clock_id:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl; function ps4_sceKernelClockGetres(clock_id:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl; function ps4_sceKernelGettimeofday(tv:Ptimeval):Integer; SysV_ABI_CDecl; function ps4_sceKernelGettimezone(tz:Ptimezone):Integer; SysV_ABI_CDecl; function ps4_clock_settime(clock_id:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl; function ps4_settimeofday(tv:Ptimeval;tz:Ptimezone):Integer; SysV_ABI_CDecl; function ps4_sceKernelSettimeofday(tv:Ptimeval;tz:Ptimezone):Integer; SysV_ABI_CDecl; function ps4_sceKernelGetTscFrequency():QWORD; SysV_ABI_CDecl; function ps4_sceKernelReadTsc():QWORD; SysV_ABI_CDecl; function ps4_sceKernelClockGettime(clockId:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl; function ps4_sceKernelGetProcessTime:QWORD; SysV_ABI_CDecl; //microseconds function ps4_sceKernelGetProcessTimeCounterFrequency:QWORD; SysV_ABI_CDecl; //microseconds*10 function ps4_sceKernelGetProcessTimeCounter:QWORD; SysV_ABI_CDecl; //microseconds*10 function ps4_nanosleep(req,rem:Ptimespec):Integer; SysV_ABI_CDecl; //nanoseconds function ps4_sceKernelNanosleep(req,rem:Ptimespec):Integer; SysV_ABI_CDecl; //nanoseconds function ps4_usleep(usec:DWORD):Integer; SysV_ABI_CDecl; //microseconds function ps4_sceKernelUsleep(usec:DWORD):Integer; SysV_ABI_CDecl; //microseconds function ps4_sleep(sec:DWORD):DWORD; SysV_ABI_CDecl; //second function ps4_sceKernelSleep(sec:DWORD):DWORD; SysV_ABI_CDecl; //second type ptimesec=^timesec; timesec=packed record tz_time :time_t; tz_secwest:DWORD; tz_dstsec :DWORD; end; function ps4_sceKernelConvertUtcToLocaltime(_time:time_t; local_time:ptime_t; _tsec:ptimesec; _dstsec:PDWORD):Integer; SysV_ABI_CDecl; function ps4_sceKernelConvertLocaltimeToUtc(_time:time_t; unknow:qword; utc_time:ptime_t; _tsec:ptimesec; _dstsec:PDWORD):Integer; SysV_ABI_CDecl; implementation Uses Windows, ntapi, sys_kernel, sys_signal, sys_time; function _pthread_time_in_ms:QWORD; //Milisecond var ts:timespec; begin ts:=Default(timespec); ps4_clock_gettime(CLOCK_REALTIME,@ts); Result:=_time_in_ms_from_timespec(ts); end; function _pthread_rel_time_in_ms(const ts:timespec):QWORD; //Milisecond var t1,t2:QWORD; begin t1:=_time_in_ms_from_timespec(ts); t2:=_pthread_time_in_ms; if (t1nil) then begin tv^.tv_sec :=tp.tv_sec; tv^.tv_usec:=(tp.tv_nsec div 1000); end; end; function ps4_sceKernelGettimeofday(tv:Ptimeval):Integer; SysV_ABI_CDecl; Var tp:timespec; begin Result:=Swgetntptimeofday(@tp,nil); _set_errno(Result); Result:=px2sce(Result); if (Result=0) and (tv<>nil) then begin tv^.tv_sec :=tp.tv_sec; tv^.tv_usec:=(tp.tv_nsec div 1000); end; end; function ps4_sceKernelGettimezone(tz:Ptimezone):Integer; SysV_ABI_CDecl; begin Swgettimezone(tz); Result:=_set_errno(0); end; function ps4_clock_settime(clock_id:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl; begin Result:=_set_errno(EPERM); end; function ps4_settimeofday(tv:Ptimeval;tz:Ptimezone):Integer; SysV_ABI_CDecl; begin Result:=_set_errno(EPERM); end; function ps4_sceKernelSettimeofday(tv:Ptimeval;tz:Ptimezone):Integer; SysV_ABI_CDecl; begin _set_errno(EPERM); Result:=px2sce(EPERM); end; function ps4_clock_getres(clock_id:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl; begin if (tp=nil) then Exit(_set_errno(EINVAL)); Result:=_set_errno(0); case clock_id of CLOCK_SECOND: begin tp^.tv_sec :=1; tp^.tv_nsec:=0; end; CLOCK_PROCTIME, CLOCK_THREAD_CPUTIME_ID, CLOCK_REALTIME, CLOCK_REALTIME_PRECISE, CLOCK_REALTIME_FAST: begin tp^.tv_sec :=0; tp^.tv_nsec:=100; end; CLOCK_MONOTONIC, CLOCK_MONOTONIC_PRECISE, CLOCK_MONOTONIC_FAST: begin tp^.tv_sec :=0; tp^.tv_nsec:=100; end; else Result:=_set_errno(EINVAL); end; end; function ps4_sceKernelClockGetres(clock_id:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl; begin Result:=ps4_clock_getres(clock_id,tp); if (Result<>0) then begin Result:=px2sce(PInteger(_error)^); end; end; function mul_div_u64(m,d,v:QWORD):QWORD; sysv_abi_default; assembler; nostackframe; asm movq v,%rax mulq m divq d end; function ps4_clock_gettime(clock_id:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl; var pc,pf:QWORD; begin if (tp=nil) then Exit(_set_errno(EINVAL)); Result:=_set_errno(0); case clock_id of CLOCK_SECOND: begin SwGetSystemTimeAsFileTime(TFILETIME(pc)); pc:=pc-DELTA_EPOCH_IN_100NS; tp^.tv_sec :=pc div POW10_7; tp^.tv_nsec:=0; end; CLOCK_REALTIME, CLOCK_REALTIME_PRECISE, CLOCK_REALTIME_FAST: begin SwGetSystemTimeAsFileTime(TFILETIME(pc)); pc:=pc-DELTA_EPOCH_IN_100NS; tp^.tv_sec :=(pc div POW10_7); tp^.tv_nsec:=(pc mod POW10_7)*100; end; CLOCK_EXT_NETWORK , CLOCK_EXT_DEBUG_NETWORK, CLOCK_EXT_AD_NETWORK , CLOCK_EXT_RAW_NETWORK , CLOCK_MONOTONIC, CLOCK_MONOTONIC_PRECISE, CLOCK_MONOTONIC_FAST: begin SwQueryPerformanceCounter(pc,pf); pc:=mul_div_u64(POW10_7,pf,pc); tp^.tv_sec :=(pc div POW10_7); tp^.tv_nsec:=(pc mod POW10_7)*100; end; CLOCK_PROCTIME: begin if SwGetProcessTime(pc) then begin tp^.tv_sec :=(pc div POW10_7); tp^.tv_nsec:=(pc mod POW10_7)*100; end else begin Result:=_set_errno(EINVAL); end; end; CLOCK_THREAD_CPUTIME_ID: begin if SwGetThreadTime(pc) then begin tp^.tv_sec :=(pc div POW10_7); tp^.tv_nsec:=(pc mod POW10_7)*100; end else begin Result:=_set_errno(EINVAL); end; end else Result:=_set_errno(EINVAL); end; end; function ps4_sceKernelGetTscFrequency():QWORD; SysV_ABI_CDecl; begin Result:=POW10_7; end; function ps4_sceKernelReadTsc():QWORD; SysV_ABI_CDecl; var pc,pf:QWORD; begin SwQueryPerformanceCounter(pc,pf); Result:=mul_div_u64(POW10_7,pf,pc); end; function ps4_sceKernelClockGettime(clockId:Integer;tp:Ptimespec):Integer; SysV_ABI_CDecl; begin Result:=ps4_clock_gettime(clockId,tp); end; function ps4_sceKernelGetProcessTime:QWORD; SysV_ABI_CDecl; //microseconds begin if SwGetProcessTime(Result) then begin Result:=Result div 10; end else begin _set_errno(EINVAL); Result:=0; end; end; function ps4_sceKernelGetProcessTimeCounterFrequency:QWORD; SysV_ABI_CDecl; //microseconds*10 begin Result:=HECTONANOSEC_PER_SEC; end; function ps4_sceKernelGetProcessTimeCounter:QWORD; SysV_ABI_CDecl; //microseconds*10 begin if SwGetProcessTime(Result) then begin // end else begin _set_errno(EINVAL); Result:=0; end; end; //1sec=10 000 000 //lpUserTime/ 10 000 000 *1 000 000 //lpUserTime/ 10 *1 function _nanosleep(req,rem:Ptimespec):Integer; var timeout:Int64; passed :Int64; START:QWORD; begin //test_cancel if (req=nil) then Exit(EINVAL); timeout:=_time_in_ns_from_timespec(req^); // //timeout:=((timeout+99999999) div 100000000)*100000000; // timeout:=-((timeout+99) div 100); //in 100ns START:=0; if (rem<>nil) then begin SwSaveTime(START); end; Case SwDelayExecution(True,@timeout) of STATUS_USER_APC, STATUS_KERNEL_APC, STATUS_ALERTED: //signal interrupt begin if (rem<>nil) then begin timeout:=-timeout; passed:=SwTimePassedUnits(START); if (passed>=timeout) then begin rem^:=Default(timespec); end else begin timeout:=timeout-passed; timeout:=timeout*100; //100ns to ns rem^.tv_sec :=timeout div POW10_9; rem^.tv_nsec:=timeout mod POW10_9; end; end; Result:=EINTR; end; else begin if (rem<>nil) then begin rem^:=Default(timespec); end; Result:=0; end; end; //test_cancel end; function ps4_nanosleep(req,rem:Ptimespec):Integer; SysV_ABI_CDecl; //nanoseconds begin Result:=_set_errno(_nanosleep(req,rem)); end; function ps4_sceKernelNanosleep(req,rem:Ptimespec):Integer; SysV_ABI_CDecl; //nanoseconds var tmp:timespec; begin tmp:=Default(timespec); repeat Result:=_nanosleep(req,@tmp); _set_errno(Result); if (Result=0) then begin if (rem<>nil) then begin rem^:=tmp; end; Exit; end; req:=@tmp; until (Result<>EINTR); Result:=px2sce(Result); end; function ps4_usleep(usec:DWORD):Integer; SysV_ABI_CDecl; //microseconds var time:timespec; begin //test_cancel time.tv_sec :=usec div 1000000; time.tv_nsec:=((usec mod 1000000)*1000); Result:=_set_errno(_nanosleep(@time,nil)); //test_cancel end; function ps4_sceKernelUsleep(usec:DWORD):Integer; SysV_ABI_CDecl; //microseconds var req,rem:timespec; begin rem:=Default(timespec); req.tv_sec :=usec div 1000000; req.tv_nsec:=((usec mod 1000000)*1000); repeat Result:=_nanosleep(@req,@rem); _set_errno(Result); if (Result=0) then Exit; req:=rem; until (Result<>EINTR); Result:=px2sce(Result); end; function _sleep(sec:DWORD):DWORD; var req,rem:timespec; ret,rsec:DWORD; begin rem:=Default(timespec); if (Integer(sec)<0) then begin req.tv_sec :=$7fffffff; req.tv_nsec:=0; ret:=_nanosleep(@req,@rem); _set_errno(ret); rsec:=0; if (ret<>0) then begin if (ret=EINTR) then begin rsec:=(Integer(rem.tv_sec)+1)-DWORD(rem.tv_nsec=0); end; end; Result:=sec+$80000001+rsec; end else begin req.tv_sec :=sec; req.tv_nsec:=0; ret:=_nanosleep(@req,@rem); _set_errno(ret); Result:=0; if (ret<>0) then begin Result:=sec; if (ret=EINTR) then begin Result:=(Integer(rem.tv_sec)+1)-DWORD(rem.tv_nsec=0); end; end; end; end; function ps4_sleep(sec:DWORD):DWORD; SysV_ABI_CDecl; //second begin //test_cancel Result:=_sleep(sec); //test_cancel end; function ps4_sceKernelSleep(sec:DWORD):DWORD; SysV_ABI_CDecl; //second begin repeat //test_cancel sec:=_sleep(sec); //test_cancel until (sec=0); Result:=0; end; // function ps4_sceKernelConvertUtcToLocaltime(_time:time_t; local_time:ptime_t; _tsec:ptimesec; _dstsec:PDWORD):Integer; SysV_ABI_CDecl; var tmz:timezone; perror:pinteger; begin Result:=ps4_gettimeofday(nil,@tmz); if (Result<0) then begin perror:=_error; if (perror<>nil) then begin Result:=px2sce(perror^); end; Exit; end; if (local_time<>nil) then begin local_time^:=(tmz.tz_minuteswest+tmz.tz_dsttime)*60+_time; end; if (_tsec<>nil) then begin _tsec^.tz_time :=_time; _tsec^.tz_secwest:=tmz.tz_minuteswest*60; _tsec^.tz_dstsec :=tmz.tz_dsttime*60; end; if (_dstsec<>nil) then begin _dstsec^:=tmz.tz_dsttime*60; end; end; function ps4_sceKernelConvertLocaltimeToUtc(_time:time_t; unknow:qword; utc_time:ptime_t; _tsec:ptimesec; _dstsec:PDWORD):Integer; SysV_ABI_CDecl; var tmz:timezone; rtime:time_t; perror:pinteger; begin Result:=ps4_gettimeofday(nil,@tmz); if (Result<0) then begin perror:=_error; if (perror<>nil) then begin Result:=px2sce(perror^); end; Exit; end; rtime:=_time-((tmz.tz_minuteswest+tmz.tz_dsttime)*60); if (utc_time<>nil) then begin utc_time^:=rtime; end; if (_tsec<>nil) then begin _tsec^.tz_time :=rtime; _tsec^.tz_secwest:=tmz.tz_minuteswest*60; _tsec^.tz_dstsec :=tmz.tz_dsttime*60; end; if (_dstsec<>nil) then begin _dstsec^:=tmz.tz_dsttime*60; end; end; Procedure Init; var min,max,cur:ULONG; begin NtQueryTimerResolution(@min,@max,@cur); NtSetTimerResolution(max,True,@cur); end; initialization Init; end.