?? signal.c
字號:
/** linux/kernel/signal.c** (C) 1991 Linus Torvalds*/#include <linux/sched.h> // 調度程序頭文件,定義了任務結構task_struct、初始任務0 的數據,// 還有一些有關描述符參數設置和獲取的嵌入式匯編函數宏語句。#include <linux/kernel.h> // 內核頭文件。含有一些內核常用函數的原形定義。#include <asm/segment.h> // 段操作頭文件。定義了有關段寄存器操作的嵌入式匯編函數。#include <signal.h> // 信號頭文件。定義信號符號常量,信號結構以及信號操作函數原型。volatile void do_exit (int error_code); // 前面的限定符volatile 要求編譯器不要對其進行優化。// 獲取當前任務信號屏蔽位圖(屏蔽碼)。intsys_sgetmask (){ return current->blocked;}// 設置新的信號屏蔽位圖。SIGKILL 不能被屏蔽。返回值是原信號屏蔽位圖。intsys_ssetmask (int newmask){ int old = current->blocked; current->blocked = newmask & ~(1 << (SIGKILL - 1)); return old;}// 復制sigaction 數據到fs 數據段to 處。。static inline voidsave_old (char *from, char *to){ int i; verify_area (to, sizeof (struct sigaction)); // 驗證to 處的內存是否足夠。 for (i = 0; i < sizeof (struct sigaction); i++) { put_fs_byte (*from, to); // 復制到fs 段。一般是用戶數據段。 from++; // put_fs_byte()在include/asm/segment.h 中。 to++; }}// 把sigaction 數據從fs 數據段from 位置復制到to 處。static inline voidget_new (char *from, char *to){ int i; for (i = 0; i < sizeof (struct sigaction); i++) *(to++) = get_fs_byte (from++);}// signal()系統調用。類似于sigaction()。為指定的信號安裝新的信號句柄(信號處理程序)。// 信號句柄可以是用戶指定的函數,也可以是SIG_DFL(默認句柄)或SIG_IGN(忽略)。// 參數signum --指定的信號;handler -- 指定的句柄;restorer –原程序當前執行的地址位置。// 函數返回原信號句柄。intsys_signal (int signum, long handler, long restorer){ struct sigaction tmp; if (signum < 1 || signum > 32 || signum == SIGKILL) // 信號值要在(1-32)范圍內, return -1; // 并且不得是SIGKILL。 tmp.sa_handler = (void (*)(int)) handler; // 指定的信號處理句柄。 tmp.sa_mask = 0; // 執行時的信號屏蔽碼。 tmp.sa_flags = SA_ONESHOT | SA_NOMASK; // 該句柄只使用1 次后就恢復到默認值,// 并允許信號在自己的處理句柄中收到。 tmp.sa_restorer = (void (*)(void)) restorer; // 保存返回地址。 handler = (long) current->sigaction[signum - 1].sa_handler; current->sigaction[signum - 1] = tmp; return handler;}// sigaction()系統調用。改變進程在收到一個信號時的操作。signum 是除了SIGKILL 以外的任何// 信號。[如果新操作(action)不為空]則新操作被安裝。如果oldaction 指針不為空,則原操作// 被保留到oldaction。成功則返回0,否則為-1。intsys_sigaction (int signum, const struct sigaction *action, struct sigaction *oldaction){ struct sigaction tmp;// 信號值要在(1-32)范圍內,并且信號SIGKILL 的處理句柄不能被改變。 if (signum < 1 || signum > 32 || signum == SIGKILL) return -1;// 在信號的sigaction 結構中設置新的操作(動作)。 tmp = current->sigaction[signum - 1]; get_new ((char *) action, (char *) (signum - 1 + current->sigaction));// 如果oldaction 指針不為空的話,則將原操作指針保存到oldaction 所指的位置。 if (oldaction) save_old ((char *) &tmp, (char *) oldaction);// 如果允許信號在自己的信號句柄中收到,則令屏蔽碼為0,否則設置屏蔽本信號。 if (current->sigaction[signum - 1].sa_flags & SA_NOMASK) current->sigaction[signum - 1].sa_mask = 0; else current->sigaction[signum - 1].sa_mask |= (1 << (signum - 1)); return 0;}// 系統調用中斷處理程序中真正的信號處理程序(在kernel/system_call.s,119 行)。// 該段代碼的主要作用是將信號的處理句柄插入到用戶程序堆棧中,并在本系統調用結束// 返回后立刻執行信號句柄程序,然后繼續執行用戶的程序。voiddo_signal (long signr, long eax, long ebx, long ecx, long edx, long fs, long es, long ds, long eip, long cs, long eflags, unsigned long *esp, long ss){ unsigned long sa_handler; long old_eip = eip; struct sigaction *sa = current->sigaction + signr - 1; //current->sigaction[signu-1]。 int longs; unsigned long *tmp_esp; sa_handler = (unsigned long) sa->sa_handler;// 如果信號句柄為SIG_IGN(忽略),則返回;如果句柄為SIG_DFL(默認處理),則如果信號是// SIGCHLD 則返回,否則終止進程的執行 if (sa_handler == 1) return; if (!sa_handler) { if (signr == SIGCHLD) return; else do_exit (1 << (signr - 1)); // [?? 為什么以信號位圖為參數?不為什么!??]// 這里應該是do_exit(1<<signr))。 }// 如果該信號句柄只需使用一次,則將該句柄置空(該信號句柄已經保存在sa_handler 指針中)。 if (sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL;// 下面這段代碼將信號處理句柄插入到用戶堆棧中,同時也將sa_restorer,signr,進程屏蔽碼(如果// SA_NOMASK 沒置位),eax,ecx,edx 作為參數以及原調用系統調用的程序返回指針及標志寄存器值// 壓入堆棧。因此在本次系統調用中斷(0x80)返回用戶程序時會首先執行用戶的信號句柄程序,然后// 再繼續執行用戶程序。// 將用戶調用系統調用的代碼指針eip 指向該信號處理句柄。 *(&eip) = sa_handler;// 如果允許信號自己的處理句柄收到信號自己,則也需要將進程的阻塞碼壓入堆棧。 longs = (sa->sa_flags & SA_NOMASK) ? 7 : 8;// 將原調用程序的用戶的堆棧指針向下擴展7(或8)個長字(用來存放調用信號句柄的參數等),// 并檢查內存使用情況(例如如果內存超界則分配新頁等)。 *(&esp) -= longs; verify_area (esp, longs * 4);// 在用戶堆棧中從下到上存放sa_restorer, 信號signr, 屏蔽碼blocked(如果SA_NOMASK 置位),// eax, ecx, edx, eflags 和用戶程序原代碼指針。 tmp_esp = esp; put_fs_long ((long) sa->sa_restorer, tmp_esp++); put_fs_long (signr, tmp_esp++); if (!(sa->sa_flags & SA_NOMASK)) put_fs_long (current->blocked, tmp_esp++); put_fs_long (eax, tmp_esp++); put_fs_long (ecx, tmp_esp++); put_fs_long (edx, tmp_esp++); put_fs_long (eflags, tmp_esp++); put_fs_long (old_eip, tmp_esp++); current->blocked |= sa->sa_mask; // 進程阻塞碼(屏蔽碼)添上sa_mask 中的碼位。}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -