免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12
最近访问板块 发新帖
楼主: _nosay

[内核入门] 为什么每个进程要在内核中有一个栈? [复制链接]

论坛徽章:
13
15-16赛季CBA联赛之八一
日期:2016-07-08 21:00:1415-16赛季CBA联赛之同曦
日期:2017-02-15 14:26:1515-16赛季CBA联赛之佛山
日期:2017-02-20 14:19:2615-16赛季CBA联赛之青岛
日期:2017-05-07 16:49:1115-16赛季CBA联赛之广夏
日期:2017-07-30 09:13:1215-16赛季CBA联赛之广东
日期:2018-07-05 22:34:3615-16赛季CBA联赛之江苏
日期:2018-09-03 12:10:2115-16赛季CBA联赛之上海
日期:2018-09-25 03:49:2215-16赛季CBA联赛之广东
日期:2018-09-25 04:09:12
发表于 2017-07-04 10:14 |显示全部楼层
回复 10# mordorwww

栈在task_struct结构后面,我问的是栈可不可以公用,task_struct当然每个进程要有一个。。

论坛徽章:
9
程序设计版块每日发帖之星
日期:2016-02-13 06:20:00数据库技术版块每日发帖之星
日期:2016-06-15 06:20:00数据库技术版块每日发帖之星
日期:2016-06-16 06:20:00数据库技术版块每日发帖之星
日期:2016-06-18 06:20:00程序设计版块每日发帖之星
日期:2016-06-27 06:20:00程序设计版块每日发帖之星
日期:2016-07-09 06:20:00IT运维版块每日发帖之星
日期:2016-07-15 06:20:00IT运维版块每日发帖之星
日期:2016-07-27 06:20:00程序设计版块每日发帖之星
日期:2016-08-18 06:20:00
发表于 2017-07-04 15:51 |显示全部楼层
_nosay 发表于 2017-07-04 10:14
回复 10# mordorwww

栈在task_struct结构后面,我问的是栈可不可以公用,task_struct当然每个进程要有 ...

你看看进程IO阻塞时的处理就知道了

论坛徽章:
13
15-16赛季CBA联赛之八一
日期:2016-07-08 21:00:1415-16赛季CBA联赛之同曦
日期:2017-02-15 14:26:1515-16赛季CBA联赛之佛山
日期:2017-02-20 14:19:2615-16赛季CBA联赛之青岛
日期:2017-05-07 16:49:1115-16赛季CBA联赛之广夏
日期:2017-07-30 09:13:1215-16赛季CBA联赛之广东
日期:2018-07-05 22:34:3615-16赛季CBA联赛之江苏
日期:2018-09-03 12:10:2115-16赛季CBA联赛之上海
日期:2018-09-25 03:49:2215-16赛季CBA联赛之广东
日期:2018-09-25 04:09:12
发表于 2017-07-04 16:22 |显示全部楼层
回复 12# mordorwww

好的

论坛徽章:
22
丑牛
日期:2014-08-15 14:32:0015-16赛季CBA联赛之同曦
日期:2017-12-14 15:28:14黑曼巴
日期:2017-08-10 08:14:342017金鸡报晓
日期:2017-02-08 10:39:42黑曼巴
日期:2016-11-15 15:48:38CU十四周年纪念徽章
日期:2016-11-09 13:19:1015-16赛季CBA联赛之同曦
日期:2016-04-08 18:00:03平安夜徽章
日期:2015-12-26 00:06:30程序设计版块每日发帖之星
日期:2015-12-03 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-09 06:20:002015亚冠之吉达阿赫利
日期:2015-07-03 08:39:42
发表于 2017-07-04 18:47 |显示全部楼层
进去的 A 进程,出来的可以是 B 进程。
如果只保留了一个进程的上下文,那么什么进入就要什么出来。这就不是多任务的操作系统了

论坛徽章:
13
15-16赛季CBA联赛之八一
日期:2016-07-08 21:00:1415-16赛季CBA联赛之同曦
日期:2017-02-15 14:26:1515-16赛季CBA联赛之佛山
日期:2017-02-20 14:19:2615-16赛季CBA联赛之青岛
日期:2017-05-07 16:49:1115-16赛季CBA联赛之广夏
日期:2017-07-30 09:13:1215-16赛季CBA联赛之广东
日期:2018-07-05 22:34:3615-16赛季CBA联赛之江苏
日期:2018-09-03 12:10:2115-16赛季CBA联赛之上海
日期:2018-09-25 03:49:2215-16赛季CBA联赛之广东
日期:2018-09-25 04:09:12
发表于 2017-07-04 19:46 |显示全部楼层
回复 14# amarant

