FPPS4/sys/kern/kern_thr.pas

595 lines
15 KiB
Plaintext

unit kern_thr;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
uses
mqueue,
ucontext,
signal,
signalvar,
sys_event,
kern_mtx;
const
TDS_INACTIVE =0;
TDS_INHIBITED=1;
TDS_CAN_RUN =2;
TDS_RUNQ =3;
TDS_RUNNING =4;
TDF_BORROWING =$00000001; // Thread is borrowing pri from another.
TDF_INPANIC =$00000002; // Caused a panic, let it drive crashdump.
TDF_INMEM =$00000004; // Thread's stack is in memory.
TDF_SINTR =$00000008; // Sleep is interruptible.
TDF_TIMEOUT =$00000010; // Timing out during sleep.
TDF_IDLETD =$00000020; // This is a per-CPU idle thread.
TDF_CANSWAP =$00000040; // Thread can be swapped.
TDF_SLEEPABORT =$00000080; // sleepq_abort was called.
TDF_KTH_SUSP =$00000100; // kthread is suspended
TDF_UNUSED09 =$00000200; // --available--
TDF_BOUNDARY =$00000400; // Thread suspended at user boundary
TDF_ASTPENDING =$00000800; // Thread has some asynchronous events.
TDF_TIMOFAIL =$00001000; // Timeout from sleep after we were awake.
TDF_SBDRY =$00002000; // Stop only on usermode boundary.
TDF_UPIBLOCKED =$00004000; // Thread blocked on user PI mutex.
TDF_NEEDSUSPCHK=$00008000; // Thread may need to suspend.
TDF_NEEDRESCHED=$00010000; // Thread needs to yield.
TDF_NEEDSIGCHK =$00020000; // Thread may need signal delivery.
TDF_NOLOAD =$00040000; // Ignore during load avg calculations.
TDF_UNUSED19 =$00080000; // --available--
TDF_THRWAKEUP =$00100000; // Libthr thread must not suspend itself.
TDF_UNUSED21 =$00200000; // --available--
TDF_SWAPINREQ =$00400000; // Swapin request due to wakeup.
TDF_UNUSED23 =$00800000; // --available--
TDF_SCHED0 =$01000000; // Reserved for scheduler private use
TDF_SCHED1 =$02000000; // Reserved for scheduler private use
TDF_SCHED2 =$04000000; // Reserved for scheduler private use
TDF_SCHED3 =$08000000; // Reserved for scheduler private use
TDF_ALRMPEND =$10000000; // Pending SIGVTALRM needs to be posted.
TDF_PROFPEND =$20000000; // Pending SIGPROF needs to be posted.
TDF_MACPEND =$40000000; // AST-based MAC event pending.
TDF_SLICEEND =TDF_SCHED2; // Thread time slice is over.
TDF_SUSP_CTX =$80000000; // Sony extension
//
TDP_OLDMASK =$00000001; // Need to restore mask after suspend.
TDP_INKTR =$00000002; // Thread is currently in KTR code.
TDP_INKTRACE =$00000004; // Thread is currently in KTRACE code.
TDP_BUFNEED =$00000008; // Do not recurse into the buf flush
TDP_COWINPROGRESS=$00000010; // Snapshot copy-on-write in progress.
TDP_ALTSTACK =$00000020; // Have alternate signal stack.
TDP_DEADLKTREAT =$00000040; // Lock aquisition - deadlock treatment.
TDP_NOFAULTING =$00000080; // Do not handle page faults.
TDP_NOSLEEPING =$00000100; // Thread is not allowed to sleep on a sq.
TDP_OWEUPC =$00000200; // Call addupc() at next AST.
TDP_ITHREAD =$00000400; // Thread is an interrupt thread.
TDP_SYNCIO =$00000800; // Local override, disable async i/o.
TDP_SCHED1 =$00001000; // Reserved for scheduler private use
TDP_SCHED2 =$00002000; // Reserved for scheduler private use
TDP_SCHED3 =$00004000; // Reserved for scheduler private use
TDP_SCHED4 =$00008000; // Reserved for scheduler private use
TDP_GEOM =$00010000; // Settle GEOM before finishing syscall
TDP_SOFTDEP =$00020000; // Stuck processing softdep worklist
TDP_NORUNNINGBUF =$00040000; // Ignore runningbufspace check
TDP_WAKEUP =$00080000; // Don't sleep in umtx cond_wait
TDP_INBDFLUSH =$00100000; // Already in BO_BDFLUSH, do not recurse
TDP_KTHREAD =$00200000; // This is an official kernel thread
TDP_CALLCHAIN =$00400000; // Capture thread's callchain
TDP_IGNSUSP =$00800000; // Permission to ignore the MNTK_SUSPEND*
TDP_AUDITREC =$01000000; // Audit record pending on thread
TDP_RFPPWAIT =$02000000; // Handle RFPPWAIT on syscall exit
TDP_RESETSPUR =$04000000; // Reset spurious page fault history.
TDP_NERRNO =$08000000; // Last errno is already in td_errno
TDP_UIOHELD =$10000000; // Current uio has pages held in td_ma
TDP_DEVMEMIO =$20000000; // Accessing memory for /dev/mem
TDP_EXECVMSPC =$40000000; // Execve destroyed old vmspace
TDI_SUSPENDED =$0001; // On suspension queue.
TDI_SLEEPING =$0002; // Actually asleep! (tricky).
TDI_SWAPPED =$0004; // Stack not in mem. Bad juju if run.
TDI_LOCK =$0008; // Stopped on a lock.
TDI_IWAIT =$0010; // Awaiting interrupt.
TDI_SUSP_CTX =$0020; // Sony extension
THR_SUSPENDED =$0001;
// These flags are kept in p_flag.
P_ADVLOCK =$00001; // Process may hold a POSIX advisory lock.
P_CONTROLT =$00002; // Has a controlling terminal.
P_WEXIT =$02000; // Working on exiting.
P_EXEC =$04000; // Process called exec.
P_INEXEC =$4000000; // Process is in execve().
// Types and flags for mi_switch().
SW_TYPE_MASK =$ff; // First 8 bits are switch type
SWT_NONE = 0; // Unspecified switch.
SWT_PREEMPT = 1; // Switching due to preemption.
SWT_OWEPREEMPT = 2; // Switching due to opepreempt.
SWT_TURNSTILE = 3; // Turnstile contention.
SWT_SLEEPQ = 4; // Sleepq wait.
SWT_SLEEPQTIMO = 5; // Sleepq timeout wait.
SWT_RELINQUISH = 6; // yield call.
SWT_NEEDRESCHED = 7; // NEEDRESCHED was set.
SWT_IDLE = 8; // Switching from the idle thread.
SWT_IWAIT = 9; // Waiting for interrupts.
SWT_SUSPEND =10; // Thread suspended.
SWT_REMOTEPREEMPT =11; // Remote processor preempted.
SWT_REMOTEWAKEIDLE=12; // Remote processor preempted idle.
SWT_COUNT =13; // Number of switch types.
// Flags
SW_VOL =$0100; // Voluntary switch.
SW_INVOL =$0200; // Involuntary switch.
SW_PREEMPT=$0400; // The invol switch is a preemption
type
p_teb=^teb;
teb=packed record
SEH :Pointer;
stack :Pointer;
sttop :Pointer;
_align1:array[0..20] of QWORD;
wow64 :Pointer; //0x0C0
_align2:array[0..30] of QWORD;
gsbase :Pointer; //0x1C0
spare :array[0..1] of QWORD;
_align3:array[0..164] of QWORD;
thread :Pointer; //0x700
tcb :Pointer; //0x708
iflag :Integer; //0x710
end;
const
teb_wow64 =ptruint(@teb(nil^).wow64 );
teb_gsbase=ptruint(@teb(nil^).gsbase);
teb_thread=ptruint(@teb(nil^).thread);
teb_tcb =ptruint(@teb(nil^).tcb );
teb_iflag =ptruint(@teb(nil^).iflag );
{$IF teb_wow64 <>$0C0}{$STOP teb_wow64 <>$0C0}{$ENDIF}
{$IF teb_gsbase<>$1C0}{$STOP teb_gsbase<>$1C0}{$ENDIF}
{$IF teb_thread<>$700}{$STOP teb_thread<>$700}{$ENDIF}
{$IF teb_tcb <>$708}{$STOP teb_tcb <>$708}{$ENDIF}
{$IF teb_iflag <>$710}{$STOP teb_iflag <>$710}{$ENDIF}
type
t_td_name=array[0..31] of AnsiChar;
pp_kthread=^p_kthread;
p_kthread=^kthread;
kthread=record
td_umtxq :Pointer; //p_umtx_q
td_handle :THandle; //nt thread
td_teb :p_teb;
td_lock :Pointer;
td_tid :QWORD;
td_sigstk :stack_t;
td_state :Integer;
td_pflags :Integer;
td_flags :Integer;
td_errno :Integer;
pcb_flags :Integer;
td_ref :Integer;
//
td_priority :Word;
td_pri_class :Word;
td_base_pri :Word;
td_base_user_pri:Word;
td_lend_user_pri:Word;
td_user_pri :Word;
td_name :t_td_name;
//
td_cpuset :Ptruint;
td_sigmask :sigset_t;
td_oldsigmask :sigset_t;
td_sigqueue :sigqueue_t;
td_frame :trapframe;
td_fpstate :array[0..103] of QWORD;
pcb_fsbase :Pointer;
pcb_gsbase :Pointer;
td_retval :array[0..1] of QWORD;
td_ustack :packed record
stack :Pointer;
sttop :Pointer;
end;
td_kstack :packed record
stack :Pointer;
sttop :Pointer;
end;
//
td_sleepqueue :Pointer;
td_slpq :TAILQ_ENTRY;
td_wchan :Pointer;
td_sqqueue :Integer;
td_intrval :Integer;
td_inhibitors :Integer;
td_dupfd :Integer;
td_ru :packed record
ru_inblock :Int64;
ru_oublock :Int64;
ru_nsignals :Int64;
ru_nvcsw :Int64;
ru_nivcsw :Int64;
end;
td_slptick :Int64;
//
td_fpop :Pointer;
td_map_def_user :Pointer;
td_sel :Pointer;
td_vp_reserv :Int64;
end;
p_thr_param=^thr_param;
thr_param=packed record
start_func:Pointer;
arg :Pointer;
stack_base:Pointer;
stack_size:Ptruint;
tls_base :Pointer;
tls_size :Ptruint;
child_tid :PDWORD;
parent_tid:PDWORD;
flags :Integer;
align :Integer;
rtp :Pointer;
name :PChar;
spare :array[0..1] of Pointer;
end;
{$IF sizeof(thr_param)<>104}{$STOP sizeof(thr_param)<>104}{$ENDIF}
{
* pargs, used to hold a copy of the command line, if it had a sane length.
}
p_pargs=^t_pargs;
t_pargs=packed record
ar_ref :Integer; // Reference count.
ar_length:Integer; // Length.
ar_args :AnsiChar; // Arguments.
end;
function curkthread:p_kthread;
procedure set_curkthread(td:p_kthread);
function TD_IS_SLEEPING(td:p_kthread):Boolean;
function TD_ON_SLEEPQ(td:p_kthread):Boolean;
function TD_IS_SUSPENDED(td:p_kthread):Boolean;
function TD_IS_SWAPPED(td:p_kthread):Boolean;
function TD_ON_LOCK(td:p_kthread):Boolean;
function TD_AWAITING_INTR(td:p_kthread):Boolean;
function TD_IS_RUNNING(td:p_kthread):Boolean;
function TD_ON_RUNQ(td:p_kthread):Boolean;
function TD_CAN_RUN(td:p_kthread):Boolean;
function TD_IS_INHIBITED(td:p_kthread):Boolean;
function TD_ON_UPILOCK(td:p_kthread):Boolean;
function TD_IS_IDLETHREAD(td:p_kthread):Boolean;
procedure TD_SET_SLEEPING(td:p_kthread);
procedure TD_SET_SWAPPED(td:p_kthread);
procedure TD_SET_LOCK(td:p_kthread);
procedure TD_SET_SUSPENDED(td:p_kthread);
procedure TD_SET_IWAIT(td:p_kthread);
procedure TD_CLR_SLEEPING(td:p_kthread);
procedure TD_CLR_SWAPPED(td:p_kthread);
procedure TD_CLR_LOCK(td:p_kthread);
procedure TD_CLR_SUSPENDED(td:p_kthread);
procedure TD_CLR_IWAIT(td:p_kthread);
procedure TD_SET_RUNNING(td:p_kthread);
procedure TD_SET_RUNQ(td:p_kthread);
procedure TD_SET_CAN_RUN(td:p_kthread);
procedure THREAD_NO_SLEEPING();
procedure THREAD_SLEEPING_OK();
function curthread_pflags_set(flags:Integer):Integer;
procedure curthread_pflags_restore(save:Integer);
procedure PROC_LOCK;
procedure PROC_UNLOCK;
procedure PROC_INIT; //SYSINIT
function pargs_alloc(len:Integer):p_pargs;
procedure pargs_free(pa:p_pargs);
procedure pargs_hold(pa:p_pargs);
procedure pargs_drop(pa:p_pargs);
const
MAXCOMLEN=19;
var
p_proc:record
p_mtx:mtx;
p_flag :Integer;
p_osrel:Integer;
p_sdk_version:Integer;
p_sce_replay_exec:Integer;
p_ptc:Int64;
p_nsignals:Int64;
p_nvcsw :Int64;
p_nivcsw :Int64;
p_comm :array[0..MAXCOMLEN] of AnsiChar;
prog_name :array[0..1023] of AnsiChar;
p_randomized_path:array[0..7] of AnsiChar;
p_klist:t_knlist;
p_args:p_pargs;
end;
implementation
uses
kern_event,
md_time;
function curkthread:p_kthread; assembler; nostackframe;
asm
movqq %gs:teb.thread,Result
end;
procedure set_curkthread(td:p_kthread); assembler; nostackframe;
asm
movqq td,%gs:teb.thread
end;
function TD_IS_SLEEPING(td:p_kthread):Boolean;
begin
Result:=(td^.td_inhibitors and TDI_SLEEPING)<>0;
end;
function TD_ON_SLEEPQ(td:p_kthread):Boolean;
begin
Result:=(td^.td_wchan<>nil);
end;
function TD_IS_SUSPENDED(td:p_kthread):Boolean;
begin
Result:=(td^.td_inhibitors and TDI_SUSPENDED)<>0;
end;
function TD_IS_SWAPPED(td:p_kthread):Boolean;
begin
Result:=(td^.td_inhibitors and TDI_SWAPPED)<>0;
end;
function TD_ON_LOCK(td:p_kthread):Boolean;
begin
Result:=(td^.td_inhibitors and TDI_LOCK)<>0;
end;
function TD_AWAITING_INTR(td:p_kthread):Boolean;
begin
Result:=(td^.td_inhibitors and TDI_IWAIT)<>0;
end;
function TD_IS_RUNNING(td:p_kthread):Boolean;
begin
Result:=(td^.td_state=TDS_RUNNING);
end;
function TD_ON_RUNQ(td:p_kthread):Boolean;
begin
Result:=(td^.td_state=TDS_RUNQ);
end;
function TD_CAN_RUN(td:p_kthread):Boolean;
begin
Result:=(td^.td_state=TDS_CAN_RUN);
end;
function TD_IS_INHIBITED(td:p_kthread):Boolean;
begin
Result:=(td^.td_state=TDS_INHIBITED);
end;
function TD_ON_UPILOCK(td:p_kthread):Boolean;
begin
Result:=(td^.td_flags and TDF_UPIBLOCKED)<>0;
end;
function TD_IS_IDLETHREAD(td:p_kthread):Boolean;
begin
Result:=(td^.td_flags and TDF_IDLETD)<>0;
end;
procedure TD_SET_INHIB(td:p_kthread;inhib:Integer); inline;
begin
td^.td_state:=TDS_INHIBITED;
td^.td_inhibitors:=td^.td_inhibitors or inhib;
end;
procedure TD_CLR_INHIB(td:p_kthread;inhib:Integer); inline;
begin
if ((td^.td_inhibitors and inhib)<>0) then
begin
inhib:=td^.td_inhibitors and (not inhib);
td^.td_inhibitors:=inhib;
if (inhib=0) then
begin
td^.td_state:=TDS_CAN_RUN;
end;
end;
end;
procedure TD_SET_SLEEPING(td:p_kthread);
begin
TD_SET_INHIB(td,TDI_SLEEPING);
end;
procedure TD_SET_SWAPPED(td:p_kthread);
begin
TD_SET_INHIB(td,TDI_SWAPPED);
end;
procedure TD_SET_LOCK(td:p_kthread);
begin
TD_SET_INHIB(td,TDI_LOCK);
end;
procedure TD_SET_SUSPENDED(td:p_kthread);
begin
TD_SET_INHIB(td,TDI_SUSPENDED);
end;
procedure TD_SET_IWAIT(td:p_kthread);
begin
TD_SET_INHIB(td,TDI_IWAIT);
end;
procedure TD_CLR_SLEEPING(td:p_kthread);
begin
TD_CLR_INHIB(td,TDI_SLEEPING);
end;
procedure TD_CLR_SWAPPED(td:p_kthread);
begin
TD_CLR_INHIB(td,TDI_SWAPPED);
end;
procedure TD_CLR_LOCK(td:p_kthread);
begin
TD_CLR_INHIB(td,TDI_LOCK);
end;
procedure TD_CLR_SUSPENDED(td:p_kthread);
begin
TD_CLR_INHIB(td,TDI_SUSPENDED);
end;
procedure TD_CLR_IWAIT(td:p_kthread);
begin
TD_CLR_INHIB(td,TDI_IWAIT);
end;
procedure TD_SET_RUNNING(td:p_kthread);
begin
td^.td_state:=TDS_RUNNING;
end;
procedure TD_SET_RUNQ(td:p_kthread);
begin
td^.td_state:=TDS_RUNQ;
end;
procedure TD_SET_CAN_RUN(td:p_kthread);
begin
td^.td_state:=TDS_CAN_RUN;
end;
procedure THREAD_NO_SLEEPING();
var
td:p_kthread;
begin
td:=curkthread;
Assert((td^.td_pflags and TDP_NOSLEEPING)=0,'nested no sleeping');
td^.td_pflags:=td^.td_pflags or TDP_NOSLEEPING;
end;
procedure THREAD_SLEEPING_OK();
var
td:p_kthread;
begin
td:=curkthread;
Assert((td^.td_pflags and TDP_NOSLEEPING)<>0,'nested sleeping ok');
td^.td_pflags:=td^.td_pflags and (not TDP_NOSLEEPING);
end;
//
function curthread_pflags_set(flags:Integer):Integer;
var
td:p_kthread;
begin
td:=curkthread;
if (td=nil) then Exit(0);
Result:=(not flags) or (td^.td_pflags and flags);
td^.td_pflags:=td^.td_pflags or flags;
end;
procedure curthread_pflags_restore(save:Integer);
var
td:p_kthread;
begin
td:=curkthread;
if (td=nil) then Exit;
td^.td_pflags:=td^.td_pflags and save;
end;
//
procedure PROC_LOCK;
begin
mtx_lock(p_proc.p_mtx);
end;
procedure PROC_UNLOCK;
begin
mtx_unlock(p_proc.p_mtx);
end;
procedure PROC_INIT;
const
osreldate=$000DBBA0;
begin
FillChar(p_proc,SizeOf(p_proc),0);
mtx_init(p_proc.p_mtx,'process lock');
knlist_init_mtx(@p_proc.p_klist,@p_proc.p_mtx);
p_proc.p_osrel:=osreldate;
p_proc.p_randomized_path:='system';
p_proc.p_ptc:=rdtsc;
end;
//
function pargs_alloc(len:Integer):p_pargs;
begin
Result:=AllocMem(sizeof(t_pargs) + len);
Result^.ar_ref :=1;
Result^.ar_length:=len;
end;
procedure pargs_free(pa:p_pargs);
begin
FreeMem(pa);
end;
procedure pargs_hold(pa:p_pargs);
begin
if (pa=nil) then Exit;
System.InterlockedIncrement(pa^.ar_ref);
end;
procedure pargs_drop(pa:p_pargs);
begin
if (pa=nil) then Exit;
if (System.InterlockedDecrement(pa^.ar_ref)=0) then
begin
pargs_free(pa);
end;
end;
end.