diff --git a/exit.c(detailed) b/exit.c(detailed) new file mode 100644 index 0000000..200167e --- /dev/null +++ b/exit.c(detailed) @@ -0,0 +1,290 @@ +/* + * linux/kernel/exit.c + * + * (C) 1991 Linus Torvalds + */ + +#include +#include +#include + +#include +#include +#include +#include +#include // + +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) /* ϵͳ����thread_exitʵ�ֺ������ο���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; /* ��ǰ�߳�ID */ + thread_value[thread] = value_ptr; /* �������̵߳ķ���ֵ��¼��thread_value������ */ + /*********************************************/ + tell_father(current->father); + schedule(); + return (-1); +} + +int sys_thread_join(pthread_t thread, void** value_ptr) /* ϵͳ����thread_exitʵ�ֺ������ο���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; + /* ����������ĩ�˿�ʼɨ��������������������������Լ��ǵ�ǰ�̵߳����߳��� */ + for (p = &LAST_TASK; p > &FIRST_TASK; --p) + { + if (!*p || *p == current) continue; + if ((*p)->father != current->pid) continue; + /****************************************/ + if ((*p)->pid != thread) continue; + /****************************************/ + /* ��ʱ�ҵ���p���ǵ�ǰ�̵߳����߳� */ + 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); /* ��thread_value�����е�ֵ���� value_ptr��Ҳ���ǽ�����thread_exit�����ķ���ֵ */ + /****************************************/ /* ��˸��̵߳���sys_thread_join�������ܻ�ȡ���ֵ */ + return 0; + default: + flag = 1; + break; + } + } + /* flag=1˵���з��ϵȴ�Ҫ������̣߳�����������ֹ����״̬����ʱ�ѵ�ǰ�߳���Ϊ���жϵȴ�״̬�����µ��ȣ��ظ�ִ�� */ + if (flag) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (!(current->signal &= ~(1 << (SIGCHLD - 1)))) + goto repeat; + else + return -EINTR; + } + return -ECHILD; +} +