?? exit.c
字號:
/** linux/kernel/exit.c** (C) 1991 Linus Torvalds*/#include <errno.h> // 錯誤號頭文件。包含系統中各種出錯號。(Linus 從minix 中引進的)#include <signal.h> // 信號頭文件。定義信號符號常量,信號結構以及信號操作函數原型。#include <sys/wait.h> // 等待調用頭文件。定義系統調用wait()和waitpid()及相關常數符號。#include <linux/sched.h> // 調度程序頭文件,定義了任務結構task_struct、初始任務0 的數據,// 還有一些有關描述符參數設置和獲取的嵌入式匯編函數宏語句。#include <linux/kernel.h> // 內核頭文件。含有一些內核常用函數的原形定義。#include <linux/tty.h> // tty 頭文件,定義了有關tty_io,串行通信方面的參數、常數。#include <asm/segment.h> // 段操作頭文件。定義了有關段寄存器操作的嵌入式匯編函數。int sys_pause (void);int sys_close (int fd);//// 釋放指定進程(任務)。voidrelease (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"); // 指定任務若不存在則死機。}//// 向指定任務(*p)發送信號(sig),權限為priv。static inline intsend_sig (long sig, struct task_struct *p, int priv){// 若信號不正確或任務指針為空則出錯退出。 if (!p || sig < 1 || sig > 32) return -EINVAL;// 若有權或進程有效用戶標識符(euid)就是指定進程的euid 或者是超級用戶,則在進程位圖中添加// 該信號,否則出錯退出。其中suser()定義為(current->euid==0),用于判斷是否超級用戶。 if (priv || (current->euid == p->euid) || suser ()) p->signal |= (1 << (sig - 1)); else return -EPERM; return 0;}//// 終止會話(session)。static void{ struct task_struct **p = NR_TASKS + task; // 指針*p 首先指向任務數組最末端。// 對于所有的任務(除任務0 以外),如果其會話等于當前進程的會話就向它發送掛斷進程信號。 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!*//** 為了向進程組等發送信號,XXX 需要檢查許可。kill()的許可機制非常巧妙!*///// kill()系統調用可用于向任何進程或進程組發送任何信號。// 如果pid 值>0,則信號被發送給pid。// 如果pid=0,那么信號就會被發送給當前進程的進程組中的所有進程。// 如果pid=-1,則信號sig 就會發送給除第一個進程外的所有進程。// 如果pid < -1,則信號sig 將發送給進程組-pid 的所有進程。// 如果信號sig 為0,則不發送信號,但仍會進行錯誤檢查。如果成功則返回0。intsys_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;}//// 通知父進程 -- 向進程pid 發送信號SIGCHLD:子進程將停止或終止。// 如果沒有找到父進程,則自己釋放。static voidtell_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); // 如果沒有找到父進程,則自己釋放。}//// 程序退出處理程序。在系統調用的中斷處理程序中被調用。intdo_exit (long code) // code 是錯誤碼。{ int i;// 釋放當前進程代碼段和數據段所占的內存頁(free_page_tables()在mm/memory.c,105 行)。 free_page_tables (get_base (current->ldt[1]), get_limit (0x0f)); free_page_tables (get_base (current->ldt[2]), get_limit (0x17));// 如果當前進程有子進程,就將子進程的father 置為1(其父進程改為進程1)。如果該子進程已經// 處于僵死(ZOMBIE)狀態,則向進程1 發送子進程終止信號SIGCHLD。 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);// 對當前進程工作目錄pwd、根目錄root 以及運行程序的i 節點進行同步操作,并分別置空。 iput (current->pwd); current->pwd = NULL; iput (current->root); current->root = NULL; iput (current->executable); current->executable = NULL;// 如果當前進程是領頭(leader)進程并且其有控制的終端,則釋放該終端。 if (current->leader && current->tty >= 0) tty_table[current->tty].pgrp = 0;// 如果當前進程上次使用過協處理器,則將last_task_used_math 置空。 if (last_task_used_math == current) last_task_used_math = NULL;// 如果當前進程是leader 進程,則終止所有相關進程。 if (current->leader) kill_session ();// 把當前進程置為僵死狀態,并設置退出碼。 current->state = TASK_ZOMBIE; current->exit_code = code;// 通知父進程,也即向父進程發送信號SIGCHLD -- 子進程將停止或終止。 tell_father (current->father); schedule (); // 重新調度進程的運行。 return (-1); /* just to suppress warnings */}//// 系統調用exit()。終止進程。intsys_exit (int error_code){ return do_exit ((error_code & 0xff) << 8);}//// 系統調用waitpid()。掛起當前進程,直到pid 指定的子進程退出(終止)或者收到要求終止// 該進程的信號,或者是需要調用一個信號句柄(信號處理程序)。如果pid 所指的子進程早已// 退出(已成所謂的僵死進程),則本調用將立刻返回。子進程使用的所有資源將釋放。// 如果pid > 0, 表示等待進程號等于pid 的子進程。// 如果pid = 0, 表示等待進程組號等于當前進程的任何子進程。// 如果pid < -1, 表示等待進程組號等于pid 絕對值的任何子進程。// [ 如果pid = -1, 表示等待任何子進程。]// 若options = WUNTRACED,表示如果子進程是停止的,也馬上返回。// 若options = WNOHANG,表示如果沒有子進程退出或終止就馬上返回。// 如果stat_addr 不為空,則就將狀態信息保存到那里。intsys_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) { // 如果指定的pid>0,但掃描的進程pid if ((*p)->pid != pid) // 與之不等,則跳過。 continue; } else if (!pid) { // 如果指定的pid=0,但掃描的進程組號 if ((*p)->pgrp != current->pgrp) // 與當前進程的組號不等,則跳過。 continue; } else if (pid != -1) { // 如果指定的pid<-1,但掃描的進程組 號if ((*p)->pgrp != -pid) // 與其絕對值不等,則跳過。 continue; } switch ((*p)->state) { case TASK_STOPPED: if (!(options & WUNTRACED)) continue; put_fs_long (0x7f, stat_addr); // 置狀態信息為0x7f。 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; // 退出,返回子進程的pid. default: flag = 1; // 如果子進程不在停止或僵死狀態,則flag=1。 continue; } } if (flag) { // 如果子進程沒有處于退出或僵死狀態, if (options & WNOHANG) // 并且options = WNOHANG,則立刻返回。 return 0; current->state = TASK_INTERRUPTIBLE; // 置當前進程為可中斷等待狀態。 schedule (); // 重新調度。 if (!(current->signal &= ~(1 << (SIGCHLD - 1)))) // 又開始執行本進程時, goto repeat; // 如果進程沒有收到除SIGCHLD 的信號,則還是重復處理。 else return -EINTR; // 退出,返回出錯碼。 } return -ECHILD;}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -