#include <u.h>
#include <libc.h>
#include <ureg.h>
#include "linuxsys.h"
#include "linux.h"
SYSCALL(sys_kill)
{
int pid;
int sig;
pid = (int)ARG1;
sig = (int)ARG2;
RETURN(_kill(pid, sig));
}
struct sigaction
{
void *handler;
ulong flags;
void *restorer;
uchar mask;
};
static void
uv2sigset(uchar *set, int setsize, uvlong mask)
{
int i;
for(i=0; i<setsize; i++){
if(i < sizeof(uvlong)){
set[i] = ((mask >> (i*8)) & 0xff);
} else {
set[i] = 0;
}
}
}
static uvlong
sigset2uv(uchar *set, int setsize)
{
uvlong r;
int i;
r = 0LL;
if(setsize > sizeof(uvlong))
setsize = sizeof(uvlong);
for(i=0; i<setsize; i++)
r |= (uvlong)set[i] << (i*8);
return r;
}
enum
{
SIG_BLOCK = 0,
SIG_UNBLOCK = 1,
SIG_SETMASK = 2,
};
SYSCALL(sys_rt_sigprocmask)
{
int how;
uchar *act;
uchar *oact;
int setsize;
uvlong x;
how = (int)ARG1;
act = (uchar*)ARG2;
oact = (uchar*)ARG3;
setsize = (int)ARG4;
DPRINT("rt_sigprocmask(%d, 0x%p, 0x%p, %d)...", how, act, oact, setsize);
if(oact)
uv2sigset(oact, setsize, threadp->ss.blocked);
if(act){
x = sigset2uv(act, setsize);
} else {
RETURN(0);
}
x &= ~(1LL<<(SIGKILL-1));
x &= ~(1LL <<(SIGSTOP-1));
switch(how){
default:
RETURN(-EINVAL);
case SIG_BLOCK:
threadp->ss.blocked |= x;
break;
case SIG_UNBLOCK:
threadp->ss.blocked &= ~x;
break;
case SIG_SETMASK:
threadp->ss.blocked = x;
break;
}
RETURN(0);
}
static void
printsigstate(char *s)
{
uvlong pending;
uvlong blocked;
blocked = threadp->ss.blocked;
pending = sigpending(&threadp->ss);
fprint(2, "[%d] [%s] sigstate: pending: 0x%llux, blocked 0x%llux, ready 0x%llux\n",
threadp->pid, s, pending, blocked, pending & ~blocked);
}
SYSCALL(sys_rt_sigsuspend)
{
uvlong x;
uvlong t;
uchar *sm;
int setsize;
sm = (uchar*)ARG1;
setsize = (int)ARG2;
DPRINT("rt_sigsuspend(0x%p, %d)...",sm, setsize);
// printsigstate("before sigsuspend");
t = threadp->ss.blocked;
x = sigset2uv(sm, setsize);
x &= ~(1LL<<(SIGKILL-1));
x &= ~(1LL <<(SIGSTOP-1));
threadp->ss.blocked = x;
while(!(sigpending(&threadp->ss) & ~x)){
// printsigstate("sigsuspend sleep");
sleep(10000);
// printsigstate("sigsuspend wakeup");
}
// printsigstate("sigsuspend break");
sigenable(&threadp->ss);
sigdisable(&threadp->ss);
threadp->ss.blocked = t;
// printsigstate("after sigsuspend");
RETURN(-EINTR);
}
SYSCALL(sys_rt_sigaction)
{
int sig;
struct sigaction *act;
struct sigaction *oact;
int setsize;
sig = (int)ARG1;
act = (struct sigaction*)ARG2;
oact = (struct sigaction*)ARG3;
setsize = (int)ARG4;
DPRINT("rt_sigaction(%d, 0x%p, 0x%p, %d)...", sig, act, oact, setsize);
if(act && act->flags & (SA_SIGINFO | SA_ONSTACK)){
fprint(2, "[%d] rt_sigaction: unsopprted signalflags %lux\n", threadp->tid, act->flags);
RETURN(-EINVAL);
}
if(oact){
oact->handler = threadp->ss.action[sig-1].handler;
oact->flags = threadp->ss.action[sig-1].flags;
oact->restorer = 0;
uv2sigset(&oact->mask, setsize, threadp->ss.action[sig-1].blocked);
}
if(act){
threadp->ss.action[sig-1].handler = (void*)act->handler;
threadp->ss.action[sig-1].flags = act->flags;
threadp->ss.action[sig-1].blocked = sigset2uv(&act->mask, setsize);
}
RETURN(0);
}
SYSCALL(sys_rt_sigpending)
{
uchar *set;
int setsize;
set = (uchar*)ARG1;
setsize = (int)ARG2;
DPRINT("rt_sigpending(0x%p, %d)...", set, setsize);
uv2sigset(set, setsize, sigpending(&threadp->ss));
RETURN(0);
}
|