unit kern_sig; {$mode ObjFPC}{$H+} {$CALLING SysV_ABI_CDecl} interface uses mqueue, kern_param, sys_event, time, signal, signalvar, kern_thr, kern_proc; const SA_KILL =$01; // terminates process by default SA_CORE =$02; // ditto and coredumps SA_STOP =$04; // suspend process SA_TTYSTOP =$08; // ditto, from tty SA_IGNORE =$10; // ignore by default SA_CONT =$20; // continue if suspended SA_CANTMASK=$40; // non-maskable, catchable SA_PROC =$80; // deliverable to any thread sigproptbl:array[0..30] of Integer=( SA_KILL or SA_PROC, // SIGHUP SA_KILL or SA_PROC, // SIGINT SA_KILL or SA_CORE or SA_PROC, // SIGQUIT SA_KILL or SA_CORE, // SIGILL SA_KILL or SA_CORE, // SIGTRAP SA_KILL or SA_CORE, // SIGABRT SA_KILL or SA_CORE or SA_PROC, // SIGEMT SA_KILL or SA_CORE, // SIGFPE SA_KILL or SA_PROC, // SIGKILL SA_KILL or SA_CORE, // SIGBUS SA_KILL or SA_CORE, // SIGSEGV SA_KILL or SA_CORE, // SIGSYS SA_KILL or SA_PROC, // SIGPIPE SA_KILL or SA_PROC, // SIGALRM SA_KILL or SA_PROC, // SIGTERM SA_IGNORE or SA_PROC, // SIGURG SA_STOP or SA_PROC, // SIGSTOP SA_STOP or SA_TTYSTOP or SA_PROC, // SIGTSTP SA_IGNORE or SA_CONT or SA_PROC, // SIGCONT SA_IGNORE or SA_PROC, // SIGCHLD SA_STOP or SA_TTYSTOP or SA_PROC, // SIGTTIN SA_STOP or SA_TTYSTOP or SA_PROC, // SIGTTOU SA_IGNORE or SA_PROC, // SIGIO SA_KILL, // SIGXCPU SA_KILL, // SIGXFSZ SA_KILL or SA_PROC, // SIGVTALRM SA_KILL or SA_PROC, // SIGPROF SA_IGNORE or SA_PROC, // SIGWINCH SA_IGNORE or SA_PROC, // SIGINFO SA_KILL or SA_PROC, // SIGUSR1 SA_KILL or SA_PROC // SIGUSR2 ); Function sys_sigaction(sig:Integer;act,oact:Pointer):Integer; Function sys_sigprocmask(how:Integer;_set,oset:Pointer):Integer; Function sys_sigpending(oset:Pointer):Integer; Function sys_sigwait(oset:Pointer;sig:PInteger):Integer; Function sys_sigtimedwait(oset,info,timeout:Pointer):Integer; Function sys_sigwaitinfo(oset,info:Pointer):Integer; Function sys_sigsuspend(sigmask:Pointer):Integer; Function sys_sigaltstack(ss,oss:Pointer):Integer; function sys_kill(pid,signum:Integer):Integer; function sys_sigqueue(pid,signum:Integer;value:Pointer):Integer; // Function sigonstack(sp:size_t):Integer; procedure sigqueue_init(list:p_sigqueue); procedure tdsigcleanup(td:p_kthread); procedure tdsignal(td:p_kthread;sig:Integer); procedure tdksignal(td:p_kthread;sig:Integer;ksi:p_ksiginfo); procedure forward_signal(td:p_kthread); procedure sigexit(td:p_kthread;sig:Integer); Function cursig(td:p_kthread;stop_allowed:Integer):Integer; Function kern_sigprocmask(td:p_kthread; how:Integer; _set:p_sigset_t; oset:p_sigset_t; flags:Integer ):Integer; procedure ast; procedure ps_mtx_lock; procedure ps_mtx_unlock; function sigdeferstop:Integer; procedure sigallowstop; procedure siginit; //SYSINIT // function filt_sigattach(kn:p_knote):Integer; procedure filt_sigdetach(kn:p_knote); function filt_signal(kn:p_knote;hint:QWORD):Integer; const sig_filtops:t_filterops=( f_isfd :0; f_attach:@filt_sigattach; f_detach:@filt_sigdetach; f_event :@filt_signal; ); implementation uses errno, systm, kern_mtx, md_time, kern_exit, kern_prot, kern_synch, md_context, machdep, sched_ule, sys_sleepqueue; const max_pending_per_proc=128; kern_forcesigexit=1; var signal_overflow :Integer=0; signal_alloc_fail:Integer=0; function ksiginfo_alloc():p_ksiginfo; begin Result:=AllocMem(SizeOf(ksiginfo_t)); end; procedure ksiginfo_free(ksi:p_ksiginfo); begin FreeMem(ksi); end; Function ksiginfo_tryfree(ksi:p_ksiginfo):Boolean; begin Result:=False; if ((ksi^.ksi_flags and KSI_EXT)=0) then begin FreeMem(ksi); Result:=True; end; end; procedure sigqueue_init(list:p_sigqueue); begin SIGEMPTYSET(@list^.sq_signals); SIGEMPTYSET(@list^.sq_kill); TAILQ_INIT(@list^.sq_list); list^.sq_flags:=SQ_INIT; end; Function sigqueue_get(sq:p_sigqueue;signo:Integer;si:p_ksiginfo):Integer; var ksi,next:p_ksiginfo; count:Integer; begin count:=0; Assert((sq^.sq_flags and SQ_INIT)<>0,'sigqueue not inited'); if not SIGISMEMBER(@sq^.sq_signals,signo) then Exit(0); if SIGISMEMBER(@sq^.sq_kill,signo) then begin Inc(count); SIGDELSET(@sq^.sq_kill,signo); end; ksi:=TAILQ_FIRST(@sq^.sq_list); While (ksi<>nil) do begin next:=TAILQ_NEXT(ksi,@ksi^.ksi_link); if (ksi^.ksi_info.si_signo=signo) then begin if (count=0) then begin TAILQ_REMOVE(@sq^.sq_list,ksi,@ksi^.ksi_link); ksi^.ksi_sigq:=nil; ksiginfo_copy(ksi,si); if ksiginfo_tryfree(ksi) then begin Dec(p_proc.p_pendingcnt); end; end; if (count>1) then begin Inc(count); Break; end else begin Inc(count); end; end; ksi:=next; end; if (count<=1) then begin SIGDELSET(@sq^.sq_signals,signo); end; si^.ksi_info.si_signo:=signo; Result:=signo; end; procedure sigqueue_take(ksi:p_ksiginfo); var kp:p_ksiginfo; sq:p_sigqueue; begin if (ksi=nil) or (ksi^.ksi_sigq=nil) then Exit; sq:=ksi^.ksi_sigq; TAILQ_REMOVE(@sq^.sq_list,ksi,@ksi^.ksi_link); ksi^.ksi_sigq:=nil; if ((ksi^.ksi_flags and KSI_EXT)=0)then begin Dec(p_proc.p_pendingcnt); end; kp:=TAILQ_FIRST(@sq^.sq_list); While (kp<>nil) do begin if (kp^.ksi_info.si_signo=ksi^.ksi_info.si_signo) then Break; kp:=TAILQ_NEXT(kp,@kp^.ksi_link); end; if (kp=nil) and (not SIGISMEMBER(@sq^.sq_kill,ksi^.ksi_info.si_signo)) then begin SIGDELSET(@sq^.sq_signals,ksi^.ksi_info.si_signo); end; end; Function sigqueue_add(sq:p_sigqueue;signo:Integer;si:p_ksiginfo):Integer; label out_set_bit; var ksi:p_ksiginfo; begin Result:=0; Assert((sq^.sq_flags and SQ_INIT)<>0,'sigqueue not inited'); if (signo=SIGKILL) or (signo=SIGSTOP) or (si=nil) then begin SIGADDSET(@sq^.sq_kill,signo); goto out_set_bit; end; if ((si^.ksi_flags and KSI_INS)<>0) then begin if ((si^.ksi_flags and KSI_HEAD)<>0) then TAILQ_INSERT_HEAD(@sq^.sq_list,si,@si^.ksi_link) else TAILQ_INSERT_TAIL(@sq^.sq_list,si,@si^.ksi_link); si^.ksi_sigq:=sq; goto out_set_bit; end; if (p_proc.p_pendingcnt>=max_pending_per_proc) then begin Inc(signal_overflow); Result:=EAGAIN; end else begin ksi:=ksiginfo_alloc; if (ksi=nil) then begin Inc(signal_alloc_fail); Result:=EAGAIN; end else begin Inc(p_proc.p_pendingcnt); ksiginfo_copy(si,ksi); ksi^.ksi_info.si_signo:=signo; if ((si^.ksi_flags and KSI_HEAD)<>0) then TAILQ_INSERT_HEAD(@sq^.sq_list,ksi,@ksi^.ksi_link) else TAILQ_INSERT_TAIL(@sq^.sq_list,ksi,@ksi^.ksi_link); ksi^.ksi_sigq:=sq; end; end; if ((si^.ksi_flags and KSI_TRAP)<>0) or ((si^.ksi_flags and KSI_SIGQ) =0) then begin if (Result<>0) then begin SIGADDSET(@sq^.sq_kill,signo); end; Result:=0; goto out_set_bit; end; if (Result<>0) then Exit; out_set_bit: SIGADDSET(@sq^.sq_signals,signo); end; procedure sigqueue_flush(sq:p_sigqueue); var ksi,next:p_ksiginfo; begin Assert((sq^.sq_flags and SQ_INIT)<>0,'sigqueue not inited'); ksi:=TAILQ_FIRST(@sq^.sq_list); while (ksi<>nil) do begin next:=TAILQ_NEXT(ksi,@ksi^.ksi_link); TAILQ_REMOVE(@sq^.sq_list,ksi,@ksi^.ksi_link); ksi^.ksi_sigq:=nil; if ksiginfo_tryfree(ksi) then begin Dec(p_proc.p_pendingcnt); end; ksi:=next; end; SIGEMPTYSET(@sq^.sq_signals); SIGEMPTYSET(@sq^.sq_kill); end; procedure sigqueue_move_set(src,dst:p_sigqueue;_set:p_sigset_t); var tmp:sigset_t; ksi,next:p_ksiginfo; begin Assert((src^.sq_flags and SQ_INIT)<>0,'sigqueue not inited'); Assert((dst^.sq_flags and SQ_INIT)<>0,'sigqueue not inited'); ksi:=TAILQ_FIRST(@src^.sq_list); while (ksi<>nil) do begin next:=TAILQ_NEXT(ksi,@ksi^.ksi_link); if SIGISMEMBER(_set,ksi^.ksi_info.si_signo) then begin TAILQ_REMOVE(@src^.sq_list,ksi,@ksi^.ksi_link); TAILQ_INSERT_TAIL(@dst^.sq_list,ksi,@ksi^.ksi_link); ksi^.ksi_sigq:=dst; end; ksi:=next; end; tmp:=src^.sq_kill; SIGSETAND(@tmp,_set); SIGSETOR(@dst^.sq_kill,@tmp); SIGSETNAND(@src^.sq_kill,@tmp); tmp:=src^.sq_signals; SIGSETAND(@tmp,_set); SIGSETOR(@dst^.sq_signals,@tmp); SIGSETNAND(@src^.sq_signals,@tmp); end; procedure sigqueue_delete_set(sq:p_sigqueue;_set:p_sigset_t); var ksi,next:p_ksiginfo; begin Assert((sq^.sq_flags and SQ_INIT)<>0,'sigqueue not inited'); ksi:=TAILQ_FIRST(@sq^.sq_list); while (ksi<>nil) do begin next:=TAILQ_NEXT(ksi,@ksi^.ksi_link); if SIGISMEMBER(_set,ksi^.ksi_info.si_signo) then begin TAILQ_REMOVE(@sq^.sq_list,ksi,@ksi^.ksi_link); ksi^.ksi_sigq:=nil; if ksiginfo_tryfree(ksi) then begin Dec(p_proc.p_pendingcnt) end; end; ksi:=next; end; SIGSETNAND(@sq^.sq_kill,_set); SIGSETNAND(@sq^.sq_signals,_set); end; procedure sigqueue_delete(sq:p_sigqueue;signo:Integer); var _set:sigset_t; begin SIGEMPTYSET(@_set); SIGADDSET(@_set,signo); sigqueue_delete_set(sq,@_set); end; procedure sigqueue_delete_set_proc(_set:p_sigset_t); var td0:p_kthread; worklist:sigqueue_t; begin sigqueue_init(@worklist); sigqueue_move_set(@p_proc.p_sigqueue,@worklist,_set); threads_lock; td0:=TAILQ_FIRST(get_p_threads); while (td0<>nil) do begin sigqueue_move_set(@td0^.td_sigqueue,@worklist,_set); td0:=TAILQ_NEXT(td0,@td0^.td_plist) end; threads_unlock; sigqueue_flush(@worklist); end; procedure sigqueue_delete_proc(signo:Integer); var _set:sigset_t; begin SIGEMPTYSET(@_set); SIGADDSET(@_set,signo); sigqueue_delete_set_proc(@_set); end; procedure sigqueue_delete_stopmask_proc; var _set:sigset_t; begin SIGEMPTYSET(@_set); SIGADDSET(@_set,SIGSTOP); SIGADDSET(@_set,SIGTSTP); SIGADDSET(@_set,SIGTTIN); SIGADDSET(@_set,SIGTTOU); sigqueue_delete_set_proc(@_set); end; /// Function issignal(td:p_kthread;stop_allowed:Integer):Integer; forward; Function cursig(td:p_kthread;stop_allowed:Integer):Integer; public; begin Assert((stop_allowed=SIG_STOP_ALLOWED) or (stop_allowed=SIG_STOP_NOT_ALLOWED),'cursig: stop_allowed'); if SIGPENDING(td) then begin Result:=issignal(td, stop_allowed); end else begin Result:=0; end; end; procedure signotify(td:p_kthread); begin if SIGPENDING(td) then begin thread_lock(td); td^.td_flags:=td^.td_flags or TDF_NEEDSIGCHK or TDF_ASTPENDING; thread_unlock(td); end; end; Function sigonstack(sp:size_t):Integer; public; var td:p_kthread; begin Result:=0; td:=curkthread; if (td=nil) then Exit; if ((td^.td_pflags and TDP_ALTSTACK)<>0) then begin Result:=ord((sp-size_t(td^.td_sigstk.ss_sp))0) and (signil) then begin oact^.sa_mask :=p_sigacts.ps_catchmask[_SIG_IDX(sig)]; oact^.sa_flags:=0; if (SIGISMEMBER(@p_sigacts.ps_sigonstack,sig)) then oact^.sa_flags:=oact^.sa_flags or SA_ONSTACK; if (not SIGISMEMBER(@p_sigacts.ps_sigintr,sig)) then oact^.sa_flags:=oact^.sa_flags or SA_RESTART; if (SIGISMEMBER(@p_sigacts.ps_sigreset,sig)) then oact^.sa_flags:=oact^.sa_flags or SA_RESETHAND; if (SIGISMEMBER(@p_sigacts.ps_signodefer,sig)) then oact^.sa_flags:=oact^.sa_flags or SA_NODEFER; if (SIGISMEMBER(@p_sigacts.ps_siginfo,sig)) then begin oact^.sa_flags:=oact^.sa_flags or SA_SIGINFO; oact^.u.sa_handler:=p_sigacts.ps_sigact[_SIG_IDX(sig)]; end else begin oact^.u.sa_handler:=p_sigacts.ps_sigact[_SIG_IDX(sig)]; end; if (sig=SIGCHLD and p_sigacts.ps_flag and PS_NOCLDSTOP) then oact^.sa_flags:=oact^.sa_flags or SA_NOCLDSTOP; if (sig=SIGCHLD and p_sigacts.ps_flag and PS_NOCLDWAIT) then oact^.sa_flags:=oact^.sa_flags or SA_NOCLDWAIT; end; if (act<>nil) then begin if ((sig=SIGKILL) or (sig=SIGSTOP)) and (act^.u.code<>SIG_DFL) then begin ps_mtx_unlock; PROC_UNLOCK; Result:=EINVAL; end; p_sigacts.ps_catchmask[_SIG_IDX(sig)]:=act^.sa_mask; SIG_CANTMASK(@p_sigacts.ps_catchmask[_SIG_IDX(sig)]); if ((act^.sa_flags and SA_SIGINFO)<>0) then begin p_sigacts.ps_sigact[_SIG_IDX(sig)]:=act^.u.sa_handler; SIGADDSET(@p_sigacts.ps_siginfo,sig); end else begin p_sigacts.ps_sigact[_SIG_IDX(sig)]:=act^.u.sa_handler; SIGDELSET(@p_sigacts.ps_siginfo,sig); end; if ((act^.sa_flags and SA_RESTART)=0) then SIGADDSET(@p_sigacts.ps_sigintr,sig) else SIGDELSET(@p_sigacts.ps_sigintr,sig); if ((act^.sa_flags and SA_ONSTACK)<>0) then SIGADDSET(@p_sigacts.ps_sigonstack,sig) else SIGDELSET(@p_sigacts.ps_sigonstack,sig); if ((act^.sa_flags and SA_RESETHAND)<>0) then SIGADDSET(@p_sigacts.ps_sigreset,sig) else SIGDELSET(@p_sigacts.ps_sigreset,sig); if ((act^.sa_flags and SA_NODEFER)<>0) then SIGADDSET(@p_sigacts.ps_signodefer,sig) else SIGDELSET(@p_sigacts.ps_signodefer,sig); if (sig=SIGCHLD) then begin if ((act^.sa_flags and SA_NOCLDSTOP)<>0) then p_sigacts.ps_flag:=p_sigacts.ps_flag or PS_NOCLDSTOP else p_sigacts.ps_flag:=p_sigacts.ps_flag and (not PS_NOCLDSTOP); if ((act^.sa_flags and SA_NOCLDWAIT)<>0) then begin p_sigacts.ps_flag:=p_sigacts.ps_flag or PS_NOCLDWAIT; end else p_sigacts.ps_flag:=p_sigacts.ps_flag and (not PS_NOCLDWAIT); if (p_sigacts.ps_sigact[_SIG_IDX(SIGCHLD)]=sig_t(SIG_IGN)) then p_sigacts.ps_flag:=p_sigacts.ps_flag or PS_CLDSIGIGN else p_sigacts.ps_flag:=p_sigacts.ps_flag and (not PS_CLDSIGIGN); end; if (p_sigacts.ps_sigact[_SIG_IDX(sig)]=sig_t(SIG_IGN)) or (((sigprop(sig) and SA_IGNORE)<>0) and (p_sigacts.ps_sigact[_SIG_IDX(sig)]=sig_t(SIG_DFL))) then begin sigqueue_delete_proc(sig); if (sig<>SIGCONT) then begin SIGADDSET(@p_sigacts.ps_sigignore,sig); end; SIGDELSET(@p_sigacts.ps_sigcatch,sig); end else begin SIGDELSET(@p_sigacts.ps_sigignore,sig); if (p_sigacts.ps_sigact[_SIG_IDX(sig)]=sig_t(SIG_DFL)) then SIGDELSET(@p_sigacts.ps_sigcatch,sig) else SIGADDSET(@p_sigacts.ps_sigcatch,sig); end; end; ps_mtx_unlock; PROC_UNLOCK; Result:=0; end; Function sys_sigaction(sig:Integer;act,oact:Pointer):Integer; var _act,_oact:sigaction_t; actp,oactp:p_sigaction_t; begin actp :=nil; oactp:=nil; if (oact<>nil) then oactp:=@_oact; if (act<>nil) then begin actp:=@_act; Result:=copyin(act,actp,sizeof(sigaction_t)); if (Result<>0) then Exit; end; Result:=kern_sigaction(sig,actp,oactp); if (oact<>nil) and (Result=0) then begin Result:=copyout(oactp,oact,sizeof(sigaction_t)); end; end; procedure siginit; var i:Integer; begin mtx_init(p_sigacts.ps_mtx,'sigacts'); For i:=1 to NSIG do begin if ((sigprop(i) and SA_IGNORE)<>0) and (i<>SIGCONT) then begin SIGADDSET(@p_sigacts.ps_sigignore,i); end; end; sigqueue_init(@p_proc.p_sigqueue); end; procedure reschedule_signals(block:sigset_t;flags:Integer); forward; Function kern_sigprocmask(td:p_kthread; how:Integer; _set:p_sigset_t; oset:p_sigset_t; flags:Integer ):Integer; public; label _out; var new_block,oset1:sigset_t; begin Result:=0; if ((flags and SIGPROCMASK_PROC_LOCKED)=0) then begin PROC_LOCK; end; if (oset<>nil) then begin oset^:=td^.td_sigmask; end; if (_set<>nil) then begin Case how of SIG_BLOCK: begin SIG_CANTMASK(_set); oset1:=td^.td_sigmask; SIGSETOR(@td^.td_sigmask, _set); new_block:=td^.td_sigmask; SIGSETNAND(@new_block, @oset1); end; SIG_UNBLOCK: begin SIGSETNAND(@td^.td_sigmask, _set); signotify(td); goto _out; end; SIG_SETMASK: begin SIG_CANTMASK(_set); oset1:=td^.td_sigmask; if ((flags and SIGPROCMASK_OLD)<>0) then SIGSETLO(@td^.td_sigmask, _set) else td^.td_sigmask:=_set^; new_block:=td^.td_sigmask; SIGSETNAND(@new_block, @oset1); signotify(td); end; else begin Result:=EINVAL; goto _out; end; end; reschedule_signals(new_block, flags); end; _out: if ((flags and SIGPROCMASK_PROC_LOCKED)=0) then begin PROC_UNLOCK; end; end; Function sys_sigprocmask(how:Integer;_set,oset:Pointer):Integer; var td:p_kthread; __set,_oset:sigset_t; setp,osetp:p_sigset_t; begin td:=curkthread; if (td=nil) then Exit(-1); setp :=nil; osetp:=nil; if (oset<>nil) then osetp:=@_oset; if (_set<>nil) then begin setp:=@__set; Result:=copyin(_set,setp,sizeof(sigset_t)); if (Result<>0) then Exit; end; Result:=kern_sigprocmask(td,how,setp,osetp,0); if (oset<>nil) and (Result=0) then begin Result:=copyout(osetp,oset,sizeof(sigset_t)); end; end; Function sys_sigpending(oset:Pointer):Integer; var td:p_kthread; pending:sigset_t; begin td:=curkthread; if (td=nil) then Exit(-1); PROC_LOCK; pending:=p_proc.p_sigqueue.sq_signals; SIGSETOR(@pending,@td^.td_sigqueue.sq_signals); PROC_UNLOCK; Result:=copyout(@pending,oset,sizeof(sigset_t)); end; Function kern_sigtimedwait(td:p_kthread; waitset:sigset_t; ksi:p_ksiginfo; timeout:p_timespec ):Integer; var saved_mask,new_block:sigset_t; rts,ets,tv:Int64; sig,timevalid:Integer; begin Result:=0; timevalid:=0; ets:=0; if (timeout<>nil) then begin if (timeout^.tv_nsec >= 0) and (timeout^.tv_nsec < 1000000000) then begin timevalid:=1; rts:=get_unit_uptime; ets:=rts; ets:=ets+TIMESPEC_TO_UNIT(timeout); end; end; ksiginfo_init(ksi); SIG_CANTMASK(@waitset); PROC_LOCK; saved_mask:=td^.td_sigmask; SIGSETNAND(@td^.td_sigmask,@waitset); repeat ps_mtx_lock; sig:=cursig(td,SIG_STOP_ALLOWED); ps_mtx_unlock; if (sig<>0) and SIGISMEMBER(@waitset,sig) then begin if (sigqueue_get(@td^.td_sigqueue,sig,ksi)<>0) or (sigqueue_get(@p_proc.p_sigqueue,sig,ksi)<>0) then begin Result:=0; break; end; end; if (Result<>0) then Break; if (timeout<>nil) then begin if (timevalid=0) then begin Result:=EINVAL; break; end; rts:=get_unit_uptime; if (rts>=ets) then begin Result:=EAGAIN; break; end; tv:=ets-rts; tv:=tvtohz(tv); end else begin tv:=0; end; Result:=msleep(@p_sigacts,@p_proc.p_mtx,PPAUSE or PCATCH,'sigwait',tv); if (timeout<>nil) then begin if (Result=ERESTART) then begin Result:=EINTR; end else if (Result=EAGAIN) then begin Result:=0; end; end; until false; new_block:=saved_mask; SIGSETNAND(@new_block,@td^.td_sigmask); td^.td_sigmask:=saved_mask; reschedule_signals(new_block,0); //if (ksi^.ksi_code == SI_TIMER) // itimer_accept(p, ksi^.ksi_timerid, ksi); if (sig=SIGKILL) then begin sigexit(td,sig); end; PROC_UNLOCK; end; Function sys_sigwait(oset:Pointer;sig:PInteger):Integer; var td:p_kthread; ksi:ksiginfo_t; __set:sigset_t; begin td:=curkthread; if (td=nil) then begin td^.td_retval[0]:=EFAULT; Exit(0); end; Result:=copyin(oset,@__set,sizeof(sigset_t)); if (Result<>0) then begin td^.td_retval[0]:=EFAULT; Exit(0); end; Result:=kern_sigtimedwait(td,__set,@ksi,nil); if (Result<>0) then begin if (Result=EINTR) then begin Result:=ERESTART; end; if (Result=ERESTART) then begin Exit; end; td^.td_retval[0]:=Result; Exit(0); end; Result:=copyout(@ksi.ksi_info.si_signo,sig,sizeof(Integer)); td^.td_retval[0]:=Result; Result:=0; end; Function sys_sigtimedwait(oset,info,timeout:Pointer):Integer; var td:p_kthread; ts:timespec; ksi:ksiginfo_t; __set:sigset_t; begin td:=curkthread; if (td=nil) then Exit(-1); if (timeout<>nil) then begin Result:=copyin(timeout,@ts,sizeof(timespec)); if (Result<>0) then Exit; timeout:=@ts; end; Result:=copyin(oset,@__set,sizeof(sigset_t)); if (Result<>0) then Exit; Result:=kern_sigtimedwait(td,__set,@ksi,timeout); if (Result<>0) then Exit; if (info<>nil) then begin Result:=copyout(@ksi.ksi_info,info,sizeof(siginfo_t)); if (Result<>0) then Exit; end; td^.td_retval[0]:=ksi.ksi_info.si_signo; end; Function sys_sigwaitinfo(oset,info:Pointer):Integer; var td:p_kthread; ksi:ksiginfo_t; __set:sigset_t; begin td:=curkthread; if (td=nil) then Exit(-1); Result:=copyin(oset,@__set,sizeof(sigset_t)); if (Result<>0) then Exit; Result:=kern_sigtimedwait(td,__set,@ksi,nil); if (Result<>0) then Exit; if (info<>nil) then begin Result:=copyout(@ksi.ksi_info,info,sizeof(siginfo_t)); if (Result<>0) then Exit; end; td^.td_retval[0]:=ksi.ksi_info.si_signo; end; function postsig(sig:Integer):Integer; forward; Function kern_sigsuspend(td:p_kthread;mask:sigset_t):Integer; var has_sig,sig:Integer; begin PROC_LOCK; kern_sigprocmask(td,SIG_SETMASK,@mask,@td^.td_oldsigmask,SIGPROCMASK_PROC_LOCKED); td^.td_pflags:=td^.td_pflags or TDP_OLDMASK; cpu_set_syscall_retval(td,EINTR); has_sig:=0; While (has_sig=0) do begin //PROC_UNLOCK; // //while (msleep_td(0)=0) do; //PROC_LOCK; // while (msleep(@p_sigacts,@p_proc.p_mtx,PPAUSE or PCATCH,'pause',0)=0) do; //thread_suspend_check(0); ps_mtx_lock; repeat sig:=cursig(td,SIG_STOP_ALLOWED); if (sig=0) then Break; has_sig:=has_sig+postsig(sig); until false; ps_mtx_unlock; end; PROC_UNLOCK; td^.td_errno:=EINTR; td^.td_pflags:=td^.td_pflags or TDP_NERRNO; Result:=EJUSTRETURN; end; Function sys_sigsuspend(sigmask:Pointer):Integer; var td:p_kthread; mask:sigset_t; begin td:=curkthread; if (td=nil) then Exit(-1); Result:=copyin(sigmask,@mask,sizeof(sigset_t)); if (Result<>0) then Exit; Result:=kern_sigsuspend(td,mask); end; Function kern_sigaltstack(td:p_kthread;ss:p_stack_t;oss:p_stack_t):Integer; var oonstack:Integer; begin oonstack:=sigonstack(cpu_getstack(td)); if (oss<>nil) then begin oss^:=td^.td_sigstk; if ((td^.td_pflags and TDP_ALTSTACK)<>0) then begin if (oonstack<>0) then begin oss^.ss_flags:=SS_ONSTACK; end else begin oss^.ss_flags:=0; end; end else begin oss^.ss_flags:=SS_DISABLE; end; end; if (ss<>nil) then begin if (oonstack<>0) then Exit(EPERM); if ((ss^.ss_flags and (not SS_DISABLE))<>0) then Exit(EINVAL); if ((ss^.ss_flags and SS_DISABLE)=0) then begin if (ss^.ss_sizenil) then begin Result:=copyin(ss,@_ss,sizeof(stack_t)); if (Result<>0) then Exit; ss:=@_ss; end; p_oss:=nil; if (oss<>nil) then begin p_oss:=@_oss; end; Result:=kern_sigaltstack(td,ss,p_oss); if (Result<>0) then Exit; if (oss<>nil) then begin Result:=copyout(p_oss,oss,sizeof(stack_t)); end; end; function pksignal(sig:Integer;ksi:p_ksiginfo):Integer; forward; { * Common code for kill process group/broadcast kill. * cp is calling process. } function killpg1(sig,pgid,all:Integer;ksi:p_ksiginfo):Integer; var err:Integer; begin Result:=ESRCH; if (all<>0) then begin //broadcast PROC_LOCK; err:=p_cansignal(sig); if (err=0) then begin if (sig<>0) then pksignal(sig, ksi); Result:=err; end else if (Result=ESRCH) then begin Result:=err; end; PROC_UNLOCK; end else begin if (pgid=0) then begin //zero pgid means send to my process group. end else begin Exit(ESRCH); end; PROC_LOCK; err:=p_cansignal(sig); if (err=0) then begin if (sig<>0) then pksignal(sig, ksi); Result:=err; end else if (Result=ESRCH) then begin Result:=err; end; PROC_UNLOCK; end; end; function sys_kill(pid,signum:Integer):Integer; var ksi:ksiginfo_t; error:Integer; begin if (signum > _SIG_MAXSIG) then begin Exit(EINVAL); end; ksiginfo_init(@ksi); ksi.ksi_info.si_signo:=signum; ksi.ksi_info.si_code:=SI_USER; ksi.ksi_info.si_pid :=pid; if (pid > 0) then begin { kill single process } if (pid<>p_proc.p_pid) then Exit(ESRCH); PROC_LOCK; error:=p_cansignal(signum); if (error=0) and (signum<>0) then begin pksignal(signum, @ksi); end; PROC_UNLOCK; Exit(error); end; case pid of -1: { broadcast signal } Exit(killpg1(signum, 0, 1, @ksi)); 0: { signal own process group } Exit(killpg1(signum, 0, 0, @ksi)); else { negative explicit process group } Exit(killpg1(signum, -pid, 0, @ksi)); end; { NOTREACHED } end; function sys_sigqueue(pid,signum:Integer;value:Pointer):Integer; var ksi:ksiginfo_t; error:Integer; begin if (signum > _SIG_MAXSIG) then begin Exit(EINVAL); end; { * Specification says sigqueue can only send signal to * single process. } if (pid <= 0) then begin Exit(EINVAL); end; if (pid<>0) and (pid<>p_proc.p_pid) then begin Exit(ESRCH); end; error:=p_cansignal(signum); if (error=0) and (signum<>0) then begin ksiginfo_init(@ksi); ksi.ksi_flags:=KSI_SIGQ; ksi.ksi_info.si_signo:=signum; ksi.ksi_info.si_code :=SI_QUEUE; ksi.ksi_info.si_pid :=p_proc.p_pid; ksi.ksi_info.si_value.sival_ptr:=value; PROC_LOCK(); error:=pksignal(signum, @ksi); PROC_UNLOCK(); end; Exit(error); end; procedure postsig_done(sig:Integer;td:p_kthread); var mask:sigset_t; begin InterlockedIncrement64(p_proc.p_nsignals); InterlockedIncrement64(td^.td_ru.ru_nsignals); mask:=p_sigacts.ps_catchmask[_SIG_IDX(sig)]; if (not SIGISMEMBER(@p_sigacts.ps_signodefer,sig)) then begin SIGADDSET(@mask,sig); end; kern_sigprocmask(td,SIG_BLOCK,@mask,nil,SIGPROCMASK_PROC_LOCKED or SIGPROCMASK_PS_LOCKED); if (SIGISMEMBER(@p_sigacts.ps_sigreset,sig)) then begin SIGDELSET(@p_sigacts.ps_sigcatch,sig); if (sig<>SIGCONT) and ((sigprop(sig) and SA_IGNORE)<>0) then begin SIGADDSET(@p_sigacts.ps_sigignore,sig); end; p_sigacts.ps_sigact[_SIG_IDX(sig)]:=sig_t(SIG_DFL); end; end; function tdsendsignal(td:p_kthread;sig:Integer;ksi:p_ksiginfo):Integer; forward; procedure trapsignal(td:p_kthread;ksi:p_ksiginfo); var sig:Integer; begin sig :=ksi^.ksi_info.si_signo; Assert(_SIG_VALID(sig),'invalid signal'); PROC_LOCK; ps_mtx_lock; if SIGISMEMBER(@p_sigacts.ps_sigcatch,sig) and (not SIGISMEMBER(@td^.td_sigmask,sig)) then begin sendsig(p_sigacts.ps_sigact[_SIG_IDX(sig)],ksi,@td^.td_sigmask); postsig_done(sig,td); ps_mtx_unlock; end else begin //ignoring? if (kern_forcesigexit<>0) and (SIGISMEMBER(@td^.td_sigmask,sig) or (p_sigacts.ps_sigact[_SIG_IDX(sig)]=sig_t(SIG_IGN))) then begin SIGDELSET(@td^.td_sigmask,sig); SIGDELSET(@p_sigacts.ps_sigcatch,sig); SIGDELSET(@p_sigacts.ps_sigignore,sig); p_sigacts.ps_sigact[_SIG_IDX(sig)]:=sig_t(SIG_DFL); end; ps_mtx_unlock; tdsendsignal(td,sig,ksi); end; PROC_UNLOCK; end; function sigtd(sig,prop:Integer):p_kthread; var td:p_kthread; first_td :p_kthread; signal_td:p_kthread; begin td:=curkthread; if (td<>nil) then if not SIGISMEMBER(@td^.td_sigmask,sig) then begin Exit(td); end; first_td :=nil; signal_td:=nil; threads_lock; td:=TAILQ_FIRST(get_p_threads); while (td<>nil) do begin if (first_td=nil) then begin first_td:=td; end; if (not SIGISMEMBER(@td^.td_sigmask,sig)) then begin signal_td:=td; Break; end; td:=TAILQ_NEXT(td,@td^.td_plist) end; threads_unlock; if (signal_td=nil) then begin Result:=first_td; end else begin Result:=signal_td; end; end; procedure kern_psignal(sig:Integer); var ksi:ksiginfo_t; begin ksiginfo_init(@ksi); ksi.ksi_info.si_signo:=sig; ksi.ksi_info.si_code :=SI_KERNEL; ksi.ksi_info.si_pid :=p_proc.p_pid; tdsendsignal(nil,sig,@ksi); end; function pksignal(sig:Integer;ksi:p_ksiginfo):Integer; begin Result:=tdsendsignal(nil,sig,ksi); end; procedure tdsigwakeup(td:p_kthread;sig:Integer;action:sig_t;intrval:Integer); forward; function tdsendsignal(td:p_kthread;sig:Integer;ksi:p_ksiginfo):Integer; var sigqueue:p_sigqueue; action:sig_t; intrval:Integer; prop:Integer; begin Result:=0; Writeln('tdsendsignal(',td^.td_tid,':',td^.td_name,',',sig,')'); KNOTE_LOCKED(@p_proc.p_klist, NOTE_SIGNAL or sig); prop:=sigprop(sig); if (td=nil) then begin td:=sigtd(sig,prop); sigqueue:=@p_proc.p_sigqueue; end else begin sigqueue:=@td^.td_sigqueue; end; ps_mtx_lock; if (SIGISMEMBER(@p_sigacts.ps_sigignore,sig)) then begin ps_mtx_unlock; if (ksi<>nil) then if (ksi^.ksi_flags and KSI_INS)<>0 then begin ksiginfo_tryfree(ksi); end; Exit; end; if (SIGISMEMBER(@td^.td_sigmask,sig)) then action:=sig_t(SIG_HOLD) else if (SIGISMEMBER(@p_sigacts.ps_sigcatch,sig)) then action:=sig_t(SIG_CATCH) else action:=sig_t(SIG_DFL); if (SIGISMEMBER(@p_sigacts.ps_sigintr,sig)) then begin intrval:=EINTR; end else begin intrval:=ERESTART; end; ps_mtx_unlock; if ((prop and SA_CONT)<>0) then begin sigqueue_delete_stopmask_proc end else if ((prop and SA_STOP)<>0) then begin sigqueue_delete_proc(SIGCONT); end; Result:=sigqueue_add(sigqueue,sig,ksi); if (Result<>0) then Exit; signotify(td); if (action=sig_t(SIG_HOLD)) and ((prop and SA_CONT)=0) then Exit; tdsigwakeup(td,sig,action,intrval); end; procedure tdsignal(td:p_kthread;sig:Integer); public; var ksi:ksiginfo_t; begin ksiginfo_init(@ksi); ksi.ksi_info.si_signo:=sig; ksi.ksi_info.si_code :=SI_KERNEL; ksi.ksi_info.si_pid :=p_proc.p_pid; tdsendsignal(td,sig,@ksi); end; procedure tdksignal(td:p_kthread;sig:Integer;ksi:p_ksiginfo); begin tdsendsignal(td,sig,ksi); end; procedure forward_signal(td:p_kthread); begin if (td=curkthread) then Exit; ipi_send_cpu(td); end; procedure tdsigwakeup(td:p_kthread;sig:Integer;action:sig_t;intrval:Integer); label _out; var prop:Integer; begin prop:=sigprop(sig); PROC_LOCK; thread_lock(td); if (action=sig_t(SIG_DFL)) and ((prop and SA_KILL)<>0) and (td^.td_priority>PUSER) then begin sched_prio(td,PUSER); end; if TD_ON_SLEEPQ(td) then begin if ((td^.td_flags and TDF_SINTR)=0) then begin goto _out; end; if ((prop and SA_CONT)<>0) and (action=sig_t(SIG_DFL)) then begin thread_unlock(td); PROC_UNLOCK; sigqueue_delete(@p_proc.p_sigqueue,sig); sigqueue_delete(@td^.td_sigqueue,sig); Exit; end; if ((prop and SA_STOP)<>0) and ((td^.td_flags and TDF_SBDRY)<>0) then begin goto _out; end; if (td^.td_priority>PUSER) then begin sched_prio(td,PUSER); end; sleepq_abort(td,intrval); end else begin if TD_IS_RUNNING(td) and (td<>curkthread) then begin forward_signal(td); end; end; _out: PROC_UNLOCK; thread_unlock(td); end; procedure reschedule_signals(block:sigset_t;flags:Integer); var td:p_kthread; sig:Integer; begin if (SIGISEMPTY(@p_proc.p_sigqueue.sq_signals)) then Exit; SIGSETAND(@block,@p_proc.p_sigqueue.sq_signals); repeat sig:=sig_ffs(@block); if (sig=0) then Exit; SIGDELSET(@block,sig); td:=sigtd(sig,0); signotify(td); if ((flags and SIGPROCMASK_PS_LOCKED)=0) then begin ps_mtx_lock; end; if SIGISMEMBER(@p_sigacts.ps_sigcatch,sig) then begin if SIGISMEMBER(@p_sigacts.ps_sigintr,sig) then begin tdsigwakeup(td,sig,sig_t(SIG_CATCH),EINTR); end else begin tdsigwakeup(td,sig,sig_t(SIG_CATCH),ERESTART); end; end; if ((flags and SIGPROCMASK_PS_LOCKED)=0) then begin ps_mtx_unlock; end; until false; end; procedure tdsigcleanup(td:p_kthread); var unblocked:sigset_t; begin sigqueue_flush(@td^.td_sigqueue); SIGFILLSET(@unblocked); SIGSETNAND(@unblocked,@td^.td_sigmask); SIGFILLSET(@td^.td_sigmask); reschedule_signals(unblocked,0); end; function sigdeferstop:Integer; public; var td:p_kthread; begin td:=curkthread; if (td^.td_flags and TDF_SBDRY)<>0 then Exit(0); thread_lock(td); td^.td_flags:=td^.td_flags or TDF_SBDRY; thread_unlock(td); Result:=1; end; procedure sigallowstop; public; var td:p_kthread; begin td:=curkthread; thread_lock(td); td^.td_flags:=td^.td_flags and (not TDF_SBDRY); thread_unlock(td); end; Function issignal(td:p_kthread;stop_allowed:Integer):Integer; var sigpending:sigset_t; sig,prop:Integer; begin repeat sigpending:=td^.td_sigqueue.sq_signals; SIGSETOR(@sigpending,@p_proc.p_sigqueue.sq_signals); SIGSETNAND(@sigpending,@td^.td_sigmask); if (td^.td_flags and TDF_SBDRY)<>0 then begin SIG_STOPSIGMASK(@sigpending); end; if (SIGISEMPTY(@sigpending)) then begin Exit(0); end; sig:=sig_ffs(@sigpending); if SIGISMEMBER(@p_sigacts.ps_sigignore,sig) then begin sigqueue_delete(@td^.td_sigqueue,sig); sigqueue_delete(@p_proc.p_sigqueue,sig); continue; end; prop:=sigprop(sig); Case ptrint(p_sigacts.ps_sigact[_SIG_IDX(sig)]) of SIG_DFL: begin if ((prop and SA_STOP)<>0) then begin ps_mtx_unlock; PROC_LOCK; //sig_suspend_threads(td, p, 0); //thread_suspend_switch(td); PROC_UNLOCK; ps_mtx_lock; end else if ((prop and SA_IGNORE)<>0) then begin //ignore end else begin Exit(sig); end; end; SIG_IGN:; //ignore else Exit(sig); end; sigqueue_delete(@td^.td_sigqueue,sig); sigqueue_delete(@p_proc.p_sigqueue,sig); until false; end; function postsig(sig:Integer):Integer; var td:p_kthread; action:sig_t; ksi:ksiginfo_t; returnmask:sigset_t; begin td:=curkthread; Assert(sig<>0,'postsig'); ksiginfo_init(@ksi); if (sigqueue_get(@td^.td_sigqueue,sig,@ksi)=0) and (sigqueue_get(@p_proc.p_sigqueue,sig,@ksi)=0) then begin Exit(0); end; ksi.ksi_info.si_signo:=sig; //if (ksi.ksi_code=SI_TIMER) // itimer_accept(p, ksi.ksi_timerid, &ksi); action:=p_sigacts.ps_sigact[_SIG_IDX(sig)]; if (action=sig_t(SIG_DFL)) then begin ps_mtx_unlock; sigexit(td,sig); // NOTREACHED end else begin Assert((action<>sig_t(SIG_IGN)) and (not SIGISMEMBER(@td^.td_sigmask,sig)),'postsig action'); if ((td^.td_pflags and TDP_OLDMASK)<>0) then begin returnmask:=td^.td_oldsigmask; td^.td_pflags:=td^.td_pflags and (not TDP_OLDMASK); end else begin returnmask:=td^.td_sigmask; end; sendsig(action,@ksi,@returnmask); postsig_done(sig,td); end; Result:=1; end; procedure sigexit(td:p_kthread;sig:Integer); public; begin exit1(W_EXITCODE(0,sig)); // NOTREACHED end; // procedure ast; public; var td:p_kthread; flags,sig:Integer; // sttop:Pointer; stack:Pointer; begin td:=curkthread; if (td=nil) then Exit; Writeln('ast'); //teb stack if ((td^.pcb_flags and PCB_IS_JIT)=0) then begin sttop:=td^.td_teb^.sttop; stack:=td^.td_teb^.stack; // td^.td_teb^.sttop:=td^.td_kstack.sttop; td^.td_teb^.stack:=td^.td_kstack.stack; end; //teb stack thread_lock(td); flags:=td^.td_flags; td^.td_flags:=flags and (not ( TDF_ASTPENDING or TDF_NEEDSUSPCHK or TDF_NEEDRESCHED or TDF_NEEDSIGCHK or TDF_ALRMPEND or TDF_PROFPEND or TDF_MACPEND )); thread_unlock(td); if ((flags and TDF_ALRMPEND)<>0) then begin PROC_LOCK; kern_psignal(SIGVTALRM); PROC_UNLOCK; end; if ((flags and TDF_PROFPEND)<>0) then begin PROC_LOCK; kern_psignal(SIGPROF); PROC_UNLOCK; end; if ((flags and TDF_NEEDRESCHED)<>0) then begin thread_lock(td); sched_prio(td,td^.td_user_pri); mi_switch(SW_INVOL or SWT_NEEDRESCHED); thread_unlock(td); end; if ((flags and TDF_NEEDSIGCHK)<>0) or (p_proc.p_pendingcnt>0) or (not SIGISEMPTY(@p_proc.p_sigqueue.sq_list)) then begin PROC_LOCK; ps_mtx_lock; repeat sig:=cursig(td,SIG_STOP_ALLOWED); if (sig=0) then Break; postsig(sig); until false; ps_mtx_unlock; PROC_UNLOCK; end; if ((flags and TDF_NEEDSUSPCHK)<>0) then begin //PROC_LOCK; //thread_suspend_check(0); //PROC_UNLOCK; end; if ((td^.td_pflags and TDP_OLDMASK)<>0) then begin td^.td_pflags:=td^.td_pflags and (not TDP_OLDMASK); kern_sigprocmask(td,SIG_SETMASK,@td^.td_oldsigmask,nil,0); end; if ((flags and TDF_SUSP_CTX)<>0) then begin // context suspend thread_lock(td); //recheck? if ((td^.td_flags and TDF_SUSP_CTX)<>0) then begin td^.td_flags:=td^.td_flags and (not TDF_SUSP_CTX); td^.td_state:=TDS_INHIBITED; td^.td_inhibitors:=td^.td_inhibitors or TDI_SUSP_CTX; mi_switch(SW_VOL or SWT_SUSPEND); thread_unlock(td); end else begin thread_unlock(td); end; end; if ((td^.td_flags and TDF_ASTPENDING)=0) then begin thread_lock(td); td^.td_flags:=td^.td_flags and (not TDF_UNUSED09); //sony ext???? thread_unlock(td); end; //teb stack if ((td^.pcb_flags and PCB_IS_JIT)=0) then begin td^.td_teb^.sttop:=sttop; td^.td_teb^.stack:=stack; end; //teb stack end; // function filt_sigattach(kn:p_knote):Integer; begin kn^.kn_ptr.p_proc:=@p_proc; kn^.kn_flags:=kn^.kn_flags or EV_CLEAR; // automatically set knlist_add(@p_proc.p_klist, kn, 0); Exit(0); end; procedure filt_sigdetach(kn:p_knote); begin knlist_remove(@p_proc.p_klist, kn, 0); end; function filt_signal(kn:p_knote;hint:QWORD):Integer; begin if ((hint and NOTE_SIGNAL)<>0) then begin hint:=hint and (not NOTE_SIGNAL); if (kn^.kn_id=hint) then begin Inc(kn^.kn_kevent.data); end; end; Exit(ord(kn^.kn_data<>0)); end; end.