You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
7.2 KiB

/*
* 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;
}