mirror of https://github.com/red-prig/fpPS4.git
1939 lines
37 KiB
Plaintext
1939 lines
37 KiB
Plaintext
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))<td^.td_sigstk.ss_size);
|
|
end;
|
|
end;
|
|
|
|
Function sigprop(sig:Integer):Integer;
|
|
begin
|
|
Result:=0;
|
|
if (sig>0) and (sig<NSIG) then
|
|
begin
|
|
Result:=sigproptbl[_SIG_IDX(sig)];
|
|
end;
|
|
end;
|
|
|
|
procedure ps_mtx_lock; public;
|
|
begin
|
|
mtx_lock(p_sigacts.ps_mtx);
|
|
end;
|
|
|
|
procedure ps_mtx_unlock; public;
|
|
begin
|
|
mtx_unlock(p_sigacts.ps_mtx);
|
|
end;
|
|
|
|
Function kern_sigaction(sig:Integer;
|
|
act,oact:p_sigaction_t):Integer;
|
|
begin
|
|
if (not _SIG_VALID(sig)) then Exit(EINVAL);
|
|
|
|
PROC_LOCK;
|
|
ps_mtx_lock;
|
|
|
|
if (oact<>nil) 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_size<MINSIGSTKSZ) then Exit(ENOMEM);
|
|
|
|
td^.td_sigstk:=ss^;
|
|
td^.td_pflags:=td^.td_pflags or TDP_ALTSTACK;
|
|
end else
|
|
begin
|
|
td^.td_pflags:=td^.td_pflags and (not TDP_ALTSTACK);
|
|
end;
|
|
end;
|
|
|
|
Result:=0;
|
|
end;
|
|
|
|
Function sys_sigaltstack(ss,oss:Pointer):Integer;
|
|
var
|
|
td:p_kthread;
|
|
_ss,_oss:stack_t;
|
|
p_oss:p_stack_t;
|
|
begin
|
|
td:=curkthread;
|
|
if (td=nil) then Exit(-1);
|
|
|
|
if (ss<>nil) 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.
|
|
|