version 1.1.1.1, 2018/04/24 18:00:41
|
version 1.1.1.2, 2018/04/24 18:01:35
|
Line 1
|
Line 1
|
|
/* |
|
* linux/kernel/exit.c |
|
* |
|
* (C) 1991 Linus Torvalds |
|
*/ |
|
|
#include <errno.h> |
#include <errno.h> |
#include <signal.h> |
#include <signal.h> |
#include <sys/wait.h> |
#include <sys/wait.h> |
Line 26 void release(struct task_struct * p)
|
Line 32 void release(struct task_struct * p)
|
panic("trying to release non-existent task"); |
panic("trying to release non-existent task"); |
} |
} |
|
|
static inline void send_sig(long sig,struct task_struct * p,int priv) |
static inline int send_sig(long sig,struct task_struct * p,int priv) |
{ |
{ |
if (!p || sig<1 || sig>32) |
if (!p || sig<1 || sig>32) |
return; |
return -EINVAL; |
if (priv || |
if (priv || (current->euid==p->euid) || suser()) |
current->uid==p->uid || |
|
current->euid==p->uid || |
|
current->uid==p->euid || |
|
current->euid==p->euid) |
|
p->signal |= (1<<(sig-1)); |
p->signal |= (1<<(sig-1)); |
|
else |
|
return -EPERM; |
|
return 0; |
} |
} |
|
|
void do_kill(long pid,long sig,int priv) |
static void kill_session(void) |
|
{ |
|
struct task_struct **p = NR_TASKS + task; |
|
|
|
while (--p > &FIRST_TASK) { |
|
if (*p && (*p)->session == current->session) |
|
(*p)->signal |= 1<<(SIGHUP-1); |
|
} |
|
} |
|
|
|
/* |
|
* XXX need to check permissions needed to send signals to process |
|
* groups, etc. etc. kill() permissions semantics are tricky! |
|
*/ |
|
int sys_kill(int pid,int sig) |
{ |
{ |
struct task_struct **p = NR_TASKS + task; |
struct task_struct **p = NR_TASKS + task; |
|
int err, retval = 0; |
|
|
if (!pid) while (--p > &FIRST_TASK) { |
if (!pid) while (--p > &FIRST_TASK) { |
if (*p && (*p)->pgrp == current->pid) |
if (*p && (*p)->pgrp == current->pid) |
send_sig(sig,*p,priv); |
if (err=send_sig(sig,*p,1)) |
|
retval = err; |
} else if (pid>0) while (--p > &FIRST_TASK) { |
} else if (pid>0) while (--p > &FIRST_TASK) { |
if (*p && (*p)->pid == pid) |
if (*p && (*p)->pid == pid) |
send_sig(sig,*p,priv); |
if (err=send_sig(sig,*p,0)) |
|
retval = err; |
} else if (pid == -1) while (--p > &FIRST_TASK) |
} else if (pid == -1) while (--p > &FIRST_TASK) |
send_sig(sig,*p,priv); |
if (err = send_sig(sig,*p,0)) |
|
retval = err; |
else while (--p > &FIRST_TASK) |
else while (--p > &FIRST_TASK) |
if (*p && (*p)->pgrp == -pid) |
if (*p && (*p)->pgrp == -pid) |
send_sig(sig,*p,priv); |
if (err = send_sig(sig,*p,0)) |
|
retval = err; |
|
return retval; |
} |
} |
|
|
int sys_kill(int pid,int sig) |
static void tell_father(int pid) |
{ |
{ |
do_kill(pid,sig,!(current->uid || current->euid)); |
int i; |
return 0; |
|
|
if (pid) |
|
for (i=0;i<NR_TASKS;i++) { |
|
if (!task[i]) |
|
continue; |
|
if (task[i]->pid != pid) |
|
continue; |
|
task[i]->signal |= (1<<(SIGCHLD-1)); |
|
return; |
|
} |
|
/* if we don't find any fathers, we just release ourselves */ |
|
release(current); |
} |
} |
|
|
int do_exit(long code) |
int do_exit(long code) |
Line 81 int do_exit(long code)
|
Line 117 int do_exit(long code)
|
tty_table[current->tty].pgrp = 0; |
tty_table[current->tty].pgrp = 0; |
if (last_task_used_math == current) |
if (last_task_used_math == current) |
last_task_used_math = NULL; |
last_task_used_math = NULL; |
if (current->father) { |
if (current->leader) |
current->state = TASK_ZOMBIE; |
kill_session(); |
do_kill(current->father,SIGCHLD,1); |
current->state = TASK_ZOMBIE; |
current->exit_code = code; |
current->exit_code = code; |
} else |
tell_father(current->father); |
release(current); |
|
schedule(); |
schedule(); |
return (-1); /* just to suppress warnings */ |
return (-1); /* just to suppress warnings */ |
} |
} |
Line 96 int sys_exit(int error_code)
|
Line 131 int sys_exit(int error_code)
|
return do_exit((error_code&0xff)<<8); |
return do_exit((error_code&0xff)<<8); |
} |
} |
|
|
int sys_waitpid(pid_t pid,int * stat_addr, int options) |
int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options) |
{ |
{ |
int flag=0; |
int flag; |
struct task_struct ** p; |
struct task_struct ** p; |
|
|
verify_area(stat_addr,4); |
verify_area(stat_addr,4); |
repeat: |
repeat: |
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) |
flag=0; |
if (*p && *p != current && |
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) { |
(pid==-1 || (*p)->pid==pid || |
if (!*p || *p == current) |
(pid==0 && (*p)->pgrp==current->pgrp) || |
continue; |
(pid<0 && (*p)->pgrp==-pid))) |
if ((*p)->father != current->pid) |
if ((*p)->father == current->pid) { |
continue; |
|
if (pid>0) { |
|
if ((*p)->pid != pid) |
|
continue; |
|
} else if (!pid) { |
|
if ((*p)->pgrp != current->pgrp) |
|
continue; |
|
} else if (pid != -1) { |
|
if ((*p)->pgrp != -pid) |
|
continue; |
|
} |
|
switch ((*p)->state) { |
|
case TASK_STOPPED: |
|
if (!(options & WUNTRACED)) |
|
continue; |
|
put_fs_long(0x7f,stat_addr); |
|
return (*p)->pid; |
|
case TASK_ZOMBIE: |
|
current->cutime += (*p)->utime; |
|
current->cstime += (*p)->stime; |
|
flag = (*p)->pid; |
|
put_fs_long((*p)->exit_code,stat_addr); |
|
release(*p); |
|
return flag; |
|
default: |
flag=1; |
flag=1; |
if ((*p)->state==TASK_ZOMBIE) { |
continue; |
put_fs_long((*p)->exit_code, |
} |
(unsigned long *) stat_addr); |
} |
current->cutime += (*p)->utime; |
|
current->cstime += (*p)->stime; |
|
flag = (*p)->pid; |
|
release(*p); |
|
return flag; |
|
} |
|
} |
|
if (flag) { |
if (flag) { |
if (options & WNOHANG) |
if (options & WNOHANG) |
return 0; |
return 0; |
sys_pause(); |
current->state=TASK_INTERRUPTIBLE; |
|
schedule(); |
if (!(current->signal &= ~(1<<(SIGCHLD-1)))) |
if (!(current->signal &= ~(1<<(SIGCHLD-1)))) |
goto repeat; |
goto repeat; |
else |
else |