diff options
Diffstat (limited to 'linux/kernel/exit.c')
| -rw-r--r-- | linux/kernel/exit.c | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/linux/kernel/exit.c b/linux/kernel/exit.c new file mode 100644 index 0000000..3402c33 --- /dev/null +++ b/linux/kernel/exit.c @@ -0,0 +1,135 @@ +#include <errno.h> +#include <signal.h> +#include <sys/wait.h> + +#include <linux/sched.h> +#include <linux/kernel.h> +#include <linux/tty.h> +#include <asm/segment.h> + +int sys_pause(void); +int sys_close(int fd); + +void release(struct task_struct * p) +{ + int i; + + if (!p) + return; + for (i=1 ; i<NR_TASKS ; i++) + if (task[i]==p) { + task[i]=NULL; + free_page((long)p); + schedule(); + return; + } + panic("trying to release non-existent task"); +} + +static inline void send_sig(long sig,struct task_struct * p,int priv) +{ + if (!p || sig<1 || sig>32) + return; + if (priv || + current->uid==p->uid || + current->euid==p->uid || + current->uid==p->euid || + current->euid==p->euid) + p->signal |= (1<<(sig-1)); +} + +void do_kill(long pid,long sig,int priv) +{ + struct task_struct **p = NR_TASKS + task; + + if (!pid) while (--p > &FIRST_TASK) { + if (*p && (*p)->pgrp == current->pid) + send_sig(sig,*p,priv); + } else if (pid>0) while (--p > &FIRST_TASK) { + if (*p && (*p)->pid == pid) + send_sig(sig,*p,priv); + } else if (pid == -1) while (--p > &FIRST_TASK) + send_sig(sig,*p,priv); + else while (--p > &FIRST_TASK) + if (*p && (*p)->pgrp == -pid) + send_sig(sig,*p,priv); +} + +int sys_kill(int pid,int sig) +{ + do_kill(pid,sig,!(current->uid || current->euid)); + return 0; +} + +int do_exit(long code) +{ + int i; + + free_page_tables(get_base(current->ldt[1]),get_limit(0x0f)); + free_page_tables(get_base(current->ldt[2]),get_limit(0x17)); + for (i=0 ; i<NR_TASKS ; i++) + if (task[i] && task[i]->father == current->pid) + task[i]->father = 0; + for (i=0 ; i<NR_OPEN ; i++) + if (current->filp[i]) + sys_close(i); + iput(current->pwd); + current->pwd=NULL; + iput(current->root); + current->root=NULL; + if (current->leader && current->tty >= 0) + tty_table[current->tty].pgrp = 0; + if (last_task_used_math == current) + last_task_used_math = NULL; + if (current->father) { + current->state = TASK_ZOMBIE; + do_kill(current->father,SIGCHLD,1); + current->exit_code = code; + } else + release(current); + schedule(); + return (-1); /* just to suppress warnings */ +} + +int sys_exit(int error_code) +{ + return do_exit((error_code&0xff)<<8); +} + +int sys_waitpid(pid_t pid,int * stat_addr, int options) +{ + int flag=0; + struct task_struct ** p; + + verify_area(stat_addr,4); +repeat: + for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) + if (*p && *p != current && + (pid==-1 || (*p)->pid==pid || + (pid==0 && (*p)->pgrp==current->pgrp) || + (pid<0 && (*p)->pgrp==-pid))) + if ((*p)->father == current->pid) { + flag=1; + if ((*p)->state==TASK_ZOMBIE) { + 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 (options & WNOHANG) + return 0; + sys_pause(); + if (!(current->signal &= ~(1<<(SIGCHLD-1)))) + goto repeat; + else + return -EINTR; + } + return -ECHILD; +} + + |
