+ -
当前位置:首页 → 问答吧 → 关于linux内核0.11中signal机制实现的疑问--

关于linux内核0.11中signal机制实现的疑问--

时间:2010-08-06

来源:互联网

//先附上有疑问的源代码do_signal......

    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 {
            unsigned long sa_handler;
87
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;
92
93         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;
                    else
99
                             do_exit(1<<(signr-1)); // 为什么以信号位图为参数?不为什么!?☺
100
                                                      // 这里应该是 do_exit(1<<(signr))。
101         }
    // 如果该信号句柄只需使用一次,则将该句柄置空(该信号句柄已经保存在 sa_handler 指针中)。
102         if (sa->sa_flags & SA_ONESHOT)
103                 sa->sa_handler = NULL;
    // 下面这段代码将信号处理句柄插入到用户堆栈中,同时也将 sa_restorer,signr,进程屏蔽码(如果
    // SA_NOMASK 没置位),eax,ecx,edx 作为参数以及原调用系统调用的程序返回指针及标志寄存器值
    // 压入堆栈。因此在本次系统调用中断(0x80)返回用户程序时会首先执行用户的信号句柄程序,然后
    // 再继续执行用户程序。
    // 将用户调用系统调用的代码指针 eip 指向该信号处理句柄。
            *(&eip) = sa_handler;
104
    // 如果允许信号自己的处理句柄收到信号自己,则也需要将进程的阻塞码压入堆栈。
    // 注意,这里 longs 的结果应该选择(7*4)8*4),因为堆栈是以 4 字节为单位操作的。
105         longs = (sa->sa_flags & SA_NOMASK)?7:8;
    // 将原调用程序的用户堆栈指针向下扩展 7(或 个长字(用来存放调用信号句柄的参数等),
                                               - 145 -
                                         5.9 signal.c 程序
    // 并检查内存使用情况(例如如果内存超界则分配新页等)。
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++);
            put_fs_long(old_eip,tmp_esp++);

117
118         current->blocked |= sa->sa_mask; // 进程阻塞码(屏蔽码)添上 sa_mask 中的码位。
119 }
120


我的问题是:调用do_signal是在内核中进行的,就是在执行内核调用(返回前的)的最后阶段执行的,那么这个时候的堆栈指针照理说是指向内核堆栈的,
那么就是说:地106行: *(&esp) -= longs;
                     这句话的意思就是取内核堆栈中保存的用户堆栈指针esp的么????
                     从下面的put_fs_long可以看出确实是的
                     那么为什么这句话的意思是取内核堆栈中保存的esp的值呢?怎么理解?

Screenshot-1.png (119.4 KB)

下载次数:0

2010-08-06 13:17

内核栈和用户栈

作者: sunseven1245yah   发布时间: 2010-08-06

回复 sunseven1245yah


   首先你应该搞清楚这个esp是什么东东...这个是作为unsigned long *类型的参数传到这个函数的。 映像中这个esp应该是当前进程的用户态栈指针。 esp只是一个变量.不是CPU中的一个寄存器ESP。不要混淆了...
   0.11的内核能够访问整个内存空间.所以有了用户态栈指针之后就可以直接访问了...
   
   貌似现在研究Linux内核的人蛮少啊... 这样的帖子挂了几天了都没人回答...
   加俺的群吧...  7404853

作者: PCliangtao   发布时间: 2010-08-07

热门下载

更多