阅读背景:

linux内核学习-6信号量(关注新浪微博:寂寞侵蚀的岁月(4000多篇技术分享))

来源:互联网 

#include // 调度程序头文件,定义了义务构造task_struct、初始义务0 的数据,// 还有一些有关描写符参数设置和获得的嵌入式汇编函数宏语句。8 #include // 内核头文件。含有一些内核常常使用函数的本相定义。9 #include // 段操作头文件。定义了有关段寄存器操作的嵌入式汇编函数。1011 #include // 信号头文件。定义信号符号常量,信号构造和信号操作函数原型。1213 volatile void do_exit(int error_code); // 前面的限定符volatile 请求编译器不要对其进行优化。14// 获得当前义务信号屏蔽位图(屏蔽码)。15 int sys_sgetmask()16 {17 return current->blocked;18 }19// 设置新的信号屏蔽位图。SIGKILL 不能被屏蔽。返回值是原信号屏蔽位图。20 int sys_ssetmask(int newmask)21 {22 int old=current->blocked;2324 current->blocked = newmask & ~(1<<(SIGKILL-1));25 return old;26 }27// 复制sigaction 数据到fs 数据段to 处。。28 static inline void save_old(char * from,char * to)调用相应功效的C函数处置程序。对信号进行辨认预处置。调用do_signal()函数。将信号处置程序句柄插入到用户堆栈中。IRET内核体系调用中止处置程序体系调用int 0x80下一语句信号处置程序用户程序更多电子书教程下载请登陆https://down.zzbaike.com/ebook我站供给的电子书教程均为网上搜集,如果该教程触及或损害到您的版权请接洽我们。第5 章 内核代码 linux/kernel/11329 {30 int i;3132 verify_area(to, sizeof(struct sigaction)); // 验证to 处的内存是不是足够。33 for (i=0 ; i< sizeof(struct sigaction) ; i++) {34 put_fs_byte(*from,to); // 复制到fs 段。通常为用户数据段。35 from++; // put_fs_byte()在include/asm/segment.h 中。36 to++;37 }38 }39// 把sigaction 数据从fs 数据段from 地位复制到to 处。40 static inline void get_new(char * from,char * to)41 {42 int i;4344 for (i=0 ; i< sizeof(struct sigaction) ; i++)45 *(to++) = get_fs_byte(from++);46 }47// signal()体系调用。相似于sigaction()。为指定的信号安装新的信号句柄(信号处置程序)。// 信号句柄可以是用户指定的函数,也能够是SIG_DFL(默许句柄)或SIG_IGN(疏忽)。// 参数signum --指定的信号;handler -- 指定的句柄;restorer –原程序当前履行的地址地位。// 函数返回原信号句柄。48 int sys_signal(int signum, long handler, long restorer)49 {50 struct sigaction tmp;5152 if (signum<1 signum="">32 || signum==SIGKILL) // 信号值要在(1-32)规模内,53 return -1; // 并且不得是SIGKILL。54 tmp.sa_handler = (void (*)(int)) handler; // 指定的信号处置句柄。55 tmp.sa_mask = 0; // 履行时的信号屏蔽码。56 tmp.sa_flags = SA_ONESHOT | SA_NOMASK; // 该句柄只应用1 次后就恢复到默许值,// 并许可信号在自己的处置句柄中收到。57 tmp.sa_restorer = (void (*)(void)) restorer; // 保留返回地址。58 handler = (long) current->sigaction[signum-1].sa_handler;59 current->sigaction[signum-1] = tmp;60 return handler;61 }62// sigaction()体系调用。转变过程在收到一个信号时的操作。signum 是除SIGKILL 之外的任何// 信号。[如果新操作(action)不为空]则新操作被安装。如果oldaction 指针不为空,则原操作// 被保留到oldaction。胜利则返回0,否则为-1。63 int sys_sigaction(int signum, const struct sigaction * action,64 struct sigaction * oldaction)65 {66 struct sigaction tmp;67// 信号值要在(1-32)规模内,并且信号SIGKILL 的处置句柄不能被转变。68 if (signum<1 signum="">32 || signum==SIGKILL)69 return -1;// 在信号的sigaction 构造中设置新的操作(动作)。70 tmp = current->sigaction[signum-1];更多电子书教程下载请登陆https://down.zzbaike.com/ebook我站供给的电子书教程均为网上搜集,如果该教程触及或损害到您的版权请接洽我们。第5 章 内核代码 linux/kernel/11471 get_new((char *) action,72 (char *) (signum-1+current->sigaction));// 如果oldaction 指针不为空的话,则将原操作指针保留到oldaction 所指的地位。73 if (oldaction)74 save_old((char *) &tmp,(char *) oldaction);// 如果许可信号在自己的信号句柄中收到,则令屏蔽码为0,否则设置屏蔽本信号。75 if (current->sigaction[signum-1].sa_flags & SA_NOMASK)76 current->sigaction[signum-1].sa_mask = 0;77 else78 current->sigaction[signum-1].sa_mask |= (1<<(signum-1));79 return 0;80 }81// 体系调用中止处置程序中真实的信号处置程序(在kernel/system_call.s,119 行)。// 该段代码的重要作用是将信号的处置句柄插入到用户程序堆栈中,并在本体系调用停止// 返回后立刻履行信号句柄程序,然后持续履行用户的程序。82 void do_signal(long signr,long eax, long ebx, long ecx, long edx,83 long fs, long es, long ds,84 long eip, long cs, long eflags,85 unsigned long * esp, long ss)86 {87 unsigned long sa_handler;88 long old_eip=eip;89 struct sigaction * sa = current->sigaction + signr - 1; //current->sigaction[signu-1]。90 int longs;91 unsigned long * tmp_esp;9293 sa_handler = (unsigned long) sa->sa_handler;// 如果信号句柄为SIG_IGN(疏忽),则返回;如果句柄为SIG_DFL(默许处置),则如果信号是// SIGCHLD 则返回,否则终止过程的履行94 if (sa_handler==1)95 return;96 if (!sa_handler) {97 if (signr==SIGCHLD)98 return;99 else100 do_exit(1<<(signr-1)); // [?? 为何以信号位图为参数?不为何!?☺]// 这里应当是do_exit(1<sa_flags & SA_ONESHOT)103 sa->sa_handler = NULL;// 下面这段代码将信号处置句柄插入到用户堆栈中,同时也将sa_restorer,signr,过程屏蔽码(如果// SA_NOMASK 没置位),eax,ecx,edx 作为参数和原调用体系调用的程序返回指针及标记寄存器值// 压入堆栈。因此在本次体系调用中止(0x80)返回用户程序时会首先履行用户的信号句柄程序,然后// 再持续履行用户程序。// 将用户调用体系调用的代码指针eip 指向该信号处置句柄。104 *(&eip) = sa_handler;// 如果许可信号自己的处置句柄收到信号自己,则也须要将过程的阻塞码压入堆栈。105 longs = (sa->sa_flags & SA_NOMASK)?7:8;// 将原调用程序的用户的堆栈指针向下扩大7(或8)个长字(用来寄存调用信号句柄的参数等),更多电子书教程下载请登陆https://down.zzbaike.com/ebook我站供给的电子书教程均为网上搜集,如果该教程触及或损害到您的版权请接洽我们。第5 章 内核代码 linux/kernel/115// 并检讨内存应用情形(例如如果内存超界则分配新页等)。106 *(&esp) -= longs;107 verify_area(esp,longs*4);// 在用户堆栈中从下到上寄存sa_restorer, 信号signr, 屏蔽码blocked(如果SA_NOMASK 置位),// eax, ecx, edx, eflags 和用户程序原代码指针。108 tmp_esp=esp;109 put_fs_long((long) sa->sa_restorer,tmp_esp++);110 put_fs_long(signr,tmp_esp++);111 if (!(sa->sa_flags & SA_NOMASK))112 put_fs_long(current->blocked,tmp_esp++);113 put_fs_long(eax,tmp_esp++);114 put_fs_long(ecx,tmp_esp++);115 put_fs_long(edx,tmp_esp++);116 put_fs_long(eflags,tmp_esp++);117 put_fs_long(old_eip,tmp_esp++);118 current->blocked |= sa->sa_mask; // 过程阻塞码(屏蔽码)添上sa_mask 中的码位。119 }1205.8.3 其它信息5.8.3.1 过程信号解释过程当中的信号是用于过程之间通讯的一种简略资讯,通常是下表中的一个标号数值,并且不携带任何其它的信息。例如当一个子过程终止或停止时,就会发生一个标号为17 的SIGCHILD 信号发送给父过程,以通知父过程有关子过程确当前状况。关于一个过程如何处置收到的信号,一般有两种做法:一是程序的过程不去处置,此时该信号会由体系相应的默许信号处置程序进行处置;第二种做法是过程应用自己的信号处置程序来处置信号。#include // 调度程序头文件,定义了义务构造task_struct、初始义务0 的数据,/




你的当前访问异常,请进行认证后继续阅读剩余内容。

分享到: