signal hanler 与 user lever thread library
时间:2010-12-29
来源:互联网
本帖最后由 baozhao 于 2010-12-29 08:08 编辑
诸位, 我最近在了解用户级线程库(即M:1模型),发现了一个令我困惑的问题。
用户级线程库必须有user level scheduler,假定我们按轮转方式,每隔一段时间就发一个信号给进程,然后signal hanler 里面实现scheduler,切换到另一个用户态线程(使用longjump 或者setcontext之类的函数)。
但是这里面存在的问题是, 内核栈里面还是上一个用户态线程的信息,尽管用户态能切换到另一个用户态线程,但是内核栈上一个线程的信息并没有清除(Linux正常情况是是在signal handler处理尾部插入sigreturn重新返回内核进行清理,longjmp已经无法达到此目的),这样下去的话,必然会导致问题(反复接到信号,内核栈溢出?)
我发现别人有类似的疑惑,但是没有得到回答,见
http://www.spinics.net/lists/linux-c-programming/msg00623.html
并且
https://www.securecoding.cert.org/confluence/display/seccode/SIG32-C.+Do+not+call+longjmp%28%29+from+inside+a+signal+handler
有明确意见,但是不少线程库的实现确实在signal handler调用了longjmp。
请指出我的理解有何问题?
诸位, 我最近在了解用户级线程库(即M:1模型),发现了一个令我困惑的问题。
用户级线程库必须有user level scheduler,假定我们按轮转方式,每隔一段时间就发一个信号给进程,然后signal hanler 里面实现scheduler,切换到另一个用户态线程(使用longjump 或者setcontext之类的函数)。
但是这里面存在的问题是, 内核栈里面还是上一个用户态线程的信息,尽管用户态能切换到另一个用户态线程,但是内核栈上一个线程的信息并没有清除(Linux正常情况是是在signal handler处理尾部插入sigreturn重新返回内核进行清理,longjmp已经无法达到此目的),这样下去的话,必然会导致问题(反复接到信号,内核栈溢出?)
我发现别人有类似的疑惑,但是没有得到回答,见
http://www.spinics.net/lists/linux-c-programming/msg00623.html
并且
https://www.securecoding.cert.org/confluence/display/seccode/SIG32-C.+Do+not+call+longjmp%28%29+from+inside+a+signal+handler
有明确意见,但是不少线程库的实现确实在signal handler调用了longjmp。
请指出我的理解有何问题?
作者: baozhao 发布时间: 2010-12-29
我的理解是:
进入signal handler以后,并没有什么信息留在内核栈上。被信号中断的那个用户态的上下文是被保存在用户栈上的。而sigreturn要做的事情就是,让调用者指定一个sig上下文信息,然后内核负责把用户恢复到那个上下文去。(还有就是去掉相应的sig mask,这一点siglongjmp也会做。)
在此过程中,内核不需要保存任何中间状态。
关于LZ贴的第一篇文章,longjmp后,应该就不在signal handle context上面了。
进入signal handle的时候,用户态的栈应该是这样的:
=> setjmp时的栈 => ... => 被信号中断时的栈 => 内核放置的sigframe => signal handle的返回地址(去调用sigreturn) => signal handle的栈
如果signal handle正常返回,那么sigreturn被调用,栈上的sigframe被作为参数传递。然后经过sigreturn的折腾,返回用户态时,就回到了“被信号中断的栈”。
而如果signal handle里面longjmp了,那么用户态已经回到了setjmp时的栈上。后面的一系列信息都失效掉了。
当然,对于用户态多线程的情况,并不是这样。因为不同的用户态线程会有不同的栈空间,这时的longjmp会jmp到其他的栈空间,而不是自己栈空间里面靠前的栈。
对于第二篇文章,它要表达的应该是setjmp/longjmp导致函数被重入的问题。线程在自己的栈空间范围内做longjmp,的确有这样的问题,需要小心。
但是longjmp到其他线程的栈空间上呢?逻辑上说,longjmp以后,我们已经到了另一个线程。setjmp/longjmp导致的是一个函数在两个线程里面被并发的访问。如果这个函数不能支持这么做,那么解决办法应该是线程间同步。
进入signal handler以后,并没有什么信息留在内核栈上。被信号中断的那个用户态的上下文是被保存在用户栈上的。而sigreturn要做的事情就是,让调用者指定一个sig上下文信息,然后内核负责把用户恢复到那个上下文去。(还有就是去掉相应的sig mask,这一点siglongjmp也会做。)
在此过程中,内核不需要保存任何中间状态。
关于LZ贴的第一篇文章,longjmp后,应该就不在signal handle context上面了。
进入signal handle的时候,用户态的栈应该是这样的:
=> setjmp时的栈 => ... => 被信号中断时的栈 => 内核放置的sigframe => signal handle的返回地址(去调用sigreturn) => signal handle的栈
如果signal handle正常返回,那么sigreturn被调用,栈上的sigframe被作为参数传递。然后经过sigreturn的折腾,返回用户态时,就回到了“被信号中断的栈”。
而如果signal handle里面longjmp了,那么用户态已经回到了setjmp时的栈上。后面的一系列信息都失效掉了。
当然,对于用户态多线程的情况,并不是这样。因为不同的用户态线程会有不同的栈空间,这时的longjmp会jmp到其他的栈空间,而不是自己栈空间里面靠前的栈。
对于第二篇文章,它要表达的应该是setjmp/longjmp导致函数被重入的问题。线程在自己的栈空间范围内做longjmp,的确有这样的问题,需要小心。
但是longjmp到其他线程的栈空间上呢?逻辑上说,longjmp以后,我们已经到了另一个线程。setjmp/longjmp导致的是一个函数在两个线程里面被并发的访问。如果这个函数不能支持这么做,那么解决办法应该是线程间同步。
作者: kouu 发布时间: 2010-12-29
相关阅读 更多
热门阅读
-
office 2019专业增强版最新2021版激活秘钥/序列号/激活码推荐 附激活工具
阅读:74
-
如何安装mysql8.0
阅读:31
-
Word快速设置标题样式步骤详解
阅读:28
-
20+道必知必会的Vue面试题(附答案解析)
阅读:37
-
HTML如何制作表单
阅读:22
-
百词斩可以改天数吗?当然可以,4个步骤轻松修改天数!
阅读:31
-
ET文件格式和XLS格式文件之间如何转化?
阅读:24
-
react和vue的区别及优缺点是什么
阅读:121
-
支付宝人脸识别如何关闭?
阅读:21
-
腾讯微云怎么修改照片或视频备份路径?
阅读:28