#include <u.h>
#include <libc.h>
#include <ureg.h>
#include "linuxsys.h"
#include "linux.h"
static struct {
char *msg; /* just check prefix */
int num;
} sigtab[] = {
{"hangup", SIGHUP},
{"interrupt", SIGINT},
{"quit", SIGQUIT},
{"alarm", SIGALRM},
{"sys: trap: illegal instruction", SIGILL},
{"sys: trap: reserved instruction", SIGILL},
{"sys: trap: reserved", SIGILL},
{"sys: trap: arithmetic overflow", SIGFPE},
{"abort", SIGABRT},
{"sys: fp:", SIGFPE},
{"exit", SIGKILL},
{"die", SIGKILL},
{"kill", SIGKILL},
{"sys: trap: bus error", SIGSEGV},
{"sys: trap: address error", SIGSEGV},
{"sys: trap: TLB", SIGSEGV},
{"sys: write on closed pipe", SIGPIPE},
{"alarm", SIGALRM},
{"term", SIGTERM},
{"usr1", SIGUSR1},
{"usr2", SIGUSR2},
{"rt1", SIGRT1},
{"rt2", SIGRT2},
{"rt3", SIGRT3},
{"rt4", SIGRT4},
{"rt5", SIGRT5},
{"rt6", SIGRT6},
{"rt7", SIGRT7},
{"rt8", SIGRT8},
{"tstp", SIGTSTP},
{"ttin", SIGTTIN},
{"ttou", SIGTTOU},
{"stop", SIGSTOP},
{"start", SIGCONT},
};
#define NSIGTAB ((sizeof sigtab)/(sizeof (sigtab[0])))
int
stringsig(char *msg)
{
int i;
for(i=0; i<NSIGTAB; i++){
if(strncmp(msg, sigtab[i].msg, strlen(sigtab[i].msg)) == 0)
return sigtab[i].num;
}
return 0;
}
char*
sigstring(int sig)
{
int i;
for(i=0; i<NSIGTAB; i++){
if(sigtab[i].num == sig)
return sigtab[i].msg;
}
return nil;
}
static void
dosig(Sigstate *ss, int sig, void *info, uvlong rblocked)
{
void *h;
USED(info);
h = ss->action[sig-1].handler;
if((ulong)h > 2){
ss->blocked |= ss->action[sig-1].blocked;
callsignal(sig, h);
ss->blocked = rblocked;
}
}
static int
sigenqueue(Sigqueue *q, int sig, void *info)
{
int a, i;
a = i = q->wp;
i = (i + 1) & (SIGQUEUESIZE - 1);
if(i == q->rp)
return 0;
assert(q->e[a].sig == 0);
q->e[a].sig = sig;
q->e[a].info = info;
q->wp = i;
return 1;
}
static int
sigdequeue(Sigqueue *q, int *psig, void **pinfo, uvlong blocked)
{
int i, a;
a = i = q->rp;
for(;;){
if(i == q->wp)
return 0;
if(!((1LL << (q->e[i].sig-1)) & blocked))
break;
i = (i + 1) & (SIGQUEUESIZE - 1);
}
if(psig)
*psig = q->e[i].sig;
if(pinfo)
*pinfo = q->e[i].info;
q->e[i].sig = 0;
if(i == a)
q->rp = (i + 1) & (SIGQUEUESIZE - 1);
return 1;
}
static uvlong
sigpeekqueue(Sigqueue *q)
{
int i;
uvlong m;
m = 0LL;
for(i = q->rp; i != q->wp; i = (i + 1) & (SIGQUEUESIZE - 1))
m |= 1LL << (q->e[i].sig-1);
return m;
}
void sigprocess(Sigstate *ss)
{
int sig;
void *info;
uvlong rblocked;
if(ss->level)
return;
for(sig=1; sig<=32; sig++){
ulong m;
m = 1 << (sig-1);
if((m & ss->pending) == 0)
continue;
rblocked = ss->blocked;
if(m & rblocked)
continue;
info = ss->info[sig-1];
ss->pending &= ~m;
dosig(ss, sig, info, rblocked);
}
for(;;){
rblocked = ss->blocked;
if(!sigdequeue(&ss->rtsq, &sig, &info, rblocked))
break;
dosig(ss, sig, info, rblocked);
}
}
uvlong
sigpending(Sigstate *ss)
{
uvlong m;
m = (uvlong)ss->pending;
m |= sigpeekqueue(&ss->rtsq);
return m;
}
void
sigclearall(Sigstate *ss)
{
ss->pending = 0;
ss->rtsq.rp = ss->rtsq.wp = 0;
}
void sigdisable(Sigstate *ss)
{
_xinc(&ss->level);
}
void sigenable(Sigstate *ss)
{
if(!_xdec(&ss->level))
sigprocess(ss);
}
int
signote(Sigstate *ss, char *msg)
{
int sig;
void *info;
if((sig = stringsig(msg)) < 1)
return 0;
info = nil;
if(sig <= 32){
ulong m;
m = 1<<(sig-1);
if(m & ss->pending){
fprint(2, "signal %d lost!\n", sig);
return 1;
}
ss->info[sig-1] = info;
ss->pending |= m;
} else {
if(!sigenqueue(&ss->rtsq, sig, info))
fprint(2, "rt signal %d lost!\n", sig);
}
return 1;
}
|