parent
32a8680895
commit
c63e828e6f
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* linux/kernel/exit.c
|
||||
*
|
||||
* (C) 1991 Linus Torvalds
|
||||
*/
|
||||
|
||||
#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 int send_sig(long sig,struct task_struct * p,int priv)
|
||||
{
|
||||
if (!p || sig<1 || sig>32)
|
||||
return -EINVAL;
|
||||
if (priv || (current->euid==p->euid) || suser())
|
||||
p->signal |= (1<<(sig-1));
|
||||
else
|
||||
return -EPERM;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
int err, retval = 0;
|
||||
|
||||
if (!pid) while (--p > &FIRST_TASK) {
|
||||
if (*p && (*p)->pgrp == current->pid)
|
||||
if (err=send_sig(sig,*p,1))
|
||||
retval = err;
|
||||
} else if (pid>0) while (--p > &FIRST_TASK) {
|
||||
if (*p && (*p)->pid == pid)
|
||||
if (err=send_sig(sig,*p,0))
|
||||
retval = err;
|
||||
} else if (pid == -1) while (--p > &FIRST_TASK)
|
||||
if (err = send_sig(sig,*p,0))
|
||||
retval = err;
|
||||
else while (--p > &FIRST_TASK)
|
||||
if (*p && (*p)->pgrp == -pid)
|
||||
if (err = send_sig(sig,*p,0))
|
||||
retval = err;
|
||||
return retval;
|
||||
}
|
||||
|
||||
static void tell_father(int pid)
|
||||
{
|
||||
int i;
|
||||
|
||||
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 */
|
||||
/* This is not really OK. Must change it to make father 1 */
|
||||
printk("BAD BAD - no father found\n\r");
|
||||
release(current);
|
||||
}
|
||||
|
||||
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 = 1;
|
||||
if (task[i]->state == TASK_ZOMBIE)
|
||||
/* assumption task[1] is always init */
|
||||
(void) send_sig(SIGCHLD, task[1], 1);
|
||||
}
|
||||
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;
|
||||
iput(current->executable);
|
||||
current->executable=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->leader)
|
||||
kill_session();
|
||||
current->state = TASK_ZOMBIE;
|
||||
current->exit_code = code;
|
||||
tell_father(current->father);
|
||||
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,unsigned long * stat_addr, int options)
|
||||
{
|
||||
int flag, code;
|
||||
struct task_struct ** p;
|
||||
|
||||
verify_area(stat_addr,4);
|
||||
repeat:
|
||||
flag=0;
|
||||
for(p = &LAST_TASK ; p > &FIRST_TASK ; --p) {
|
||||
if (!*p || *p == current)
|
||||
continue;
|
||||
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;
|
||||
code = (*p)->exit_code;
|
||||
release(*p);
|
||||
put_fs_long(code,stat_addr);
|
||||
return flag;
|
||||
default:
|
||||
flag=1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
if (options & WNOHANG)
|
||||
return 0;
|
||||
current->state=TASK_INTERRUPTIBLE;
|
||||
schedule();
|
||||
if (!(current->signal &= ~(1<<(SIGCHLD-1))))
|
||||
goto repeat;
|
||||
else
|
||||
return -EINTR;
|
||||
}
|
||||
return -ECHILD;
|
||||
}
|
||||
|
||||
//new
|
||||
int sys_syspthread_join(int thread, long* value_ptr)
|
||||
{
|
||||
int flag, code;
|
||||
struct task_struct** p;
|
||||
|
||||
verify_area(value_ptr, 4);
|
||||
repeat:
|
||||
flag = 0;
|
||||
for (p = &LAST_TASK; p > &FIRST_TASK; --p) {
|
||||
if (!*p || *p == current)
|
||||
continue;
|
||||
if ((*p)->father != current->pid)
|
||||
continue;
|
||||
if (thread > 0) {
|
||||
if ((*p)->pid != thread)
|
||||
continue;
|
||||
}
|
||||
else if (!thread) {
|
||||
if ((*p)->pgrp != current->pgrp)
|
||||
continue;
|
||||
}
|
||||
else if (thread != -1) {
|
||||
if ((*p)->pgrp != -thread)
|
||||
continue;
|
||||
}
|
||||
switch ((*p)->state) {
|
||||
case TASK_STOPPED:
|
||||
if (!WUNTRACED)
|
||||
continue;
|
||||
put_fs_long(0x7f, value_ptr);
|
||||
return (*p)->pid;
|
||||
case TASK_ZOMBIE:
|
||||
current->cutime += (*p)->utime;
|
||||
current->cstime += (*p)->stime;
|
||||
flag = (*p)->pid;
|
||||
code = (*p)->exit_code;
|
||||
release(*p);
|
||||
put_fs_long(code, value_ptr);
|
||||
return flag;
|
||||
default:
|
||||
flag = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (flag) {
|
||||
current->state = TASK_INTERRUPTIBLE;
|
||||
schedule();
|
||||
if (!(current->signal &= ~(1 << (SIGCHLD - 1))))
|
||||
goto repeat;
|
||||
else
|
||||
return -EINTR;
|
||||
}
|
||||
return -ECHILD;
|
||||
}
|
||||
|
||||
int sys_endthread(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 = 1;
|
||||
if (task[i]->state == TASK_ZOMBIE)
|
||||
/* assumption task[1] is always init */
|
||||
(void)send_sig(SIGCHLD, task[1], 1);
|
||||
}
|
||||
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;
|
||||
iput(current->executable);
|
||||
current->executable = 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->leader)
|
||||
kill_session();
|
||||
current->state = TASK_ZOMBIE;
|
||||
current->exit_code = code;
|
||||
tell_father(current->father);
|
||||
release(current);
|
||||
return (-1); /* just to suppress warnings */
|
||||
}
|
||||
|
Loading…
Reference in new issue