46 * the current mask in old_mask and block until a signal comes in. 47 */ /* 自动地更换成新的信号屏蔽码, 并等待信号的到来 * * 我们需要对系统调用 (syscall) 做一些处理 我们会从系统调用库接口取得某些信息

Similar documents
ebook15-10

36 asm ("mov %%fs,%%ax":"=a" ( res):); \ 37 res;}) 38 // 以下定义了一些函数原型 39 void page_exception(void); // 页异常 实际是 page_fault(mm/page.s,14) void divi

第6章 信号量,中断和时间

程序 linux/include/linux/math_emu.h 1 /* 2 * linux/include/linux/math_emu.h 3 * 4 * (C) 1991 Linus Torvalds 5 */ 6 #ifndef _LINUX_MATH_EMU_H 7 #de

1 CPU interrupt INT trap CPU exception

IntelBook_cn.doc

CC213

36 p->p_osptr->p_ysptr = p->p_ysptr; 37 if (p->p_ysptr) 38 p->p_ysptr->p_osptr = p->p_osptr; 39 else 40 p->p_pptr->p_cptr = p->p_osptr; 41 free_page((

Linux kernel exploit研究和探索

linux进程间通信

新・明解C言語入門編『索引』

新版 明解C++入門編

多进程管理副本.key

int *p int a 0x00C7 0x00C7 0x00C int I[2], *pi = &I[0]; pi++; char C[2], *pc = &C[0]; pc++; float F[2], *pf = &F[0]; pf++;

エスポラージュ株式会社 住所 : 東京都江東区大島 東急ドエルアルス大島 HP: ******************* * 关于 Java 测试试题 ******

untitled

chap07.key

Guava学习之Resources

FY.DOC

Microsoft Word - 01.DOC

C 1

A Preliminary Implementation of Linux Kernel Virus and Process Hiding


_汪_文前新ok[3.1].doc

幻灯片 1

untitled

Andes Technology PPT Temp

06721 main() lock pick proc() restart() [2][4] MINIX minix2.0 GDT, IDT irq table[] CPU CPU CPU CPU (IDTR) idt[] CPU _hwint00:! Interrupt

Microsoft PowerPoint - os_4.ppt

Microsoft Word - 把时间当作朋友(2011第3版)3.0.b.06.doc

untitled

Kernel Kernel Kernel Kernel load estimator runqueue kernel/sched.

ebook

C PICC C++ C++ C C #include<pic.h> C static volatile unsigned char 0x01; static volatile unsigned char 0x02; static volatile unsigned cha

untitled

OOP with Java 通知 Project 4: 4 月 18 日晚 9 点 关于抄袭 没有分数

提纲. 1 实验准备. 2 从实模式进入保护模式. 3 小结 陈香兰 ( 中国科学技术大学计算机学院 ) 软件综合实验之操作系统 July 1, / 11


static struct file_operations gpio_ctl_fops={ ioctl: gpio_ctl_ioctl, open : gpio_open, release: gpio_release, ; #defineled1_on() (GPBDAT &= ~0x1) #def

月光迴旋曲

《C语言程序设计》第2版教材习题参考答案

华恒家庭网关方案

没有幻灯片标题

上 述 的 描 述 是 在 一 台 计 算 机 上 只 有 一 颗 CPU, 并 且 该 CPU 只 有 一 个 核 心 的 情 形, 在 这 种 环 境 下, 虽 然 系 统 可 以 运 行 多 个 任 务, 但 是 在 某 一 个 时 间 点,CPU 只 能 执 行 一 个 进 程 但 是 如

Microsoft Word - 把时间当作朋友(2011第3版)3.0.b.07.doc

《C语言程序设计》教材习题参考答案

06 01 action JavaScript action jquery jquery AJAX CSS jquery CSS jquery HTML CSS jquery.css() getter setter.css('backgroundcolor') jquery CSS b

目 錄 壹 青 輔 會 結 案 附 件 貳 活 動 計 劃 書 參 執 行 內 容 一 教 學 內 容 二 與 當 地 教 師 教 學 交 流 三 服 務 執 行 進 度 肆 執 行 成 效 一 教 學 課 程 二 與 當 地 教 師 教 學 交 流 三 服 務 滿 意 度 調 查 伍 服 務 檢

Microsoft PowerPoint - 3. 函数Functionl.ppt [兼容模式]

C语言的应用.PDF

_12-17.QXD

ROP_bamboofox.key

帝国CMS下在PHP文件中调用数据库类执行SQL语句实例

OOP with Java 通知 Project 2 提交时间 : 3 月 14 日晚 9 点 另一名助教 : 王桢 学习使用文本编辑器 学习使用 cmd: Power shell 阅读参考资料

C++ 程序设计 告别 OJ1 - 参考答案 MASTER 2019 年 5 月 3 日 1

穨control.PDF

<4D F736F F D20B5DAC1F9D5C22ECFB5CDB3B5F7B6C8A3AC495043BACDD2B3C3E6CAA7D0A7BFD8D6C62E646F63>

提问袁小兵:

謙卑的小巨人 文 / 林士涵 印製見證文集是父親在生病後就有的想法 目的是希望更多親朋好友能透 過這些見證認識主耶穌 一起享受屬耶穌那好得無比的生命 我的父親林進聰 民國 42 年 9 月 18 日生於台中縣大肚 鄉 退伍後輾轉來到工業技術研究院化工所上班 認識了他生 命中兩個最愛 信仰耶穌基督以及

第 一 节 认 识 自 我 的 意 义 一 个 人 只 有 认 识 自 我, 才 能 够 正 确 地 认 识 到 自 己 的 优 劣 势, 找 出 自 己 的 职 业 亮 点, 为 自 己 的 顺 利 求 职 推 波 助 澜 ; 一 个 人 只 有 认 识 自 我, 才 能 在 求 职 中 保 持

Microsoft PowerPoint - ch6 [相容模式]

威 福 髮 藝 店 桃 園 市 蘆 竹 區 中 山 里 福 祿 一 街 48 號 地 下 一 樓 50,000 獨 資 李 依 純 105/04/06 府 經 登 字 第 號 宏 品 餐 飲 桃 園 市 桃 園 區 信 光 里 民

2013 C 1 # include <stdio.h> 2 int main ( void ) 3 { 4 int cases, a, b, i; 5 scanf ("%d", & cases ); 6 for (i = 0;i < cases ;i ++) 7 { 8 scanf ("%d %d

Lorem ipsum dolor sit amet, consectetuer adipiscing elit

1

Outline 1 中断信号的作用和处理的一般原则 2 I/O 设备如何引起 CPU 中断 3 x86 CPU 如何在硬件级处理中断信号中断和异常的硬件处理 : 进入中断 / 异常中断和异常的硬件处理 : 从中断 / 异常返回 4 Linux 内核中软件级中断处理及其数据结构初始化中断描述符表低级异

概述

OOP with Java 通知 Project 4: 4 月 19 日晚 9 点

( CIP) /. :, ( ) ISBN TP CIP ( 2005) : : : : * : : 174 ( A ) : : ( 023) : ( 023)

我为什么会扎根泰达?

今天 年春季号 总 92 期

*

( ) / / / / / / /

(Microsoft Word - 8\244T\244\362\277\337\272]\244W\265L\246W.doc)

Microsoft Word - 專家本色 doc


但, 你 应 该 听 过 我 们 走 在 大 路 上 这 首 歌, 或 许 还 知 道 革 命 人 永 远 是 年 轻 那 支 歌 ; 并 且, 几 乎 可 以 肯 定, 你 在 戴 红 领 巾 的 那 阵, 必 然 唱 过 牛 儿 还 在 山 坡 吃 草, 放 牛 的 却 不 知 道 哪 儿 去

2 临 终 助 念 答 问 序 临 终 关 怀, 由 佛 门 净 宗 古 来 祖 师 大 德 提 倡 助 念 往 生, 现 今 已 渐 为 社 会 大 众 所 重 视, 在 台 湾, 台 大 长 庚 等 各 大 医 院, 也 都 设 有 助 念 室 ; 大 陆 上 许 多 道 场, 也 有 专 为

校园之星

Microsoft Word - 澎湖田調報告-宏達組9804.doc

<4D F736F F F696E74202D FA8BEA861B8EAB7BDBEE3A658BB50C0B3A5CE28B773A6CBA5AB29>


之 原 則 及 國 防 部 訂 頒 國 軍 列 管 國 有 不 動 產 提 供 非 軍 方 單 位 使 用 處 理 原 則 規 定 不 符, 仍 應 以 出 租 方 式 辦 理 惟 可 就 偏 遠 地 區 提 供 官 兵 金 融 水 電 服 務 使 用 部 分, 研 議 降 低 租 金 標 準, 報

chineseall

釋禪波羅蜜次第法門

证券代码: 证券简称:锦江股份 公告编号:【】

1700 装 卸 搬 运 7645 装 卸 搬 运 服 务 2100 建 筑 7410 工 程 服 务 11% 装 卸 搬 运 服 务, 是 指 使 用 装 卸 搬 运 工 具 或 者 人 力 畜 力 将 货 物 在 运 输 工 具 之 间 装 卸 现 场 之 间 或 者 运 输 工 具 与 装 卸

前 言 教 育 无 小 事, 它 成 就 着 学 生 的 未 来 作 为 教 师, 他 们 无 时 无 刻 不 在 关 注 着 学 生 的 成 长 学 生 的 未 来 学 生 就 像 一 朵 含 苞 待 放 的 花 朵, 需 要 老 师 们 的 细 心 呵 护, 给 学 生 需 要 的 东 西, 而

《盗墓笔记》 南派三叔/著

平 凡 足 迹 李 本 川 作 者 为 中 国 科 学 院 海 洋 研 究 所 研 究 员,1935 年 生, 山 东 荣 成 人 我 今 年 63 岁 了 大 前 年 丈 夫 和 儿 子 在 一 个 月 内 先 后 离 开 了 人 世, 女 儿 又 已 出 嫁, 现 在 是 孑 然 一 身 我 是

<CFFBB7D1D5DFD0D0CEAAD1A72E6D7073>

独立学院建设与发展


W. Richard Stevens UNIX Sockets API echo Sockets TCP OOB IO C struct C/C++ UNIX fork() select(2)/poll(2)/epoll(4) IO IO CPU 100% libevent UNIX CPU IO

礼仪玉和葬玉

Linux 操作系统分析 Chapter 9-2 Linux 中程序的执行 陈香兰 苏州研究院中国科学技术大学 Fall 2014 November 4,

,,.,. :, :,1999. Barry Wilkinson and Michael Allen. Parallel Programming(Techniques and Applications using Networked Workstations and Parallel

INTRODUCTION TO COM.DOC

untitled

C/C++ - 字符输入输出和字符确认

Transcription:

程序 8-6 linux/kernel/signal.c 1 /* 2 * linux/kernel/signal.c 3 * 4 * (C) 1991 Linus Torvalds 5 */ 6 7 #include <linux/sched.h> // 调度程序头文件, 定义任务结构 task_struct 初始任务 0 的数据, // 还有一些有关描述符参数设置和获取的嵌入式汇编函数宏语句 8 #include <linux/kernel.h> // 内核头文件 含有一些内核常用函数的原形定义 9 #include <asm/segment.h> // 段操作头文件 定义了有关段寄存器操作的嵌入式汇编函数 10 11 #include <signal.h> // 信号头文件 定义信号符号常量, 信号结构及信号操作函数原型 12 #include <errno.h> // 出错号头文件 定义出错号符号常量 13 // 获取当前任务信号屏蔽位图 ( 屏蔽码或阻塞码 ) sgetmask 可分解为 signal-get-mask 以下类似 14 int sys_sgetmask() 15 { 16 return current->blocked; 17 } 18 // 设置新的信号屏蔽位图 信号 SIGKILL 和 SIGSTOP 不能被屏蔽 返回值是原信号屏蔽位图 19 int sys_ssetmask(int newmask) 20 { 21 int old=current->blocked; 22 23 current->blocked = newmask & ~(1<<(SIGKILL-1)) & ~(1<<(SIGSTOP-1)); 24 return old; 25 } 26 // 检测并取得进程收到的但被屏蔽 ( 阻塞 ) 的信号 还未处理信号的位图将被放入 set 中 27 int sys_sigpending(sigset_t *set) 28 { 29 /* fill in "set" with signals pending but blocked. */ /* 用还未处理并且被阻塞信号的位图填入 set 指针所指位置处 */ // 首先验证进程提供的用户存储空间应有 4 个字节 然后把还未处理并且被阻塞信号的位图填入 // set 指针所指位置处 30 verify_area(set,4); 31 put_fs_long(current->blocked & current->signal, (unsigned long *)set); 32 return 0; 33 } 34 35 /* atomically swap in the new signal mask, and wait for a signal. 36 * 37 * we need to play some games with syscall restarting. We get help 38 * from the syscall library interface. Note that we need to coordinate 39 * the calling convention with the libc routine. 40 * 41 * "set" is just the sigmask as described in 1003.1-1988, 3.3.7. 42 * It is assumed that sigset_t can be passed as a 32 bit quantity. 43 * 44 * "restart" holds a restart indication. If it's non-zero, then we 45 * install the old mask, and return normally. If it's zero, we store

46 * the current mask in old_mask and block until a signal comes in. 47 */ /* 自动地更换成新的信号屏蔽码, 并等待信号的到来 * * 我们需要对系统调用 (syscall) 做一些处理 我们会从系统调用库接口取得某些信息 * 注意, 我们需要把调用规则与 libc 库中的子程序统一考虑 * * "set" 正是 POSIX 标准 1003.1-1988 的 3.3.7 节中所描述的信号屏蔽码 sigmask * 其中认为类型 sigset_t 能够作为一个 32 位量传递 * * "restart" 中保持有重启指示标志 如果为非 0 值, 那么我们就设置原来的屏蔽码, * 并且正常返回 如果它为 0, 那么我们就把当前的屏蔽码保存在 oldmask 中 * 并且阻塞进程, 直到收到任何一个信号为止 */ // 该系统调用临时把进程信号屏蔽码替换成参数中给定的 set, 然后挂起进程, 直到收到一个 // 信号为止 // restart 是一个被中断的系统调用重新启动标志 当第 1 次调用该系统调用时, 它是 0 并且 // 在该函数中会把进程原来的阻塞码 blocked 保存起来 (old_mask), 并设置 restart 为非 0 // 值 因此当进程第 2 次调用该系统调用时, 它就会恢复进程原来保存在 old_mask 中的阻塞码 48 int sys_sigsuspend(int restart, unsigned long old_mask, unsigned long set) 49 { // pause() 系统调用将导致调用它的进程进入睡眠状态, 直到收到一个信号 该信号或者会终止 // 进程的执行, 或者导致进程去执行相应的信号捕获函数 50 extern int sys_pause(void); 51 // 如果 restart 标志不为 0, 表示是重新让程序运行起来 于是恢复前面保存在 old_mask 中的 // 原进程阻塞码 并返回码 -EINTR( 系统调用被信号中断 ) 52 if (restart) { 53 /* we're restarting */ /* 我们正在重新启动系统调用 */ 54 current->blocked = old_mask; 55 return -EINTR; 56 } // 否则表示 restart 标志的值是 0 表示第 1 次调用 于是首先设置 restart 标志 ( 置为 1), // 保存进程当前阻塞码 blocked 到 old_mask 中, 并把进程的阻塞码替换成 set 然后调用 // pause() 让进程睡眠, 等待信号的到来 当进程收到一个信号时,pause() 就会返回, 并且 // 进程会去执行信号处理函数, 然后本调用返回 -ERESTARTNOINTR 码退出 这个返回码说明 // 在处理完信号后要求返回到本系统调用中继续运行, 即本系统调用不会被中断 57 /* we're not restarting. do the work */ /* 我们不是重新重新运行, 那么就干活吧 */ 58 *(&restart) = 1; 59 *(&old_mask) = current->blocked; 60 current->blocked = set; 61 (void) sys_pause(); /* return after a signal arrives */ 62 return -ERESTARTNOINTR; /* handle the signal, and come back */ 63 } 64 // 复制 sigaction 数据到 fs 数据段 to 处 即从内核空间复制到用户 ( 任务 ) 数据段中 65 static inline void save_old(char * from,char * to) 66 { 67 int i; 68 // 首先验证 to 处的内存空间是否足够大 然后把一个 sigaction 结构信息复制到 fs 段 ( 用户 ) // 空间中 宏函数 put_fs_byte() 在 include/asm/segment.h 中实现

69 verify_area(to, sizeof(struct sigaction)); 70 for (i=0 ; i< sizeof(struct sigaction) ; i++) { 71 put_fs_byte(*from,to); 72 from++; 73 to++; 74 } 75 } 76 // 把 sigaction 数据从 fs 数据段 from 位置复制到 to 处 即从用户数据空间取到内核数据段中 77 static inline void get_new(char * from,char * to) 78 { 79 int i; 80 81 for (i=0 ; i< sizeof(struct sigaction) ; i++) 82 *(to++) = get_fs_byte(from++); 83 } 84 // signal() 系统调用 类似于 sigaction() 为指定的信号安装新的信号句柄( 信号处理程序 ) // 信号句柄可以是用户指定的函数, 也可以是 SIG_DFL( 默认句柄 ) 或 SIG_IGN( 忽略 ) // 参数 signum -- 指定的信号 ;handler -- 指定的句柄 ;restorer 恢复函数指针, 该函数由 // Libc 库提供 用于在信号处理程序结束后恢复系统调用返回时几个寄存器的原有值以及系统 // 调用的返回值, 就好象系统调用没有执行过信号处理程序而直接返回到用户程序一样 函数 // 返回原信号句柄 85 int sys_signal(int signum, long handler, long restorer) 86 { 87 struct sigaction tmp; 88 // 首先验证信号值在有效范围 (1--32) 内, 并且不得是信号 SIGKILL( 和 SIGSTOP) 因为这 // 两个信号不能被进程捕获 89 if (signum<1 signum>32 signum==sigkill signum==sigstop) 90 return -EINVAL; // 然后根据提供的参数组建 sigaction 结构内容 sa_handler 是指定的信号处理句柄 ( 函数 ) // sa_mask 是执行信号处理句柄时的信号屏蔽码 sa_flags 是执行时的一些标志组合 这里设定 // 该信号处理句柄只使用 1 次后就恢复到默认值, 并允许信号在自己的处理句柄中收到 91 tmp.sa_handler = (void (*)(int)) handler; 92 tmp.sa_mask = 0; 93 tmp.sa_flags = SA_ONESHOT SA_NOMASK; 94 tmp.sa_restorer = (void (*)(void)) restorer; // 保存恢复处理函数指针 // 接着取该信号原来的处理句柄, 并设置该信号的 sigaction 结构 最后返回原信号句柄 95 handler = (long) current->sigaction[signum-1].sa_handler; 96 current->sigaction[signum-1] = tmp; 97 return handler; 98 } 99 // sigaction() 系统调用 改变进程在收到一个信号时的操作 signum 是除了 SIGKILL 以外的 // 任何信号 [ 如果新操作 (action) 不为空 ] 则新操作被安装 如果 oldaction 指针不为空, // 则原操作被保留到 oldaction 成功则返回 0, 否则为 -EINVAL 100 int sys_sigaction(int signum, const struct sigaction * action, 101 struct sigaction * oldaction) 102 { 103 struct sigaction tmp; 104 // 首先验证信号值在有效范围 (1--32) 内, 并且不得是信号 SIGKILL( 和 SIGSTOP) 因为这

// 两个信号不能被进程捕获 105 if (signum<1 signum>32 signum==sigkill signum==sigstop) 106 return -EINVAL; // 在信号的 sigaction 结构中设置新的操作 ( 动作 ) 如果 oldaction 指针不为空的话, 则将 // 原操作指针保存到 oldaction 所指的位置 107 tmp = current->sigaction[signum-1]; 108 get_new((char *) action, 109 (char *) (signum-1+current->sigaction)); 110 if (oldaction) 111 save_old((char *) &tmp,(char *) oldaction); // 如果允许信号在自己的信号句柄中收到, 则令屏蔽码为 0, 否则设置屏蔽本信号 112 if (current->sigaction[signum-1].sa_flags & SA_NOMASK) 113 current->sigaction[signum-1].sa_mask = 0; 114 else 115 current->sigaction[signum-1].sa_mask = (1<<(signum-1)); 116 return 0; 117 } 118 119 /* 120 * Routine writes a core dump image in the current directory. 121 * Currently not implemented. 122 */ /* * 在当前目录中产生 core dump 映像文件的子程序 目前还没有实现 */ 123 int core_dump(long signr) 124 { 125 return(0); /* We didn't do a dump */ 126 } 127 // 系统调用的中断处理程序中真正的信号预处理程序 ( 在 kernel/sys_call.s,119 行 ) 这段 // 代码的主要作用是将信号处理句柄插入到用户程序堆栈中, 并在本系统调用结束返回后立刻 // 执行信号句柄程序, 然后继续执行用户的程序 // 函数的参数是进入系统调用处理程序 sys_call.s 开始, 直到调用本函数 (sys_call.s // 第 125 行 ) 前逐步压入堆栈的值 这些值包括 ( 在 sys_call.s 中的代码行 ): // 1 CPU 执行中断指令压入的用户栈地址 ss 和 esp 标志寄存器 eflags 和返回地址 cs 和 eip; // 2 第 85--91 行在刚进入 system_call 时压入栈的段寄存器 ds es fs 以及寄存器 eax // (orig_eax) edx ecx 和 ebx 的值 ; // 3 第 100 行调用 sys_call_table 后压入栈中的相应系统调用处理函数的返回值 (eax) // 4 第 124 行压入栈中的当前处理的信号值 (signr) 128 int do_signal(long signr,long eax,long ebx, long ecx, long edx, long orig_eax, 129 long fs, long es, long ds, 130 long eip, long cs, long eflags, 131 unsigned long * esp, long ss) 132 { 133 unsigned long sa_handler; 134 long old_eip=eip; 135 struct sigaction * sa = current->sigaction + signr - 1; 136 int longs; // 即 current->sigaction[signr-1] 137 138 unsigned long * tmp_esp; 139 // 以下是调试语句 当定义了 notdef 时会打印相关信息

140 #ifdef notdef 141 printk("pid: %d, signr: %x, eax=%d, oeax = %d, int=%d\n", 142 current->pid, signr, eax, orig_eax, 143 sa->sa_flags & SA_INTERRUPT); 144 #endif // 如果不是系统调用而是其它中断执行过程中调用到本函数时, roig_eax 值为 -1 参见 // sys_call.s 第 144 行等语句 因此当 orig_eax 不等于 -1 时, 说明是在某个系统调用的 // 最后调用了本函数 在 kernel/exit.c 的 waitpid() 函数中, 如果收到了 SIGCHLD 信号, // 或者在读管道函数 fs/pipe.c 中管道当前读数据但没有读到任何数据等情况下, 进程收到 // 了任何一个非阻塞的信号, 则都会以 -ERESTARTSYS 返回值返回 它表示进程可以被中断, // 但是在继续执行后会重新启动系统调用 返回码 -ERESTARTNOINTR 说明在处理完信号后要求 // 返回到原系统调用中继续运行, 即系统调用不会被中断 参见前面第 62 行 // 因此下面语句说明如果是在系统调用中调用的本函数, 并且相应系统调用的返回码 eax 等于 // -ERESTARTSYS 或 -ERESTARTNOINTR 时进行下面的处理 ( 实际上还没有真正回到用户程序中 ) 145 if ((orig_eax!= -1) && 146 ((eax == -ERESTARTSYS) (eax == -ERESTARTNOINTR))) { // 如果系统调用返回码是 -ERESTARTSYS( 重新启动系统调用 ), 并且 sigaction 中含有标志 // SA_INTERRUPT( 系统调用被信号中断后不重新启动系统调用 ) 或者信号值小于 SIGCONT 或者 // 信号值大于 SIGTTOU( 即信号不是 SIGCONT SIGSTOP SIGTSTP SIGTTIN 或 SIGTTOU), 则 // 修改系统调用的返回值为 eax = -EINTR, 即被信号中断的系统调用 147 if ((eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT) 148 signr < SIGCONT signr > SIGTTOU)) 149 *(&eax) = -EINTR; 150 else { // 否则就恢复进程寄存器 eax 在调用系统调用之前的值, 并且把原程序指令指针回调 2 字节 即 // 当返回用户程序时, 让程序重新启动执行被信号中断的系统调用 151 *(&eax) = orig_eax; 152 *(&eip) = old_eip -= 2; 153 } 154 } // 如果信号句柄为 SIG_IGN(1, 默认忽略句柄 ) 则不对信号进行处理而直接返回 155 sa_handler = (unsigned long) sa->sa_handler; 156 if (sa_handler==1) 157 return(1); /* Ignore, see if there are more signals... */ // 如果句柄为 SIG_DFL(0, 默认处理 ), 则根据具体的信号进行分别处理 158 if (!sa_handler) { 159 switch (signr) { // 如果信号是以下两个则也忽略之, 并返回 160 case SIGCONT: 161 case SIGCHLD: 162 return(1); /* Ignore,... */ 163 // 如果信号是以下 4 种信号之一, 则把当前进程状态置为停止状态 TASK_STOPPED 若当前进程 // 父进程对 SIGCHLD 信号的 sigaction 处理标志 SA_NOCLDSTOP ( 即当子进程停止执行或又继 // 续执行时不要产生 SIGCHLD 信号 ) 没有置位, 那么就给父进程发送 SIGCHLD 信号 164 case SIGSTOP: 165 case SIGTSTP: 166 case SIGTTIN: 167 case SIGTTOU: 168 current->state = TASK_STOPPED; 169 current->exit_code = signr; 170 if (!(current->p_pptr->sigaction[sigchld-1].sa_flags & 171 SA_NOCLDSTOP))

172 current->p_pptr->signal = (1<<(SIGCHLD-1)); 173 return(1); /* Reschedule another event */ 174 // 如果信号是以下 6 种信号之一, 那么若信号产生了 core dump, 则以退出码为 signr 0x80 // 调用 do_exit() 退出 否则退出码就是信号值 do_exit() 的参数是返回码和程序提供的退出 // 状态信息 可作为 wait() 或 waitpid() 函数的状态信息 参见 sys/wait.h 文件第 13-18 行 // wait() 或 waitpid() 利用这些宏就可以取得子进程的退出状态码或子进程终止的原因 ( 信号 ) 175 case SIGQUIT: 176 case SIGILL: 177 case SIGTRAP: 178 case SIGIOT: 179 case SIGFPE: 180 case SIGSEGV: 181 if (core_dump(signr)) 182 do_exit(signr 0x80); 183 /* fall through */ 184 default: 185 do_exit(signr); 186 } 187 } 188 /* 189 * OK, we're invoking a handler 190 */ /* * OK, 现在我们准备对信号句柄调用的设置 */ // 如果该信号句柄只需被调用一次, 则将该句柄置空 注意, 该信号句柄在前面已经保存在 // sa_handler 指针中 // 在系统调用进入内核时, 用户程序返回地址 (eip cs) 被保存在内核态栈中 下面这段代 // 码修改内核态堆栈上用户调用系统调用时的代码指针 eip 为指向信号处理句柄, 同时也将 // sa_restorer signr 进程屏蔽码 ( 如果 SA_NOMASK 没置位 ) eax ecx edx 作为参数以及 // 原调用系统调用的程序返回指针及标志寄存器值压入用户堆栈 因此在本次系统调用中断 // 返回用户程序时会首先执行用户的信号句柄程序, 然后再继续执行用户程序 191 if (sa->sa_flags & SA_ONESHOT) 192 sa->sa_handler = NULL; // 将内核态栈上用户调用系统调用下一条代码指令指针 eip 指向该信号处理句柄 由于 C 函数 // 是传值函数, 因此给 eip 赋值时需要使用 "*(&eip)" 的形式 另外, 如果允许信号自己的 // 处理句柄收到信号自己, 则也需要将进程的阻塞码压入堆栈 // 这里请注意, 使用如下方式 ( 第 193 行 ) 对普通 C 函数参数进行修改是不起作用的 因为当 // 函数返回时堆栈上的参数将会被调用者丢弃 这里之所以可以使用这种方式, 是因为该函数 // 是从汇编程序中被调用的, 并且在函数返回后汇编程序并没有把调用 do_signal() 时的所有 // 参数都丢弃 eip 等仍然在堆栈中 // sigaction 结构的 sa_mask 字段给出了在当前信号句柄 ( 信号描述符 ) 程序执行期间应该被 // 屏蔽的信号集 同时, 引起本信号句柄执行的信号也会被屏蔽 不过若 sa_flags 中使用了 // SA_NOMASK 标志, 那么引起本信号句柄执行的信号将不会被屏蔽掉 如果允许信号自己的处 // 理句柄程序收到信号自己, 则也需要将进程的信号阻塞码压入堆栈 193 *(&eip) = sa_handler; 194 longs = (sa->sa_flags & SA_NOMASK)?7:8; // 将原调用程序的用户堆栈指针向下扩展 7( 或 8) 个长字 ( 用来存放调用信号句柄的参数等 ), // 并检查内存使用情况 ( 例如如果内存超界则分配新页等 ) 195 *(&esp) -= longs; 196 verify_area(esp,longs*4); // 在用户堆栈中从下到上存放 sa_restorer 信号 signr 屏蔽码 blocked( 如果 SA_NOMASK

// 置位 ) eax ecx edx eflags 和用户程序原代码指针 197 tmp_esp=esp; 198 put_fs_long((long) sa->sa_restorer,tmp_esp++); 199 put_fs_long(signr,tmp_esp++); 200 if (!(sa->sa_flags & SA_NOMASK)) 201 put_fs_long(current->blocked,tmp_esp++); 202 put_fs_long(eax,tmp_esp++); 203 put_fs_long(ecx,tmp_esp++); 204 put_fs_long(edx,tmp_esp++); 205 put_fs_long(eflags,tmp_esp++); 206 put_fs_long(old_eip,tmp_esp++); 207 current->blocked = sa->sa_mask; // 进程阻塞码 ( 屏蔽码 ) 添上 sa_mask 中的码位 208 return(0); /* Continue, execute handler */ 209 } 210