main函数
内核在通过exec执行main函数之前还会这行启动程序,启动程序地址通常由编译器和链接器在可执行程序中指定。启动程序从内核传递命令行参数以及环境变量传递给main函数以及做一些启动main函数的准备。
进程终止
正常终止:
从main函数返回
调用exit,_exit,_Exit
进程中最后一个线程返回
进程中最后一个线程执行pthread_exit
异常终止:
信号终止
最后一个线程对pthread_cancle作出响应
调用abort
退出函数
_exit(),_Exit()立即退出返回到内核,exit()执行一些清理动作然后返回内核。ISO允许进程注册清理函数,在进程退出的时候以相反的顺序执行这些清理函数,注册多少次执行多少次。
#include <stdlib.h> void exit(int status); void _Exit(int status); #include <unistd.h> void _exit(int status); int atexit(void (*func)(void)); //Returns: 0 if OK, nonzero on error
ISO C规范规定exit函数先执行清理函数然后调用fclose关闭所有标准流。Posix规定如果执行任何exec函数,那么注册的清理函数都会被清除。
环境变量列表
每个程序除了被传递命令行参数外还传递环境变量列表,列表元素是个以\0结尾的字符串,字符串格式如:Key=Value,列表地址是个全局变量:
extern char **environ;
C程序内存布局
C程序一般由文本段,初始化数据段,未初始化数据段,堆,栈,命令行参数和环境变量组成。文本段是机器执行的指令,一般是只读的且共享的,初始化数据指初始化的变量等,未初始化数据在程序执行前由内核初始化为0 或空指针。典型的内存布局如下:
size命令可以打印程序文件代码段,初始化数据段,为初始化数据段大小。
内存分配
#include <stdlib.h> void *malloc(size_t size); void *calloc(size_t nobj, size_t size); void *realloc(void *ptr, size_t newsize); //All three return: non-null pointer if OK, NULL on error void free(void *ptr);
malloc分配指定大小的内存,内存初始值是不能确定
calloc分配nobj个size大小的内存,如果是一般变量内存初始化为0,指针不一定初始化为NULL
realloc增加或减少之前分配的内存,如果增加内存,那么会将以前的内容移动到新的地方,新增加的部分初始值是不确定的。如果ptr为空同malloc.
环境变量
获取指定的环境变量值:
#include <stdlib.h> char *getenv(const char *name); //Returns: pointer to value associated with name, NULL if not found
设置环境变量:
#include <stdlib.h> int putenv(char *str);//str is like name=value,if name already exist ,remove it first //Returns: 0 if OK, nonzero on error int setenv(const char *name, const char *value, int rewrite);//nozero rewite, 0 not int unsetenv(const char *name);//remove the name=value do not care weather name exist //Both return: 0 if OK, −1 on error
局部跳转(超级goto)
#include <setjmp.h> int setjmp(jmp_buf env); //Returns: 0 if called directly, nonzero if returning from a call to longjmp void longjmp(jmp_buf env, int val);
在希望跳转到的地方调用setjmp,直接调用将返回0,jum_buf类型是一种特殊数组,包含了能够恢复调用longjump时的栈状态所有信息。在我们希望跳转的时候传递两个参数给longjmp一个是前面的env后面一个是非0值,这个值将作为setjmp的返回值。
在longjmp返回到setjmp所在函数后,setjmp所在函数中栈变量和寄存器变量值是不确定的。如果想使用栈变量又不想回滚它的值将他定义为volatile.申明为全局变量或者静态变量的值在执行longjmp时不变。
#include <stdio.h> #include <stdlib.h> #include <setjmp.h> static void f1(int ,int,int,int); static void f2(); static jmp_buf jmpbuffer; static int globval; int main(int argc,char* argv[]) { int autoval; register int regival; volatile int volaval; static int staval; globval =1;autoval=2;regival=3;volaval=4;staval=5; if(setjmp(jmpbuffer)!= 0) { printf("after longjmp:\n"); printf("globval = %d,autoval=%d,regival=%d,volaval=%d,staval=%d\n", globval,autoval,regival,volaval,staval); exit(0); } globval = 95;autoval=96;regival=97;volaval=98;staval=99; f1(autoval,regival,volaval,staval); exit(0); } static void f1(int i,int j,int k,int l) { printf("int f1:\n"); printf("globval=%d,autoval=%d,regival=%d,volaval=%d,staval=%d\n",globval,i,j,k,l); f2(); } static void f2() { longjmp(jmpbuffer,1); }
执行结果:
[email protected]:~$ gcc -o test test.c [email protected]:~$ ./test int f1: globval=95,autoval=96,regival=97,volaval=98,staval=99 after longjmp: globval = 95,autoval=96,regival=3,volaval=98,staval=99 [email protected]:~$ gcc -O2 -o test test.c [email protected]:~$ ./test int f1: globval=95,autoval=96,regival=97,volaval=98,staval=99 after longjmp: globval = 95,autoval=2,regival=3,volaval=98,staval=99
优化执行代码和不优化执行代码,结果不一样。全局变量,静态变量,寄存器变量不受优化影响。
资源限制
每个进程都有一组资源限制,其总一些可以通过gerrlimit和setrlimit来查询和更改。
#include <sys/resource.h> int getrlimit(int resource, struct rlimit *rlptr); int setrlimit(int resource, const struct rlimit *rlptr); //Both return: 0 if OK, −1 on error
rlimit结构如下:
struct rlimit { rlim_t rlim_cur; /* Soft limit */ rlim_t rlim_max; /* Hard limit (ceiling for rlim_cur) */ };
在更改资源限制时必须遵循下面规则:
任何一个进程可以将一个软限制指改为小于等于其硬限制值
任何一个进程都可降低硬限制值,但是必须大于等于软限制值。这中更改对普通用户是不可逆的
超级用户可以提高硬限制值
#include <stdio.h> #include <sys/resource.h> #define FMT "%10lld " #define doit(name) pr_limits(#name,name) static void pr_limits(char*,int); int main(int argc,char* argv[]) { doit(RLIMIT_AS); doit(RLIMIT_CORE); doit(RLIMIT_CPU); doit(RLIMIT_DATA); doit(RLIMIT_FSIZE); doit(RLIMIT_NOFILE); doit(RLIMIT_RSS); } static void pr_limits(char* name,int resource) { struct rlimit limit; if(getrlimit(resource,&limit) < 0) { printf("get resource limit faild\n"); return ; } printf("%-14s ",name); if(limit.rlim_cur == RLIM_INFINITY ) { printf("infility\n"); }else { printf(FMT,(long long)limit.rlim_cur); } if(limit.rlim_max == RLIM_INFINITY ) { printf("infility\n"); }else { printf(FMT,(long long)limit.rlim_max); } printf("\n"); }