无忧启动论坛

 找回密码
 注册
搜索
系统gho:最纯净好用系统下载站投放广告、加入VIP会员,请联系 微信:wuyouceo
楼主: 不点
打印 上一主题 下一主题

cish 开发构想

    [复制链接]
151#
 楼主| 发表于 2018-6-13 20:13:35 | 只看该作者
总结一下,这段时间面向 C 语言命令行解释器,算是完整实现了 IO 重定向以及管道。IO 重定向函数有三个:fin,fout,ferr。管道函数有两个:pad,pen。

接下来还需要实现面向 shell 解释器的 IO 重定向和管道。初步设想,最好是能够利用前面的fin,fout,ferr,pad,pen 等成果,来减轻工作量。


回复

使用道具 举报

152#
 楼主| 发表于 2018-6-15 06:55:36 | 只看该作者
前些天实现的管道,其各个成员函数是先后独立运行的,因为使用了 clone 函数的 CLONE_VFORK 控制标志。

按先后顺序运行各个管道成员,后一个成员需要等待前一个成员运行结束之后才能开始运行——这样的管道还不是一个真正的管道。于是,昨天我去掉 CLONE_VFORK 标志。然而,去掉之后,管道代码崩溃了。排错排得头痛。通过插入大量调试代码定位出错地点,问题逐渐明朗起来。原来我不知不觉已经进入 “线程” 编程的领地。不同的线程共用了很多变量,这些变量不知什么时候就会被另一个线程修改,这就带来问题了。我原先从来都没有考虑线程互相影响的问题。因此,需要查漏补缺,找到那些受影响的代码并加以完善。
回复

使用道具 举报

153#
 楼主| 发表于 2018-6-15 18:54:15 | 只看该作者
clone 函数功能是很强大。然而 clone 函数需要为子进程分配一个堆栈空间(child stack)。困难不在于如何确定需要多大的空间,而在于究竟应该在何时释放掉这个空间。尽量分配稍大的空间,满足大多数情况即可。我为子进程分配 1M 的堆栈空间。如果子进程自己需要占据超大的空间,那么,子进程自己应该重新分配堆栈空间,并切换到新的堆栈。所以,堆栈大小的问题,倒不算是问题。然而,何时释放堆栈空间?子进程自己能够释放它吗?

提出这样一个问题:父进程在用 clone 启动了子进程之后立即崩溃了。此时子进程还活着。注意,子进程的堆栈是由父进程分配的,也就是说,它存在于父进程的内存空间里面。现在父进程不存在了,那么,子进程还能正常运行吗?

clone 的 man page 并未讲到何时释放堆栈空间的问题。有些问题,google 上也找不到解答。
回复

使用道具 举报

154#
 楼主| 发表于 2018-6-16 09:05:42 | 只看该作者
本帖最后由 不点 于 2018-6-16 11:08 编辑

一去掉 CLONE_VFORK 就导致 cish 崩溃的问题,已经解决。正如先前的分析,问题确实是因不同的线程分别写入某些敏感的共有变量造成的。解决的办法是,让这些敏感的共有变量成为局部变量,或者把它们放在函数的参数表中进行传递,这就避免了互相影响。

在下面的测试中,管道的第一个成员每隔 5 秒打印出 See i=<序号>(从 0 到 9)。管道的第二个成员就是 cat 命令。运行结果,不是像以前那样(错误地)先等待 50 秒,然后一次性打印出 10 行;而是立即开始打印,每隔 5 秒打印一次。这说明管道两边已经是都在运行了,而不是先运行左边的成员函数(即第一个成员函数),等待它彻底结束后才运行右边的成员函数(即第二个成员函数)。


  1. user@ttyd:~$ cish
  2. [cling]$ pad([]{for (int i=0;i<10;i++){printf("See i=%d\n",i);sleep(5);}})
  3. (int) 0, 0, 0x00000000, 0
  4. [cling]% pen([]{shellInterpreter("cat");})
  5. See i=0
  6. See i=1
  7. See i=2
  8. See i=3
  9. See i=4
  10. See i=5
  11. See i=6
  12. See i=7
  13. See i=8
  14. See i=9
  15. (int) 0, 0, 0x00000000, 0
  16. [cling]% exit
  17. user@ttyd:~$
复制代码


再看一例。在下面的测试中,管道中的两个成员各自休息 15 秒,什么也不做。运行结果,不是像以前那样(错误地)等待 30 秒才结束,而是(正确地)等待 15 秒就结束了。这说明管道两边是并行运行的,而不是先运行左边的成员函数(即第一个成员函数),等待它彻底结束后才运行右边的成员函数(即第二个成员函数)。


  1. user@ttyd:~$ cish
  2. [cling]$ pad([]{sleep(15);})
  3. (int) 0, 0, 0x00000000, 0
  4. [cling]% pen([]{sleep(15);})
  5. (int) 0, 0, 0x00000000, 0
  6. [cling]% exit
  7. user@ttyd:~$
复制代码

回复

使用道具 举报

155#
 楼主| 发表于 2018-6-27 16:37:53 | 只看该作者
前面谈到 bash 重定向语法 2>&1(把标准错误重定向到标准输出)。然而,bash 没有同时把标准输出和标准错误进行交换的语法。要想达到这个目的,需要这样: 3>&1  1>&2  2>&3 ,这里使用了一个额外的文件号 3。然而在 cish 中是不行的。为什么呢?因为 cish 的重定向操作,是在当前进程中——文件号 3 可能早被使用了。任何一个文件号都不能随便拿来当成临时文件号来用(因为它就像 3 那样可能早已被使用了)。

权衡了好多天,觉得不太容易做。目前感觉貌似应该添加一个新的语法,就像这样:1<>2 或 2<>1,意思是交换两个文件号。这样做的好处是,不需要借用(因而也不会污染)中间文件号 3 了。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|捐助支持|无忧启动 ( 闽ICP备05002490号-1 )

闽公网安备 35020302032614号

GMT+8, 2025-12-10 18:32

Powered by Discuz! X3.3

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表