|
|
/*
|
|
|
* 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>
|
|
|
#include <unistd.h>//
|
|
|
|
|
|
int sys_pause(void);
|
|
|
int sys_close(int fd);
|
|
|
|
|
|
void* thread_value[4096] = {};//
|
|
|
|
|
|
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;
|
|
|
}
|
|
|
|
|
|
int sys_thread_exit(void* value_ptr) /* ϵͳ<CFB5><CDB3><EFBFBD><EFBFBD>thread_exitʵ<74>ֺ<EFBFBD><D6BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ο<EFBFBD><CEBF><EFBFBD>do_exit */
|
|
|
{
|
|
|
int i;
|
|
|
pthread_t thread;
|
|
|
|
|
|
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;
|
|
|
/*********************************************/
|
|
|
thread = current->pid; /* <20><>ǰ<EFBFBD>߳<EFBFBD>ID */
|
|
|
thread_value[thread] = value_ptr; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̵߳ķ<CCB5><C4B7><EFBFBD>ֵ<EFBFBD><D6B5>¼<EFBFBD><C2BC>thread_value<75><65><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|
|
/*********************************************/
|
|
|
tell_father(current->father);
|
|
|
schedule();
|
|
|
return (-1);
|
|
|
}
|
|
|
|
|
|
int sys_thread_join(pthread_t thread, void** value_ptr) /* ϵͳ<CFB5><CDB3><EFBFBD><EFBFBD>thread_exitʵ<74>ֺ<EFBFBD><D6BA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ο<EFBFBD><CEBF><EFBFBD>wait_pid */
|
|
|
{
|
|
|
if (thread <= 0 || value_ptr == NULL)
|
|
|
{
|
|
|
printk("Error:thread joining failed!\n");
|
|
|
sys_exit(0);
|
|
|
}
|
|
|
int flag;
|
|
|
struct task_struct** p;
|
|
|
repeat:
|
|
|
flag = 0;
|
|
|
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ĩ<EFBFBD>˿<EFBFBD>ʼɨ<CABC><C9A8><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EEA1A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Լ<EFBFBD><D4BC>ǵ<EFBFBD>ǰ<EFBFBD>̵߳<DFB3><CCB5><EFBFBD><EFBFBD>߳<EFBFBD><DFB3><EFBFBD> */
|
|
|
for (p = &LAST_TASK; p > &FIRST_TASK; --p)
|
|
|
{
|
|
|
if (!*p || *p == current) continue;
|
|
|
if ((*p)->father != current->pid) continue;
|
|
|
/****************************************/
|
|
|
if ((*p)->pid != thread) continue;
|
|
|
/****************************************/
|
|
|
/* <20><>ʱ<EFBFBD>ҵ<EFBFBD><D2B5><EFBFBD>p<EFBFBD><70><EFBFBD>ǵ<EFBFBD>ǰ<EFBFBD>̵߳<DFB3><CCB5><EFBFBD><EFBFBD>߳<EFBFBD> */
|
|
|
switch ((*p)->state)
|
|
|
{
|
|
|
case TASK_STOPPED:
|
|
|
break;
|
|
|
case TASK_ZOMBIE:
|
|
|
current->cutime += (*p)->utime;
|
|
|
current->cstime += (*p)->stime;
|
|
|
release(*p);
|
|
|
/****************************************/
|
|
|
put_fs_long(thread_value[thread], value_ptr); /* <20><>thread_value<75><65><EFBFBD><EFBFBD><EFBFBD>е<EFBFBD>ֵ<EFBFBD><D6B5><EFBFBD><EFBFBD> value_ptr<74><72>Ҳ<EFBFBD><D2B2><EFBFBD>ǽ<EFBFBD><C7BD><EFBFBD><EFBFBD><EFBFBD>thread_exit<69><74><EFBFBD><EFBFBD><EFBFBD>ķ<EFBFBD><C4B7><EFBFBD>ֵ */
|
|
|
/****************************************/ /* <20><>˸<EFBFBD><CBB8>̵߳<DFB3><CCB5><EFBFBD>sys_thread_join<69><6E><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܻ<EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD>ֵ */
|
|
|
return 0;
|
|
|
default:
|
|
|
flag = 1;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
/* flag=1˵<31><CBB5><EFBFBD>з<EFBFBD><D0B7>ϵȴ<CFB5>Ҫ<EFBFBD><D2AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>̣߳<DFB3><CCA3><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֹ<EFBFBD><D6B9><EFBFBD><EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD>ʱ<EFBFBD>ѵ<EFBFBD>ǰ<EFBFBD>߳<EFBFBD><DFB3><EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>жϵȴ<CFB5>״̬<D7B4><CCAC><EFBFBD><EFBFBD><EFBFBD>µ<EFBFBD><C2B5>ȣ<EFBFBD><C8A3>ظ<EFBFBD>ִ<EFBFBD><D6B4> */
|
|
|
if (flag) {
|
|
|
current->state = TASK_INTERRUPTIBLE;
|
|
|
schedule();
|
|
|
if (!(current->signal &= ~(1 << (SIGCHLD - 1))))
|
|
|
goto repeat;
|
|
|
else
|
|
|
return -EINTR;
|
|
|
}
|
|
|
return -ECHILD;
|
|
|
}
|
|
|
|