You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
130 lines
2.7 KiB
130 lines
2.7 KiB
/*
|
|
* linux/kernel/signal.c
|
|
*
|
|
* (C) 1991 Linus Torvalds
|
|
*/
|
|
|
|
#include <linux/sched.h>
|
|
#include <linux/kernel.h>
|
|
#include <asm/segment.h>
|
|
#include <errno.h>
|
|
#include <signal.h>
|
|
|
|
volatile void do_exit(int error_code);
|
|
|
|
int sys_sgetmask()
|
|
{
|
|
return current->blocked;
|
|
}
|
|
|
|
int sys_ssetmask(int newmask)
|
|
{
|
|
int old=current->blocked;
|
|
|
|
current->blocked = newmask & ~(1<<(SIGKILL-1));
|
|
return old;
|
|
}
|
|
|
|
int sys_sigpending()
|
|
{
|
|
return -ENOSYS;
|
|
}
|
|
|
|
int sys_sigsuspend()
|
|
{
|
|
return -ENOSYS;
|
|
}
|
|
|
|
static inline void save_old(char * from,char * to)
|
|
{
|
|
int i;
|
|
|
|
verify_area(to, sizeof(struct sigaction));
|
|
for (i=0 ; i< sizeof(struct sigaction) ; i++) {
|
|
put_fs_byte(*from,to);
|
|
from++;
|
|
to++;
|
|
}
|
|
}
|
|
|
|
static inline void get_new(char * from,char * to)
|
|
{
|
|
int i;
|
|
|
|
for (i=0 ; i< sizeof(struct sigaction) ; i++)
|
|
*(to++) = get_fs_byte(from++);
|
|
}
|
|
|
|
int sys_signal(int signum, long handler, long restorer)
|
|
{
|
|
struct sigaction tmp;
|
|
|
|
if (signum<1 || signum>32 || signum==SIGKILL)
|
|
return -1;
|
|
tmp.sa_handler = (void (*)(int)) handler;
|
|
tmp.sa_mask = 0;
|
|
tmp.sa_flags = SA_ONESHOT | SA_NOMASK;
|
|
tmp.sa_restorer = (void (*)(void)) restorer;
|
|
handler = (long) current->sigaction[signum-1].sa_handler;
|
|
current->sigaction[signum-1] = tmp;
|
|
return handler;
|
|
}
|
|
|
|
int sys_sigaction(int signum, const struct sigaction * action,
|
|
struct sigaction * oldaction)
|
|
{
|
|
struct sigaction tmp;
|
|
|
|
if (signum<1 || signum>32 || signum==SIGKILL)
|
|
return -1;
|
|
tmp = current->sigaction[signum-1];
|
|
get_new((char *) action,
|
|
(char *) (signum-1+current->sigaction));
|
|
if (oldaction)
|
|
save_old((char *) &tmp,(char *) oldaction);
|
|
if (current->sigaction[signum-1].sa_flags & SA_NOMASK)
|
|
current->sigaction[signum-1].sa_mask = 0;
|
|
else
|
|
current->sigaction[signum-1].sa_mask |= (1<<(signum-1));
|
|
return 0;
|
|
}
|
|
|
|
void do_signal(long signr,long eax, long ebx, long ecx, long edx,
|
|
long fs, long es, long ds,
|
|
long eip, long cs, long eflags,
|
|
unsigned long * esp, long ss)
|
|
{
|
|
unsigned long sa_handler;
|
|
long old_eip=eip;
|
|
struct sigaction * sa = current->sigaction + signr - 1;
|
|
int longs;
|
|
unsigned long * tmp_esp;
|
|
|
|
sa_handler = (unsigned long) sa->sa_handler;
|
|
if (sa_handler==1)
|
|
return;
|
|
if (!sa_handler) {
|
|
if (signr==SIGCHLD)
|
|
return;
|
|
else
|
|
do_exit(1<<(signr-1));
|
|
}
|
|
if (sa->sa_flags & SA_ONESHOT)
|
|
sa->sa_handler = NULL;
|
|
*(&eip) = sa_handler;
|
|
longs = (sa->sa_flags & SA_NOMASK)?7:8;
|
|
*(&esp) -= longs;
|
|
verify_area(esp,longs*4);
|
|
tmp_esp=esp;
|
|
put_fs_long((long) sa->sa_restorer,tmp_esp++);
|
|
put_fs_long(signr,tmp_esp++);
|
|
if (!(sa->sa_flags & SA_NOMASK))
|
|
put_fs_long(current->blocked,tmp_esp++);
|
|
put_fs_long(eax,tmp_esp++);
|
|
put_fs_long(ecx,tmp_esp++);
|
|
put_fs_long(edx,tmp_esp++);
|
|
put_fs_long(eflags,tmp_esp++);
|
|
put_fs_long(old_eip,tmp_esp++);
|
|
current->blocked |= sa->sa_mask;
|
|
}
|