《linux 内核完全剖析》 signal.c 代码分析笔记

signal.c 代码分析笔记

sgetmask


int sys_sgetmask()// 获取当前进程阻塞的信号
{
         returncurrent->blocked;
}

sys_ssetmask


int sys_ssetmask(int newmask) //设置当前进程阻塞信号,确保SIGKILL 和SIGSTOP不被阻塞
{

         int old=current->blocked;

         current->blocked= newmask & ~(1<<(SIGKILL-1)) & ~(1<<(SIGSTOP-1));

         return old;
}

sys_sigpending


int sys_sigpending(sigset_t *set)//verify_area的水有点深。嘿嘿。。。
{
   /* fill in "set" with signals pending but blocked. */

   verify_area(set,4); //验证set指向的地址处4字节是否可写,不可写就给他分配一页内存,并给与读写权限。。。。
   put_fs_long(current->blocked & current->signal, (unsigned long*)set); //这里理解成把第一个参数的值赋值给set指向的地址就好。。。。

   return 0;
}

put_fs_byte


extern inline void put_fs_byte(charval,char *addr)
{

__asm__ ("movb%0,%%fs:%1"::"r" (val),"m" (*addr));

}

需要说明的就是这里fs寄存器是指向LDT的数据段描述符0x17,即fs用于访问数据

sys_sigsuspend


int sys_sigsuspend(int restart, unsignedlong old_mask, unsigned long set)
{
   extern int sys_pause(void); //声明引用sys_pause

   if (restart) {//如果restart 非零,进程的阻塞信号为old_mask
         /*we‘re restarting */
         current->blocked= old_mask;

         return-EINTR;
    }

   //如果restart 非零
   /* we‘re not restarting.  do thework */
   *(&restart) = 1;
   *(&old_mask) = current->blocked; //把当前进程的阻塞信号做oldmask

   //额。。。我不知道给一个局部变量赋值之后又不返回,先的函数也不引用这变量,

   //这究竟有什么用!我必须质疑这是冗余的赋值操作
   current->blocked = set;
   (void) sys_pause();                     /*return after a signal arrives */

   //我不得不感叹,这个sys_pause就相当于sleep(很短的时间)

   //这么做就是为了捕获信号

   return -ERESTARTNOINTR;               /*handle the signal, and come back */
}

save_old


static inline void save_old(char *from,char * to) //把内核段的数据copy到用户段(local date space)
{
         inti;

         verify_area(to,sizeof(struct sigaction)); //确保to地址处有结构体大小的内存可读写
         for(i=0 ; i< sizeof(struct sigaction) ; i++) { //一个字节一个字节的copy,from到to
                   put_fs_byte(*from,to);
                   from++;
                   to++;
         }
}

get_new


static inline void get_new(char * from,char* to)//把数据从用户段copy到内核数据段中
{
         inti;

         for(i=0 ; i< sizeof(struct sigaction) ; i++)

                   *(to++)= get_fs_byte(from++);
}

sys_signal


int sys_signal(int signum, long handler,long restorer)
{
         structsigaction tmp;

         if(signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
         //常规检测,signal必须在定义范围内,并且不能呢个为SIGKILL和SIGSTOP,否者直接结束

                   return-EINVAL;

         tmp.sa_handler= (void (*)(int)) handler; //handler被强制转换成了一个函数指针,这个函数以int为参数,无返回
         tmp.sa_mask= 0;//清空所有信号
         tmp.sa_flags= SA_ONESHOT | SA_NOMASK;
         tmp.sa_restorer= (void (*)(void)) restorer; //restorer被强制转换成一个函数指针,这个函数以int为参数,无返回
         handler= (long) current->sigaction[signum-1].sa_handler;
         current->sigaction[signum-1]= tmp; //结构体直接赋值

         return handler;
}

sys_sigaction


int sys_sigaction(int signum, const structsigaction * action,
         structsigaction * oldaction)
{
         structsigaction tmp;

         if(signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
         //常规检测,signal必须在定义范围内,并且不能呢个为SIGKILL和SIGSTOP,否者直接结束

                   return-EINVAL;

         tmp= current->sigaction[signum-1];
         get_new((char*) action,
                   (char*) (signum-1+current->sigaction)); //把只读的action结构体的信息写入到内核数据段

         if(oldaction)
                   save_old((char*) &tmp,(char *) oldaction); //current进程原来的sigaction结构体信息

         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)); //否则把signum 写入信号变量
         return0;

}

