由Busybox升级引发的一次对Printf的探寻

    作为一名在嵌入式领域从事多年软件开发的RD,我不得不承认:有时对与一些司空见惯的事物,细究起来是知之甚少!

    公司一直使用Linux作为软件平台,使用BusyBox作为基本工具集。最近,Busybox从1.00版本升级到1.2.26, 以前使用旧版Busybox时,系统在Init阶段启动的一些进程在Init完成后,"printf"输出的信息不会显示。升级到1.2.26后,这些信息在Init完成后变的又可以显示。问题本身不是什么重大的功能上的Bug,但是其背后隐含的“printf”的运作机理值得一探究竟!

    “printf”--这个被无数程序员使用无数次的函数有时显得有点神秘。"printf"函数实质上是向1号文件(标准输出)描述符写一串字符。为什么旧版的BusyBox在Init过程中和Init完成后会有差异? Busybox的升级为什么又会影响到"printf"的行为,它是如何施加这些影响的?带着这些疑问,我最终将问题归结到BusyBox中init进程的实现上。

    BusyBox 1.00:在旧版的实现中,init会为每一个要执行的程序创建一个会话并为之打开终端设备作为标准输出。该终端设备通常情况下会作为控制终端被打开,而该控制终端对应的的会话首进程一旦退出,在该终端上已经打开的所有文件会被重定向到挂起终端上,导致后续输出不会再显示。具体细节参见TTY驱动(tty_io.c),这也解释了旧版在Init后,“printf”无法显示的问题。

    BusyBox 1.2.26: 在新版的实现中, init仍会为每一个要执行的程序创建一个会话并为之打开终端设备作为标准输出,但该终端设备通常情况下会不作为控制终端被打开,因为通常打开的是控制台设备,在TTY驱动中,控制台不会以控制终端打开,所以会话首进程退出时,已经打开的文件描述符(包括标准输出)的行为不会受到影响。

    通过对BusyBox不同版本实现的比较分析,printf的行为实际上受到很多因素的影响:调用该函数的进程,该进程所在的会话、进程组,标准输出所对应的终端设备、该终端设备的特性等等。

    由此推知,我们所常用的函数背后可能潜藏着巨大的秘密,在合适的时机有待我们去发掘!



你可能感兴趣的:(原创)