进程环境

main func

当内核启动C程序时,是通过一种exec函数启动的,是一个特殊的start-up routine,在main函数调用之前。该routine会被链接器设定为可执行程序的入口点。

ISO C 和 POSIX.1 规定,argv[argc]是一个null指针。

进程终止

有8种终止进程的方式。
正常的终止方式有:
* Return from main
* Calling exit
* Calling _exit or _Exit
* Return of the last thread from its start routine
* Calling pthread_exit from the last thread

非正常终止的方式有:
* Calling abort
* Receipt(接收) of a signal
* Response of the last thread to a cancellation request

通常,start up routine内会有如下编码:
exit(main(argc, argv));

进程环境

环境变量

大多数UNIX系统还通过如下的main函数声明:
int main(int argc, char *argv[], char *envp[]);

修改环境变量会比较繁琐。
修改一个已存在的变量
* 如果新value的长度小于旧value的长度,则直接copy覆盖即可。
* 如果新value的长度大于旧value的长度,则需要分配新的内存空间以容纳新的value,然后替代env list中的旧指针。

添加新的变量
0. 分配新的内存空间以容纳新的键值对。
* 如果是第一次添加新的变量,则env list一般是指向栈顶前的位置(默认内存布局)。如此的话,则需要在堆中重新分配内存,创建一个新的env list,其中旧变量仍然指向原来的位置。然后添加新的变量到新的env list。最后使environ全局变量置为新的env list。
* 如果不是第一次添加新的变量,则env list已经在堆中。那么只需要calloc拓展更大的内存空间以便容纳新的变量,然后类似上面的步骤施行即可。

C程序内存布局

进程环境
C程序会由以下部分组成:
* Text segment
* Initialized data segment
* Uninitialized data segment
* Stack
* Heap

还有一些其他的部分,但不会加载到进程空间中:
* the symbol table
* debugging information
* linkage tables for dynamic shared libraries
* the like

non-local branching

因为在C语言中,goto只能跳到代码块内的标号。要实现,代码块外的跳转,提供了setjmp和longjmp两个接口。

API

进程终止

exit 终止进程,并执行清理standard I/O资源,ISO C,标准C接口。
_Exit 终止进程,ISO C
_exit 终止进程,POSIX.1,系统接口。
atexit 注册进程终止时调用例程

注册的例程称为exit handler,会在exit中被调用,调用的次序会与注册的次序相反。
ISO C和POSIX.1 都规定,exit首先应该调用注册的exit handlers,然后关闭所有标准I/O流。POSIX.1 还规定,如果程序调用任意一种exec族的接口,所有exit handlers会被清除。

环境变量

extern char **environ

以NULL作为最后一个数组元素。

getenv
putenv
setenv
unsetenv
clearenv

putenv 和 setenv 的区别在于,set会分配内存来创建name=value对,而put会直接把参数地址传到环境变量。如此,可能put会因为使用栈中的数据(临时变量)而导致错误。

内存分配

ISO C

malloc
calloc
realloc
free

这些分配函数得到的空间都是已经对齐的。
这些函数会实际上申请额外的空间用以保存所分配内存块的记录。
这些内存分配函数通常内部会调用sbrk系统调用(用以拓展进程的堆)。

non-local branching

setjmp
longjmp

longjmp不保证会还原调用setjmp时自动变量(automatic variables),寄存器变量(register variables)的状态。
如果要保证automatic variables不被回滚,则应该在其前面加上volatile。
全局变量和静态变量都不会因为longjmp而回滚。
PS: Ubuntu 16.04 & kernel 4.14.32 不会有任何回滚操作。

process resource limits set

getrlimit
setrlimit

会被子进程继承