summaryrefslogtreecommitdiffstats
path: root/src/kernel/exit.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/exit.c')
-rw-r--r--src/kernel/exit.c196
1 files changed, 196 insertions, 0 deletions
diff --git a/src/kernel/exit.c b/src/kernel/exit.c
new file mode 100644
index 0000000..b22de34
--- /dev/null
+++ b/src/kernel/exit.c
@@ -0,0 +1,196 @@
1/*
2 * linux/kernel/exit.c
3 *
4 * (C) 1991 Linus Torvalds
5 */
6
7#include <errno.h>
8#include <signal.h>
9#include <sys/wait.h>
10
11#include <linux/sched.h>
12#include <linux/kernel.h>
13#include <linux/tty.h>
14#include <asm/segment.h>
15
16int sys_pause(void);
17int sys_close(int fd);
18
19void release(struct task_struct * p)
20{
21 int i;
22
23 if (!p)
24 return;
25 for (i=1 ; i<NR_TASKS ; i++)
26 if (task[i]==p) {
27 task[i]=NULL;
28 free_page((long)p);
29 schedule();
30 return;
31 }
32 panic("trying to release non-existent task");
33}
34
35static inline int send_sig(long sig,struct task_struct * p,int priv)
36{
37 if (!p || sig<1 || sig>32)
38 return -EINVAL;
39 if (priv || (current->euid==p->euid) || suser())
40 p->signal |= (1<<(sig-1));
41 else
42 return -EPERM;
43 return 0;
44}
45
46static void kill_session(void)
47{
48 struct task_struct **p = NR_TASKS + task;
49
50 while (--p > &FIRST_TASK) {
51 if (*p && (*p)->session == current->session)
52 (*p)->signal |= 1<<(SIGHUP-1);
53 }
54}
55
56/*
57 * XXX need to check permissions needed to send signals to process
58 * groups, etc. etc. kill() permissions semantics are tricky!
59 */
60int sys_kill(int pid,int sig)
61{
62 struct task_struct **p = NR_TASKS + task;
63 int err, retval = 0;
64
65 if (!pid) while (--p > &FIRST_TASK) {
66 if (*p && (*p)->pgrp == current->pid)
67 if ((err=send_sig(sig,*p,1)))
68 retval = err;
69 } else if (pid>0) while (--p > &FIRST_TASK) {
70 if (*p && (*p)->pid == pid)
71 if ((err=send_sig(sig,*p,0)))
72 retval = err;
73 } else if (pid == -1) while (--p > &FIRST_TASK) {
74 if ((err = send_sig(sig,*p,0)))
75 retval = err;
76 } else while (--p > &FIRST_TASK)
77 if (*p && (*p)->pgrp == -pid)
78 if ((err = send_sig(sig,*p,0)))
79 retval = err;
80 return retval;
81}
82
83static void tell_father(int pid)
84{
85 int i;
86
87 if (pid)
88 for (i=0;i<NR_TASKS;i++) {
89 if (!task[i])
90 continue;
91 if (task[i]->pid != pid)
92 continue;
93 task[i]->signal |= (1<<(SIGCHLD-1));
94 return;
95 }
96/* if we don't find any fathers, we just release ourselves */
97/* This is not really OK. Must change it to make father 1 */
98 printk("BAD BAD - no father found\n\r");
99 release(current);
100}
101
102int do_exit(long code)
103{
104 int i;
105 free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
106 free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
107 for (i=0 ; i<NR_TASKS ; i++)
108 if (task[i] && task[i]->father == current->pid) {
109 task[i]->father = 1;
110 if (task[i]->state == TASK_ZOMBIE)
111 /* assumption task[1] is always init */
112 (void) send_sig(SIGCHLD, task[1], 1);
113 }
114 for (i=0 ; i<NR_OPEN ; i++)
115 if (current->filp[i])
116 sys_close(i);
117 iput(current->pwd);
118 current->pwd=NULL;
119 iput(current->root);
120 current->root=NULL;
121 iput(current->executable);
122 current->executable=NULL;
123 if (current->leader && current->tty >= 0)
124 tty_table[current->tty].pgrp = 0;
125 if (last_task_used_math == current)
126 last_task_used_math = NULL;
127 if (current->leader)
128 kill_session();
129 current->state = TASK_ZOMBIE;
130 current->exit_code = code;
131 tell_father(current->father);
132 schedule();
133 return (-1); /* just to suppress warnings */
134}
135
136int sys_exit(int error_code)
137{
138 return do_exit((error_code&0xff)<<8);
139}
140
141int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
142{
143 int flag, code;
144 struct task_struct ** p;
145
146 verify_area(stat_addr,4);
147repeat:
148 flag=0;
149 for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
150 if (!*p || *p == current)
151 continue;
152 if ((*p)->father != current->pid)
153 continue;
154 if (pid>0) {
155 if ((*p)->pid != pid)
156 continue;
157 } else if (!pid) {
158 if ((*p)->pgrp != current->pgrp)
159 continue;
160 } else if (pid != -1) {
161 if ((*p)->pgrp != -pid)
162 continue;
163 }
164 switch ((*p)->state) {
165 case TASK_STOPPED:
166 if (!(options & WUNTRACED))
167 continue;
168 put_fs_long(0x7f,stat_addr);
169 return (*p)->pid;
170 case TASK_ZOMBIE:
171 current->cutime += (*p)->utime;
172 current->cstime += (*p)->stime;
173 flag = (*p)->pid;
174 code = (*p)->exit_code;
175 release(*p);
176 put_fs_long(code,stat_addr);
177 return flag;
178 default:
179 flag=1;
180 continue;
181 }
182 }
183 if (flag) {
184 if (options & WNOHANG)
185 return 0;
186 current->state=TASK_INTERRUPTIBLE;
187 schedule();
188 if (!(current->signal &= ~(1<<(SIGCHLD-1))))
189 goto repeat;
190 else
191 return -EINTR;
192 }
193 return -ECHILD;
194}
195
196