This source file includes following definitions.
- send_sig
- release
- bad_task_ptr
- audit_ptree
- session_of_pgrp
- kill_pg
- kill_proc
- sys_kill
- is_orphaned_pgrp
- has_stopped_jobs
- forget_original_parent
- do_exit
- sys_exit
- sys_waitpid
1
2
3
4
5
6
7 #define DEBUG_PROC_TREE
8
9 #include <linux/wait.h>
10 #include <linux/errno.h>
11 #include <linux/signal.h>
12 #include <linux/sched.h>
13 #include <linux/kernel.h>
14 #include <linux/mm.h>
15 #include <linux/tty.h>
16
17 #include <asm/segment.h>
18
19 int sys_close(int fd);
20
21 int send_sig(long sig,struct task_struct * p,int priv)
22 {
23 if (!p || (sig < 0) || (sig > 32))
24 return -EINVAL;
25 if (!priv && ((sig != SIGCONT) || (current->session != p->session)) &&
26 (current->euid != p->euid) && (current->uid != p->uid) && !suser())
27 return -EPERM;
28 if (!sig)
29 return 0;
30 if ((sig == SIGKILL) || (sig == SIGCONT)) {
31 if (p->state == TASK_STOPPED)
32 p->state = TASK_RUNNING;
33 p->exit_code = 0;
34 p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) |
35 (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) );
36 }
37
38 if ((sig >= SIGSTOP) && (sig <= SIGTTOU))
39 p->signal &= ~(1<<(SIGCONT-1));
40
41 p->signal |= (1<<(sig-1));
42 if (p->flags & PF_PTRACED) {
43
44 p->exit_code = sig;
45
46
47 if (p->p_pptr != NULL && p->p_pptr->state == TASK_INTERRUPTIBLE)
48 p->p_pptr->state = TASK_RUNNING;
49
50
51 if (p->state == TASK_INTERRUPTIBLE || p->state == TASK_RUNNING)
52 p->state = TASK_STOPPED;
53 }
54 return 0;
55 }
56
57 void release(struct task_struct * p)
58 {
59 int i;
60
61 if (!p)
62 return;
63 if (p == current) {
64 printk("task releasing itself\n\r");
65 return;
66 }
67 for (i=1 ; i<NR_TASKS ; i++)
68 if (task[i] == p) {
69 task[i] = NULL;
70 REMOVE_LINKS(p);
71 free_page((long) p);
72 return;
73 }
74 panic("trying to release non-existent task");
75 }
76
77 #ifdef DEBUG_PROC_TREE
78
79
80
81
82 int bad_task_ptr(struct task_struct *p)
83 {
84 int i;
85
86 if (!p)
87 return 0;
88 for (i=0 ; i<NR_TASKS ; i++)
89 if (task[i] == p)
90 return 0;
91 return 1;
92 }
93
94
95
96
97
98
99
100
101
102
103 void audit_ptree()
104 {
105 int i;
106
107 for (i=1 ; i<NR_TASKS ; i++) {
108 if (!task[i])
109 continue;
110 if (bad_task_ptr(task[i]->p_pptr))
111 printk("Warning, pid %d's parent link is bad\n",
112 task[i]->pid);
113 if (bad_task_ptr(task[i]->p_cptr))
114 printk("Warning, pid %d's child link is bad\n",
115 task[i]->pid);
116 if (bad_task_ptr(task[i]->p_ysptr))
117 printk("Warning, pid %d's ys link is bad\n",
118 task[i]->pid);
119 if (bad_task_ptr(task[i]->p_osptr))
120 printk("Warning, pid %d's os link is bad\n",
121 task[i]->pid);
122 if (task[i]->p_pptr == task[i])
123 printk("Warning, pid %d parent link points to self\n");
124 if (task[i]->p_cptr == task[i])
125 printk("Warning, pid %d child link points to self\n");
126 if (task[i]->p_ysptr == task[i])
127 printk("Warning, pid %d ys link points to self\n");
128 if (task[i]->p_osptr == task[i])
129 printk("Warning, pid %d os link points to self\n");
130 if (task[i]->p_osptr) {
131 if (task[i]->p_pptr != task[i]->p_osptr->p_pptr)
132 printk(
133 "Warning, pid %d older sibling %d parent is %d\n",
134 task[i]->pid, task[i]->p_osptr->pid,
135 task[i]->p_osptr->p_pptr->pid);
136 if (task[i]->p_osptr->p_ysptr != task[i])
137 printk(
138 "Warning, pid %d older sibling %d has mismatched ys link\n",
139 task[i]->pid, task[i]->p_osptr->pid);
140 }
141 if (task[i]->p_ysptr) {
142 if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr)
143 printk(
144 "Warning, pid %d younger sibling %d parent is %d\n",
145 task[i]->pid, task[i]->p_osptr->pid,
146 task[i]->p_osptr->p_pptr->pid);
147 if (task[i]->p_ysptr->p_osptr != task[i])
148 printk(
149 "Warning, pid %d younger sibling %d has mismatched os link\n",
150 task[i]->pid, task[i]->p_ysptr->pid);
151 }
152 if (task[i]->p_cptr) {
153 if (task[i]->p_cptr->p_pptr != task[i])
154 printk(
155 "Warning, pid %d youngest child %d has mismatched parent link\n",
156 task[i]->pid, task[i]->p_cptr->pid);
157 if (task[i]->p_cptr->p_ysptr)
158 printk(
159 "Warning, pid %d youngest child %d has non-NULL ys link\n",
160 task[i]->pid, task[i]->p_cptr->pid);
161 }
162 }
163 }
164 #endif
165
166
167
168
169
170
171 int session_of_pgrp(int pgrp)
172 {
173 struct task_struct **p;
174 int fallback;
175
176 fallback = -1;
177 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
178 if (!*p || (*p)->session <= 0)
179 continue;
180 if ((*p)->pgrp == pgrp)
181 return (*p)->session;
182 if ((*p)->pid == pgrp)
183 fallback = (*p)->session;
184 }
185 return fallback;
186 }
187
188 int kill_pg(int pgrp, int sig, int priv)
189 {
190 struct task_struct **p;
191 int err,retval = -ESRCH;
192 int found = 0;
193
194 if (sig<0 || sig>32 || pgrp<=0)
195 return -EINVAL;
196 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
197 if (*p && (*p)->pgrp == pgrp) {
198 if (sig && (err = send_sig(sig,*p,priv)))
199 retval = err;
200 else
201 found++;
202 }
203 return(found ? 0 : retval);
204 }
205
206 int kill_proc(int pid, int sig, int priv)
207 {
208 struct task_struct **p;
209
210 if (sig<0 || sig>32)
211 return -EINVAL;
212 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
213 if (*p && (*p)->pid == pid)
214 return(sig ? send_sig(sig,*p,priv) : 0);
215 return(-ESRCH);
216 }
217
218
219
220
221
222 int sys_kill(int pid,int sig)
223 {
224 struct task_struct **p = NR_TASKS + task;
225 int err, retval = 0, count = 0;
226
227 if (!pid)
228 return(kill_pg(current->pgrp,sig,0));
229 if (pid == -1) {
230 while (--p > &FIRST_TASK)
231 if (*p && (*p)->pid > 1 && *p != current) {
232 ++count;
233 if ((err = send_sig(sig,*p,0)) != -EPERM)
234 retval = err;
235 }
236 return(count ? retval : -ESRCH);
237 }
238 if (pid < 0)
239 return(kill_pg(-pid,sig,0));
240
241 return(kill_proc(pid,sig,0));
242 }
243
244
245
246
247
248
249
250
251
252 int is_orphaned_pgrp(int pgrp)
253 {
254 struct task_struct **p;
255
256 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
257 if (!(*p) ||
258 ((*p)->pgrp != pgrp) ||
259 ((*p)->state == TASK_ZOMBIE) ||
260 ((*p)->p_pptr->pid == 1))
261 continue;
262 if (((*p)->p_pptr->pgrp != pgrp) &&
263 ((*p)->p_pptr->session == (*p)->session))
264 return 0;
265 }
266 return(1);
267 }
268
269 static int has_stopped_jobs(int pgrp)
270 {
271 struct task_struct ** p;
272
273 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
274 if (!*p || (*p)->pgrp != pgrp)
275 continue;
276 if ((*p)->state == TASK_STOPPED)
277 return(1);
278 }
279 return(0);
280 }
281
282 static void forget_original_parent(struct task_struct * father)
283 {
284 struct task_struct ** p;
285
286 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
287 if (*p && (*p)->p_opptr == father)
288 if (task[1])
289 (*p)->p_opptr = task[1];
290 else
291 (*p)->p_opptr = task[0];
292 }
293
294 volatile void do_exit(long code)
295 {
296 struct task_struct *p;
297 int i;
298
299 fake_volatile:
300 free_page_tables(get_base(current->ldt[1]),get_limit(0x0f));
301 free_page_tables(get_base(current->ldt[2]),get_limit(0x17));
302 for (i=0 ; i<NR_OPEN ; i++)
303 if (current->filp[i])
304 sys_close(i);
305 forget_original_parent(current);
306 iput(current->pwd);
307 current->pwd = NULL;
308 iput(current->root);
309 current->root = NULL;
310 iput(current->executable);
311 current->executable = NULL;
312 for (i=0; i < current->numlibraries; i++) {
313 iput(current->libraries[i].library);
314 current->libraries[i].library = NULL;
315 }
316 current->state = TASK_ZOMBIE;
317 current->exit_code = code;
318 current->rss = 0;
319
320
321
322
323
324
325
326
327
328 if ((current->p_pptr->pgrp != current->pgrp) &&
329 (current->p_pptr->session == current->session) &&
330 is_orphaned_pgrp(current->pgrp) &&
331 has_stopped_jobs(current->pgrp)) {
332 kill_pg(current->pgrp,SIGHUP,1);
333 kill_pg(current->pgrp,SIGCONT,1);
334 }
335
336 send_sig (SIGCHLD, current->p_pptr, 1);
337
338
339
340
341
342
343
344
345
346 while (p = current->p_cptr) {
347 current->p_cptr = p->p_osptr;
348 p->p_ysptr = NULL;
349 p->flags &= ~PF_PTRACED;
350 if (task[1])
351 p->p_pptr = task[1];
352 else
353 p->p_pptr = task[0];
354 p->p_osptr = p->p_pptr->p_cptr;
355 p->p_osptr->p_ysptr = p;
356 p->p_pptr->p_cptr = p;
357 if (p->state == TASK_ZOMBIE)
358 send_sig(SIGCHLD,p->p_pptr,1);
359
360
361
362
363
364
365 if ((p->pgrp != current->pgrp) &&
366 (p->session == current->session) &&
367 is_orphaned_pgrp(p->pgrp) &&
368 has_stopped_jobs(p->pgrp)) {
369 kill_pg(p->pgrp,SIGHUP,1);
370 kill_pg(p->pgrp,SIGCONT,1);
371 }
372 }
373 if (current->leader) {
374 struct task_struct **p;
375 struct tty_struct *tty;
376
377 if (current->tty >= 0) {
378 tty = TTY_TABLE(current->tty);
379 if (tty->pgrp > 0)
380 kill_pg(tty->pgrp, SIGHUP, 1);
381 tty->pgrp = -1;
382 tty->session = 0;
383 }
384 for (p = &LAST_TASK ; p > &FIRST_TASK ; --p)
385 if (*p && (*p)->session == current->session)
386 (*p)->tty = -1;
387 }
388 if (last_task_used_math == current)
389 last_task_used_math = NULL;
390 #ifdef DEBUG_PROC_TREE
391 audit_ptree();
392 #endif
393 schedule();
394
395
396
397
398
399
400
401
402
403
404
405
406
407 goto fake_volatile;
408 }
409
410 int sys_exit(int error_code)
411 {
412 do_exit((error_code&0xff)<<8);
413 }
414
415 int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options)
416 {
417 int flag;
418 struct task_struct *p;
419 unsigned long oldblocked;
420
421 if (stat_addr)
422 verify_area(stat_addr,4);
423 repeat:
424 current->signal &= ~(1<<(SIGCHLD-1));
425 flag=0;
426 for (p = current->p_cptr ; p ; p = p->p_osptr) {
427 if (pid>0) {
428 if (p->pid != pid)
429 continue;
430 } else if (!pid) {
431 if (p->pgrp != current->pgrp)
432 continue;
433 } else if (pid != -1) {
434 if (p->pgrp != -pid)
435 continue;
436 }
437 switch (p->state) {
438 case TASK_STOPPED:
439 if (!p->exit_code)
440 continue;
441 if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED))
442 continue;
443 if (stat_addr)
444 put_fs_long((p->exit_code << 8) | 0x7f,
445 stat_addr);
446 p->exit_code = 0;
447 return p->pid;
448 case TASK_ZOMBIE:
449 current->cutime += p->utime + p->cutime;
450 current->cstime += p->stime + p->cstime;
451 current->cmin_flt += p->min_flt + p->cmin_flt;
452 current->cmaj_flt += p->maj_flt + p->cmaj_flt;
453 flag = p->pid;
454 if (stat_addr)
455 put_fs_long(p->exit_code, stat_addr);
456 if (p->p_opptr != p->p_pptr) {
457 REMOVE_LINKS(p);
458 p->p_pptr = p->p_opptr;
459 SET_LINKS(p);
460 send_sig(SIGCHLD,p->p_pptr,1);
461 } else
462 release(p);
463 #ifdef DEBUG_PROC_TREE
464 audit_ptree();
465 #endif
466 return flag;
467 default:
468 flag=1;
469 continue;
470 }
471 }
472 if (flag) {
473 if (options & WNOHANG)
474 return 0;
475 current->state=TASK_INTERRUPTIBLE;
476 oldblocked = current->blocked;
477 current->blocked &= ~(1<<(SIGCHLD-1));
478 schedule();
479 current->blocked = oldblocked;
480 if (current->signal & ~(current->blocked | (1<<(SIGCHLD-1))))
481 return -ERESTARTSYS;
482 else
483 goto repeat;
484 }
485 return -ECHILD;
486 }