do_signal


int do_signal(long signr,long eax,long ebx,long ecx, long edx, long orig_eax,
         longfs, long es, long ds,
         longeip, long cs, long eflags,
         unsignedlong * esp, long ss)
{

         unsignedlong sa_handler;

         longold_eip=eip;

         structsigaction * sa = current->sigaction + signr - 1;

         int longs;

         unsignedlong * tmp_esp;

#ifdef notdef

         printk("pid:%d, signr: %x, eax=%d, oeax = %d, int=%d\n",
                   current->pid,signr, eax, orig_eax,
                   sa->sa_flags& SA_INTERRUPT); //打印相关信息

#endif

         if((orig_eax != -1) && //如果不是系统调用而是其他中断执行过程中调用到本函数时,roig_eax 值为-1
             ((eax == -ERESTARTSYS) || (eax ==-ERESTARTNOINTR))) {
                   if((eax == -ERESTARTSYS) && ((sa->sa_flags & SA_INTERRUPT) ||
                       signr < SIGCONT || signr > SIGTTOU))
                            *(&eax)= -EINTR;
                   else{
                            *(&eax)= orig_eax;
                            *(&eip)= old_eip -= 2;//不明白为什么这里要回调两个byte
                   }
         }

         sa_handler= (unsigned long) sa->sa_handler;

         if(sa_handler==1)
                   return(1);   /* Ignore, see if there are more signals...*/

         if(!sa_handler) { //sa_handler 为SIG_DFL 0
                   switch(signr) {

                   caseSIGCONT:
                   caseSIGCHLD:

                            return(1);  /* Ignore, ... */

                   caseSIGSTOP:
                   caseSIGTSTP:
                   caseSIGTTIN:
                   caseSIGTTOU:

                            current->state= TASK_STOPPED;
                           //SIGSTOP SIGTSTP SIGTTIN SIGTTOU 被捕捉了,那么把当前进程置为停止状态
                            current->exit_code= signr;

                            if(!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags &

                                               SA_NOCLDSTOP))// 如果parent process 不允许child process stop
                                     current->p_pptr->signal|= (1<<(SIGCHLD-1)); //告诉parent ,child process 挂掉了
                            return(1);  /* Reschedule another event */

                   caseSIGQUIT:
                   caseSIGILL:
                   caseSIGTRAP:
                   caseSIGIOT:
                   caseSIGFPE:
                   caseSIGSEGV:
                            if(core_dump(signr))
                                     do_exit(signr|0x80);

                            /*fall through */
                   default:
                            do_exit(signr);
                   }

         }

         /*
          * OK, we‘re invoking a handler
          */

         if(sa->sa_flags & SA_ONESHOT)
                   sa->sa_handler= NULL;
         *(&eip)= sa_handler;
         longs= (sa->sa_flags & SA_NOMASK)?7:8;
          //堆栈指针向下偏移7 或者8 ,这时候 longs是 long型变量,esp也是,减去7,8也就是数值上的而已
         //但是我没想明白这个78的单位是什么??? 这又不是指针,所以我就觉得很奇怪。。。。

         *(&esp)-= longs;
         verify_area(esp,longs*4);
         tmp_esp=esp;

         //各种从用户数据段copy到内核数据段

         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;
         return(0);                   /* Continue, execute handler*/

}

《linux 内核完全剖析》 signal.c 代码分析笔记

时间: 2024-11-18 02:57:40

《linux 内核完全剖析》 signal.c 代码分析笔记的相关文章

《linux 内核完全剖析》 void free_page() 分析

