initial version
This commit is contained in:
209
Book-Lite/linux-0.12/kernel/signal.c
Normal file
209
Book-Lite/linux-0.12/kernel/signal.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* linux/kernel/signal.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
#include <linux/sched.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <asm/segment.h>
|
||||
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
|
||||
int sys_sgetmask()
|
||||
{
|
||||
return current->blocked;
|
||||
}
|
||||
|
||||
int sys_ssetmask(int newmask)
|
||||
{
|
||||
int old=current->blocked;
|
||||
|
||||
current->blocked = newmask & ~(1<<(SIGKILL-1)) & ~(1<<(SIGSTOP-1));
|
||||
return old;
|
||||
}
|
||||
|
||||
int sys_sigpending(sigset_t *set)
|
||||
{
|
||||
/* fill in "set" with signals pending but blocked. */
|
||||
verify_area(set,4);
|
||||
put_fs_long(current->blocked & current->signal, (unsigned long *)set);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* atomically swap in the new signal mask, and wait for a signal.
|
||||
*
|
||||
* we need to play some games with syscall restarting. We get help
|
||||
* from the syscall library interface. Note that we need to coordinate
|
||||
* the calling convention with the libc routine.
|
||||
*
|
||||
* "set" is just the sigmask as described in 1003.1-1988, 3.3.7.
|
||||
* It is assumed that sigset_t can be passed as a 32 bit quantity.
|
||||
*
|
||||
* "restart" holds a restart indication. If it's non-zero, then we
|
||||
* install the old mask, and return normally. If it's zero, we store
|
||||
* the current mask in old_mask and block until a signal comes in.
|
||||
*/
|
||||
int sys_sigsuspend(int restart, unsigned long old_mask, unsigned long set)
|
||||
{
|
||||
extern int sys_pause(void);
|
||||
|
||||
if (restart) {
|
||||
/* we're restarting */
|
||||
current->blocked = old_mask;
|
||||
return -EINTR;
|
||||
}
|
||||
/* we're not restarting. do the work */
|
||||
*(&restart) = 1;
|
||||
*(&old_mask) = current->blocked;
|
||||
current->blocked = set;
|
||||
(void) sys_pause(); /* return after a signal arrives */
|
||||
return -ERESTARTNOINTR; /* handle the signal, and come back */
|
||||
}
|
||||
|
||||
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 || signum==SIGSTOP)
|
||||
return -EINVAL;
|
||||
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 || signum==SIGSTOP)
|
||||
return -EINVAL;
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine writes a core dump image in the current directory.
|
||||
* Currently not implemented.
|
||||
*/
|
||||
int core_dump(long signr)
|
||||
{
|
||||
return(0); /* We didn't do a dump */
|
||||
}
|
||||
|
||||
int do_signal(long signr,long eax,long ebx, long ecx, long edx, long orig_eax,
|
||||
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;
|
||||
|
||||
#ifdef notdef
|
||||
printk("pid: %d, signr: %x, eax=%d, oeax = %d, int=%d\n",
|
||||
current->pid, signr, eax, orig_eax,
|
||||
sa->sa_flags & SA_INTERRUPT);
|
||||
#endif
|
||||
if ((orig_eax != -1) &&
|
||||
((eax == -ERESTARTSYS) || (eax == -ERESTARTNOINTR))) {
|
||||
if ((eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT) ||
|
||||
signr < SIGCONT || signr > SIGTTOU))
|
||||
*(&eax) = -EINTR;
|
||||
else {
|
||||
*(&eax) = orig_eax;
|
||||
*(&eip) = old_eip -= 2;
|
||||
}
|
||||
}
|
||||
sa_handler = (unsigned long) sa->sa_handler;
|
||||
if (sa_handler==1)
|
||||
return(1); /* Ignore, see if there are more signals... */
|
||||
if (!sa_handler) {
|
||||
switch (signr) {
|
||||
case SIGCONT:
|
||||
case SIGCHLD:
|
||||
return(1); /* Ignore, ... */
|
||||
|
||||
case SIGSTOP:
|
||||
case SIGTSTP:
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
current->state = TASK_STOPPED;
|
||||
current->exit_code = signr;
|
||||
if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
|
||||
SA_NOCLDSTOP))
|
||||
current->p_pptr->signal |= (1<<(SIGCHLD-1));
|
||||
return(1); /* Reschedule another event */
|
||||
|
||||
case SIGQUIT:
|
||||
case SIGILL:
|
||||
case SIGTRAP:
|
||||
case SIGIOT:
|
||||
case SIGFPE:
|
||||
case SIGSEGV:
|
||||
if (core_dump(signr))
|
||||
do_exit(signr|0x80);
|
||||
/* fall through */
|
||||
default:
|
||||
do_exit(signr);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* OK, we're invoking a handler
|
||||
*/
|
||||
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;
|
||||
return(0); /* Continue, execute handler */
|
||||
}
|
||||
Reference in New Issue
Block a user