求个人理解我。。
进程切换走时,保存进程上下文的是task_struct结构所占的那块空间,而不是进程的内核栈,虽然分配时它们是挨在一起的。


先确定2个问题(单CPU的前提下):
1. 进程A、进程B可能同时在内核态吗?(不可能)2. 进程A切换到进程B后,进程A的内核栈还有内容吗?(没有)


然后假设A、B是两个人,他们各自有一个办公室:
根据1=>A、B不可能同时在办公室;
根据2=>A、B离开办公室时,不可能在里面留自己的私人物品。
这样,其实只要建一间办公室不就行了吗,否则A上班时,B的办公室白白空着,B上班时,A的办公室白白空着。。

论坛徽章:
13
15-16赛季CBA联赛之八一
日期:2016-07-08 21:00:1415-16赛季CBA联赛之同曦
日期:2017-02-15 14:26:1515-16赛季CBA联赛之佛山
日期:2017-02-20 14:19:2615-16赛季CBA联赛之青岛
日期:2017-05-07 16:49:1115-16赛季CBA联赛之广夏
日期:2017-07-30 09:13:1215-16赛季CBA联赛之广东
日期:2018-07-05 22:34:3615-16赛季CBA联赛之江苏
日期:2018-09-03 12:10:2115-16赛季CBA联赛之上海
日期:2018-09-25 03:49:2215-16赛季CBA联赛之广东
日期:2018-09-25 04:09:12
发表于 2017-07-04 20:03 |显示全部楼层
回复 14# amarant

还是说,进程A从内核态返回用户态时,内核栈为空,但切换到进程B时,要在内核栈保存某些东西?

论坛徽章:
13
15-16赛季CBA联赛之八一
日期:2016-07-08 21:00:1415-16赛季CBA联赛之同曦
日期:2017-02-15 14:26:1515-16赛季CBA联赛之佛山
日期:2017-02-20 14:19:2615-16赛季CBA联赛之青岛
日期:2017-05-07 16:49:1115-16赛季CBA联赛之广夏
日期:2017-07-30 09:13:1215-16赛季CBA联赛之广东
日期:2018-07-05 22:34:3615-16赛季CBA联赛之江苏
日期:2018-09-03 12:10:2115-16赛季CBA联赛之上海
日期:2018-09-25 03:49:2215-16赛季CBA联赛之广东
日期:2018-09-25 04:09:12
发表于 2017-07-04 21:07 |显示全部楼层
回复 14# amarant

schedule()确实在restore_all之前调用:
  1. ENTRY(ret_from_intr)
  2.     GET_CURRENT(%ebx)
  3.     movl EFLAGS(%esp), %eax
  4.     movb CS(%esp), %al
  5.     testl $(VM_MASK|3), %eax
  6.     jne ret_with_reschedule
  7.     jmp restore_all
复制代码

为什么切换之前,要push esi、edi、dbp ?
  1. #define switch_to(prev,next,last) do {                                        \
  2.         asm volatile("pushl %%esi\n\t"                                        \
  3.     "pushl %%edi\n\t"                                        \
  4.     "pushl %%ebp\n\t"                                        \
  5.     "movl %%esp,%0\n\t"        /* save ESP */                \
  6.     "movl %3,%%esp\n\t"        /* restore ESP */        \
  7.     "movl $1f,%1\n\t"                /* save EIP */                \
  8.     "pushl %4\n\t"                /* restore EIP */        \
  9.     "jmp __switch_to\n"                                \
  10.     "1:\t"                                                \
  11.     "popl %%ebp\n\t"                                        \
  12.     "popl %%edi\n\t"                                        \
  13.     "popl %%esi\n\t"                                        \
  14.     :"=m" (prev->thread.esp),"=m" (prev->thread.eip),        \
  15.      "=b" (last)                                        \
  16.     :"m" (next->thread.esp),"m" (next->thread.eip),        \
  17.      "a" (prev), "d" (next),                                \
  18.      "b" (prev));                                        \
  19. } while (0)
复制代码