最近在做项目开发时用到了MySql数据库,在看了一些有关MySql的文章后,很快就上手使用了.在使用的过程中还是出现了一些问题,因为使用的是绿色免安装版的MySql所以在配置的时候出现了一些问题,该篇文章就主要针对MySql绿色版的配置及其使用进行讨论. 一.MySql概述 MySql数据库是有瑞典MySql AB公司开发,现在该公司被Oracle收购属于Oracle所有.同SQL Server类似,它也是基于关系型数据库的数据库管理系统,在Web应用方面MySQL是最好的RDBMS之一,因为它

《linux 内核完全剖析》 keyboard.S 部分代码分析(key_map)

keyboard.S 部分代码分析(key_map) keyboard中间有这么一段,我一开始没看明白,究竟啥意思 key_map: .byte 0,27 .ascii "1234567890-=" .byte 127,9 .ascii "qwertyuiop[]" .byte 13,0 .ascii "asdfghjkl;'" .byte '`,0 .ascii "\\zxcvbnm,./" .byte 0,'*,0,32

《linux 内核完全剖析》 exit.c 代码分析笔记

exit.c 代码分析笔记 release 释放进程的函数release() 主要根据指定进程的任务数据结构指针,在任务数组中删除指定的进程指针,释放相关内存页,并立刻让内核重新调度进程的运行. void release(struct task_struct * p) //释放p指向的进程 { int i; if (!p) //常规检测p是否为0 return; if (p == current) { //不能把自己给释放了 printk("task releasing itself\n\r&q

《linux 内核完全剖析》sched.c sched.h 代码分析笔记

sched.c sched.h 代码分析笔记 首先上header file sched.h #ifndef _SCHED_H #define _SCHED_H #define HZ 100 #define NR_TASKS 64 #define TASK_SIZE 0x04000000 #define LIBRARY_SIZE 0x00400000 #if (TASK_SIZE & 0x3fffff) #error "TASK_SIZE must be multiple of 4M&qu

《linux 内核完全剖析》 sys.c 代码分析

sys.c 代码分析 setregid /* * This is done BSD-style, with no consideration of the saved gid, except * that if you set the effective gid, it sets the saved gid too. This * makes it possible for a setgid program to completely drop its privileges, * which i

《linux 内核完全剖析》 笔记 由逻辑地址转换成线性地址代码分析

一开始由这段代码引发的纠结 get_base(current->ldt[1]) 下面是各个相关的代码,摘自不同的header files... current是指向当前task的指针 struct desc_struct ldt[3]; struct desc_struct { unsigned long a,b; } ; #define _get_base(addr) ({unsigned long __base; __asm__("movb %3,%%dh\n\t" &quo

《linux 内核完全剖析》 fork.c 代码分析笔记

fork.c 代码分析笔记 verifiy_area long last_pid=0; //全局变量,用来记录目前最大的pid数值 void verify_area(void * addr,int size) // addr 是虚拟地址 ,size是需要写入的字节大小 { unsigned long start; start = (unsigned long) addr; //把地址强制类型转换之后,赋值给start size += start & 0xfff; //取addr在当前虚拟地址中4

《linux 内核完全剖析》 笔记 CODE_SPACE 宏定义分析

在memory.c里面,遇到一个宏定义,如下: #define CODE_SPACE(addr) ((((addr)+4095)&~4095) < current->start_code + current->end_code) 看的第一眼,不知道,第二眼,还是不知道,纠结了半天还是不知道. 睡了一晚,今天早上再看,嘿嘿,居然看懂了... 这个宏定义用于判断给定的addr线性地址是否位于当前进程的代码段中. 4095 = 0xFFF; addr+4095的作用是将位于0~4095

《linux 内核完全剖析》 chapter 8 内核代码

求n内与n互质的数有多少个. 欧拉函数就是为这个而生的. 如果对欧拉函数不是很了解的话,可以看看这个http://zh.wikipedia.org/wiki/%E6%AC%A7%E6%8B%89%E5%87%BD%E6%95%B0 我们有了上一篇埃氏筛法求素数之后,我们求这个就简单了. 具体用法就是这个函数 用最后这个公式.n可以写成 我们先来求得2到sqrt(n)的素数然后来将n化成的形式 中间如果n能整除p的话就要带入公式了.这样我们就求得最后结果了. #include<iostream>