进程环境

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");

}
时间: 2024-11-03 21:30:17

进程环境的相关文章

《Unix环境高级编程》读书笔记 第7章-进程环境

1. main函数 int main( int argc, char *argv[] ); argc是命令行参数的数目,包括程序名在内 argv是指向参数的各个指针所构成的数组,即指针数组 当内核执行C程序时(使用exec函数),在调用main前先调用一个特殊的启动例程.可执行程序文件将此启动例程指定为程序的起始地址——这是由连接器设置的,而连接器则是由C编译器调用.启动例程从内核取得命令行参数和环境变量值,然后按上述方式调用main函数做好安排. 2. 进程终止 有8种方式使进程终止,其中5种

读书笔记-APUE第三版-(7)进程环境

本章关注单进程运行环境:启动&终止.参数传递和内存布局等. 进程启动终止 如图所示: 启动:内核通过exec函数执行程序,在main函数运行之前,会调用启动例程(start-up routine),取得命令行参数和环境变量.可以把启动例程理解为exit(main(argc,argv)). 终止:五种正常终止方式(从main方法返回/exit/_exit/最后一个线程返回/最后一个线程退出):三种异常终止方式(abort/接收到信号/最后一个线程接收到取消请求). exit与_exit关系:exi

Unix编程第7章 进程环境

准备雄心勃勃的看完APUE,但是总感觉看着看着就像进入一本字典,很多地方都是介绍函数的用法的,但是给出例子远不及函数介绍的多.而且这本书还是个大部头呢.第7章的讲的进程环境,进程是程序设计中一个比较重要的概念,知道倒是知道它的大概意思,但是其实还是有很多的细节其实都没有深究,这章呢APUE就带着我们逛了一下如下的几个主题(尼玛,学C语言的话,学那点语法其实不是很重要,反而经常把时间浪费在语法的蹩脚处): 1.程序执行的时候main函数是如何被调用的 2.命令行参数是如何传递给新程序的: 3.典型

APUE学习笔记:第七章 进程环境

7.1 引言 本章将学习:当执行程序时,其main函数是如何被调用的:命令行参数是如何传送给执行程序的:典型的存储器布局是什么样式:如何分配另外的存储空间:进程如何使用环境变量:各种不同的进程终止方式等:另外还将说明longjmp和setjmp函数以及它们与栈的交互作用:还将介绍研究进程的资源限制 7.2 main函数 C程序总是从main函数开始执行.当内核执行C程序时,在调用main前先调用一个特殊的启动例程.可执行程序文件将此启动例程指定为程序的起始地址——这是由连接编辑器设置的,而连接编

通过IsDebuggerPesent解说windows PEB进程环境块结构

首先介绍PEB和TEB概念: PEB(Process Environment Block.进程环境块)存放进程信息.每一个进程都有自己的PEB信息.位于用户地址空间. TEB(Thread Environment Block.线程环境块)系统在此TEB中保存频繁使用的线程相关的数据.位于用户地址空间.在比 PEB 所在地址低的地方. 进程中的每一个线程都有自己的一个TEB. 写一个使用IsDebuggerPesent函数的windows程序.用OD打开,断点IsDebuggerPesent函数

通过IsDebuggerPesent讲解windows PEB进程环境块结构

首先介绍PEB和TEB概念: PEB(Process Environment Block,进程环境块)存放进程信息,每个进程都有自己的PEB信息.位于用户地址空间. TEB(Thread Environment Block,线程环境块)系统在此TEB中保存频繁使用的线程相关的数据.位于用户地址空间,在比 PEB 所在地址低的地方.进程中的每个线程都有自己的一个TEB. 写一个使用IsDebuggerPesent函数的windows程序,用OD打开,断点IsDebuggerPesent函数 OD进

windows - 进程 - 进程环境变量

原文链接1 原文链接2 1.进程的环境变量 每个进程都有一个与它关联的环境块(environment block),这是在进程地址空间内分配的一块内存,其中包含字符串类似于: =::=::\... VarName=VarValue\0... \0 除第一个=::=::\外,块中可能还有其他字符串是以等号开头的,这种字符串不作为环境变量使用. 访问环境块的两种方式: 1)调用GetEnvironmentStrings获取完整的环境块 2)CUI程序专用,通过应用程序main入口点函数所接收的TCH

Linux/UNIX之进程环境

进程环境 进程终止 有8种方式使进程终止,当中5中为正常终止,它们是 1)      从main返回 2)      调用exit 3)      调用_exit或_Exit 4)      最后一个线程从其启动例程返回 5)      最后一个线程调用pthread_exit 异常终止有3中方式 6)      调用abort 7)      接到一个信号并终止 8)      最后一个线程对取消请求做出对应 exit函数 #include <stdlib.h> void exit(int

Unix环境高级编程(五)进程环境

本章主要介绍了Unix进程环境,包含main函数是如何被调用的,命令行参数如何传递,存储方式布局,分配存储空间,环境变量,进程终止方法,全局跳转longjmp和setjmp函数及进程的资源限制. main函数的原型为int main(int argc,char *argv[]);其中argc是命令行参数的数目,argv是指向参数的各个指针构成的数组.当内核执行C程序时,使用一个exec函数,在调用main函数前线调用一个特殊的启动例程,从内核获取命令行参数和环境变量. 进程终止分为正常终止和异常

第5章 进程环境(3)_环境表和环境变量

3. 环境表 (1)每个进程都有一个独立的环境表(字符指针数组) (2)初始的环境表继承自父进程 (3)两种访问方式: ①int main(int argc, char* argv[], char* envp[]);  //第3个参数 ②extern char** environ;   //全局变量 4. 环境变量操作函数 (1)getenv:获取环境变量值 头文件 #include<stdlib.h> 函数 char* getenv(const char* name); 返回值 指向与nam