|
|
1.1 root 1: /*
2: * linux/kernel/signal.c
3: *
1.1.1.7 ! root 4: * Copyright (C) 1991, 1992 Linus Torvalds
1.1 root 5: */
6:
7: #include <linux/sched.h>
8: #include <linux/kernel.h>
1.1.1.7 ! root 9: #include <linux/signal.h>
! 10: #include <linux/errno.h>
! 11: #include <linux/wait.h>
! 12: #include <linux/ptrace.h>
1.1 root 13:
1.1.1.7 ! root 14: #include <asm/segment.h>
1.1.1.5 root 15:
1.1.1.6 root 16: extern int core_dump(long signr,struct pt_regs * regs);
17:
1.1 root 18: int sys_sgetmask()
19: {
20: return current->blocked;
21: }
22:
23: int sys_ssetmask(int newmask)
24: {
25: int old=current->blocked;
26:
1.1.1.3 root 27: current->blocked = newmask & ~(1<<(SIGKILL-1)) & ~(1<<(SIGSTOP-1));
1.1 root 28: return old;
29: }
30:
1.1.1.3 root 31: int sys_sigpending(sigset_t *set)
32: {
33: /* fill in "set" with signals pending but blocked. */
34: verify_area(set,4);
35: put_fs_long(current->blocked & current->signal, (unsigned long *)set);
36: return 0;
37: }
38:
39: /* atomically swap in the new signal mask, and wait for a signal.
40: *
41: * we need to play some games with syscall restarting. We get help
42: * from the syscall library interface. Note that we need to coordinate
43: * the calling convention with the libc routine.
44: *
45: * "set" is just the sigmask as described in 1003.1-1988, 3.3.7.
46: * It is assumed that sigset_t can be passed as a 32 bit quantity.
47: *
48: * "restart" holds a restart indication. If it's non-zero, then we
49: * install the old mask, and return normally. If it's zero, we store
50: * the current mask in old_mask and block until a signal comes in.
51: */
52: int sys_sigsuspend(int restart, unsigned long old_mask, unsigned long set)
53: {
54: extern int sys_pause(void);
55:
56: if (restart) {
57: /* we're restarting */
58: current->blocked = old_mask;
59: return -EINTR;
60: }
61: /* we're not restarting. do the work */
62: *(&restart) = 1;
63: *(&old_mask) = current->blocked;
64: current->blocked = set;
65: (void) sys_pause(); /* return after a signal arrives */
66: return -ERESTARTNOINTR; /* handle the signal, and come back */
67: }
68:
1.1 root 69: static inline void save_old(char * from,char * to)
70: {
71: int i;
72:
73: verify_area(to, sizeof(struct sigaction));
74: for (i=0 ; i< sizeof(struct sigaction) ; i++) {
75: put_fs_byte(*from,to);
76: from++;
77: to++;
78: }
79: }
80:
81: static inline void get_new(char * from,char * to)
82: {
83: int i;
84:
85: for (i=0 ; i< sizeof(struct sigaction) ; i++)
86: *(to++) = get_fs_byte(from++);
87: }
88:
89: int sys_signal(int signum, long handler, long restorer)
90: {
91: struct sigaction tmp;
92:
1.1.1.3 root 93: if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
94: return -EINVAL;
1.1 root 95: tmp.sa_handler = (void (*)(int)) handler;
96: tmp.sa_mask = 0;
1.1.1.6 root 97: tmp.sa_flags = SA_ONESHOT | SA_NOMASK | SA_INTERRUPT;
1.1 root 98: tmp.sa_restorer = (void (*)(void)) restorer;
99: handler = (long) current->sigaction[signum-1].sa_handler;
100: current->sigaction[signum-1] = tmp;
101: return handler;
102: }
103:
104: int sys_sigaction(int signum, const struct sigaction * action,
105: struct sigaction * oldaction)
106: {
107: struct sigaction tmp;
108:
1.1.1.3 root 109: if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
110: return -EINVAL;
1.1 root 111: tmp = current->sigaction[signum-1];
112: get_new((char *) action,
113: (char *) (signum-1+current->sigaction));
114: if (oldaction)
115: save_old((char *) &tmp,(char *) oldaction);
116: if (current->sigaction[signum-1].sa_flags & SA_NOMASK)
117: current->sigaction[signum-1].sa_mask = 0;
118: else
119: current->sigaction[signum-1].sa_mask |= (1<<(signum-1));
120: return 0;
121: }
122:
1.1.1.4 root 123: extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
124:
1.1.1.7 ! root 125: /*
! 126: * Note that 'init' is a special process: it doesn't get signals it doesn't
! 127: * want to handle. Thus you cannot kill init even with a SIGKILL even by
! 128: * mistake.
! 129: */
1.1.1.6 root 130: int do_signal(long signr,struct pt_regs * regs)
1.1 root 131: {
1.1.1.2 root 132: unsigned long sa_handler;
1.1.1.6 root 133: long old_eip = regs->eip;
1.1 root 134: struct sigaction * sa = current->sigaction + signr - 1;
135: int longs;
136: unsigned long * tmp_esp;
137:
1.1.1.3 root 138: #ifdef notdef
139: printk("pid: %d, signr: %x, eax=%d, oeax = %d, int=%d\n",
1.1.1.6 root 140: current->pid, signr, regs->eax, regs->orig_eax,
1.1.1.3 root 141: sa->sa_flags & SA_INTERRUPT);
142: #endif
1.1.1.6 root 143: sa_handler = (unsigned long) sa->sa_handler;
144: if ((regs->orig_eax != -1) &&
145: ((regs->eax == -ERESTARTSYS) || (regs->eax == -ERESTARTNOINTR))) {
146: if ((sa_handler > 1) && (regs->eax == -ERESTARTSYS) &&
147: (sa->sa_flags & SA_INTERRUPT))
148: regs->eax = -EINTR;
1.1.1.3 root 149: else {
1.1.1.6 root 150: regs->eax = regs->orig_eax;
151: regs->eip = old_eip -= 2;
1.1.1.3 root 152: }
153: }
1.1.1.4 root 154: if (sa_handler==1) {
155: /* check for SIGCHLD: it's special */
156: if (signr == SIGCHLD)
157: while (sys_waitpid(-1,NULL,WNOHANG) > 0)
158: /* nothing */;
1.1.1.3 root 159: return(1); /* Ignore, see if there are more signals... */
1.1.1.4 root 160: }
1.1 root 161: if (!sa_handler) {
1.1.1.7 ! root 162: if (current->pid == 1)
! 163: return 1;
1.1.1.3 root 164: switch (signr) {
165: case SIGCONT:
166: case SIGCHLD:
1.1.1.4 root 167: case SIGWINCH:
1.1.1.3 root 168: return(1); /* Ignore, ... */
169:
170: case SIGSTOP:
171: case SIGTSTP:
172: case SIGTTIN:
173: case SIGTTOU:
174: current->state = TASK_STOPPED;
175: current->exit_code = signr;
176: if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &
177: SA_NOCLDSTOP))
1.1.1.6 root 178: send_sig(SIGCHLD, current->p_pptr, 1);
1.1.1.3 root 179: return(1); /* Reschedule another event */
180:
181: case SIGQUIT:
182: case SIGILL:
183: case SIGTRAP:
184: case SIGIOT:
185: case SIGFPE:
186: case SIGSEGV:
1.1.1.6 root 187: if (core_dump(signr,regs))
1.1.1.3 root 188: do_exit(signr|0x80);
189: /* fall through */
190: default:
191: do_exit(signr);
192: }
1.1 root 193: }
1.1.1.3 root 194: /*
195: * OK, we're invoking a handler
196: */
1.1 root 197: if (sa->sa_flags & SA_ONESHOT)
198: sa->sa_handler = NULL;
1.1.1.6 root 199: regs->eip = sa_handler;
200: longs = (sa->sa_flags & SA_NOMASK)?(7*4):(8*4);
201: regs->esp -= longs;
202: tmp_esp = (unsigned long *) regs->esp;
203: verify_area(tmp_esp,longs);
1.1 root 204: put_fs_long((long) sa->sa_restorer,tmp_esp++);
205: put_fs_long(signr,tmp_esp++);
206: if (!(sa->sa_flags & SA_NOMASK))
207: put_fs_long(current->blocked,tmp_esp++);
1.1.1.6 root 208: put_fs_long(regs->eax,tmp_esp++);
209: put_fs_long(regs->ecx,tmp_esp++);
210: put_fs_long(regs->edx,tmp_esp++);
211: put_fs_long(regs->eflags,tmp_esp++);
1.1 root 212: put_fs_long(old_eip,tmp_esp++);
213: current->blocked |= sa->sa_mask;
1.1.1.4 root 214: /* force a supervisor-mode page-in of the signal handler to reduce races */
215: __asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler));
1.1.1.3 root 216: return(0); /* Continue, execute handler */
1.1 root 217: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.