论坛徽章:
22
丑牛
日期:2014-08-15 14:32:0015-16赛季CBA联赛之同曦
日期:2017-12-14 15:28:14黑曼巴
日期:2017-08-10 08:14:342017金鸡报晓
日期:2017-02-08 10:39:42黑曼巴
日期:2016-11-15 15:48:38CU十四周年纪念徽章
日期:2016-11-09 13:19:1015-16赛季CBA联赛之同曦
日期:2016-04-08 18:00:03平安夜徽章
日期:2015-12-26 00:06:30程序设计版块每日发帖之星
日期:2015-12-03 06:20:002015七夕节徽章
日期:2015-08-21 11:06:17IT运维版块每日发帖之星
日期:2015-08-09 06:20:002015亚冠之吉达阿赫利
日期:2015-07-03 08:39:42
发表于 2017-07-05 09:00 |显示全部楼层
本帖最后由 amarant 于 2017-07-05 13:13 编辑
1. 进程A、进程B可能同时在内核态吗?(不可能)

当然可以。即使在不考虑多 CPU,在单 CPU 的系统也是可以的。例如 A 进程因为中断进入到 kernel,在退出 kernel 前会检查调度情况,这时候发生应该让 B 进程跑,那么出去的就是 B 了。以这样的逻辑,所有的进程在内核态都有一个描述符。如果说严格意义上时间的”同时“,那么因为 CPU 一个时刻只能执行一条指令(不考虑多发射,多线程等技术),一个 CPU 的状态只能在一个线程的上下文里。没有同时的说法。

2. 进程A切换到进程B后,进程A的内核栈还有内容吗?(没有)

必须的有内容呀。user space 的寄存器上下文都在栈里面呢。要等恢复到 user space 后,这些栈的内容才算无效了。

还是说,进程A从内核态返回用户态时,内核栈为空,但切换到进程B时,要在内核栈保存某些东西?
然后假设A、B是两个人,他们各自有一个办公室:
根据1=>A、B不可能同时在办公室;
根据2=>A、B离开办公室时,不可能在里面留自己的私人物品。
这样,其实只要建一间办公室不就行了吗,否则A上班时,B的办公室白白空着,B上班时,A的办公室白白空着。。

按你这样的逻辑,其实你就是认为从用户层进入到kernel space的时候,所有的寄存器状态都保存在 task_struct 里面,所以栈里没有有用的东西。当需要恢复的时候,直接去task_struct里面取出来。
x86的代码我没看过,arm64是把寄存器保存在栈里面的。
其实无论保存在栈里还是task_struct里,总是要有一些内存用来保存这些数据。那么保存在哪里其实不重要。
保存在栈里其实还更方便,每次切换进程上下文,只需要改一下栈指针。

还是说,进程A从内核态返回用户态时,内核栈为空,但切换到进程B时,要在内核栈保存某些东西?

返回到用户态,属于从异常恢复。直接把内核栈里面的所有寄存器恢复回来即可。
切换别的进程,因为每一个进程都有自己的内核栈,切换进程只需要改一下栈指针(通过 schedule 把保存在 task_struct 里面的 sp 以及其他一些非易失性寄存器恢复回来)。

论坛徽章:
13
15-16赛季CBA联赛之八一
日期:2016-07-08 21:00:1415-16赛季CBA联赛之同曦
日期:2017-02-15 14:26:1515-16赛季CBA联赛之佛山
日期:2017-02-20 14:19:2615-16赛季CBA联赛之青岛
日期:2017-05-07 16:49:1115-16赛季CBA联赛之广夏
日期:2017-07-30 09:13:1215-16赛季CBA联赛之广东
日期:2018-07-05 22:34:3615-16赛季CBA联赛之江苏
日期:2018-09-03 12:10:2115-16赛季CBA联赛之上海
日期:2018-09-25 03:49:2215-16赛季CBA联赛之广东
日期:2018-09-25 04:09:12
发表于 2017-07-05 09:36 |显示全部楼层
回复 18# amarant

我已经在17楼承认错误了进程A的内核态切换到进程B的用户态,相当于这时进程A还是在内核态,等着从另外一个进程的内核态,切换到进程A的用户态时,栈才会被清空。

蟹蟹mordorwwwamarant版主

论坛徽章:
0
发表于 2017-11-23 10:18 |显示全部楼层
路过而已,就看看您们的水平,不错,赞
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP