Linux编程入门-进程

进程号

系统允许的最大进程号为“/proc/sys/kernel/pid_max”文件数值-1。查看“/proc/PID/status”文件的PPid字段可获知每个进程的父进程。若某个子进程的父进程终止,则init进程收养该进程,后去getppid返回进程号1。

查看“/proc/PID/cmdline”文件可读取任意进程命令行参数,程序也可用“/proc/self/cmdline”访问自己的命令行参数。GNU C语言库也有提供全局变量:

1
2
3
4
#define _GNU_SOURCE
#include <errno.h>
extern char *program_invocation_name; //调用该程序的完整路径名
extern char *program_invocation_short_name; //不含目录的程序部分

getpid

返回调用进程的进程号:

1
2
#include <unistd.h>
__pid_t getpid(void);

getppid

返回父进程进程号:

1
__pid_t getppid (void);

环境

查看“/proc/PID/environ”文件可访问任意进程环境列表,每条后面以空字符结尾。main函数中的argv和environ指针数组指向的字符串都驻留在进程栈上一个单一连续的内存区域,该区域可存储的字节数上限通过sysconf的_SC_ARG_MAX获取。

getenv

从进程环境中检索单个值:

1
2
3
char* getenv(
const char* __name
); //不存在返回NULL

putenv

向调用进程的环境中添加一个新变量,或修改一个已存在的变量值。该函数将environ变量中某一元素的指向与string参数指向位置相同,如果随后修改string参数所指内容,将影响该进程环境,所以string不应为自动变量(在栈中分配的字符数组),以防定义此变量的函数返回后可能重写这块内存区域。当string不包含一个“\=”则从环境列表中移除string命名的环境变量。

1
2
3
int putenv (
char *__string //形式如“name=value”
); //成功0 失败非0

setenv

向环境中添加一个变量,可代替putenv。该函数为“name\=value”字符串分配一块内存缓冲区并将name和value所指字符串复制到这里,创建一个新的环境变量,不需要手动添加“\=”。若name变量已存在且overwrite为0,则不改变环境,overwrite为非0则总是改变环境。

1
2
3
4
5
int setenv (
const char *__name, //name=value
const char *__value,
int __replace
);

unsetenv

从环境中移除name标识的变量,不含“\=”。

1
2
3
int unsetenv (
const char *__name
); //成功0 失败-1

clearenv

清除环境。

1
2
3
#define _BSD_SOURCE //或_SVID_SOURCE
#include <stdlib.h>
int clearenv (void);

非局部跳转

非局部跳转指跳转目标为当前执行函数之外的某个位置。该小节使用时建议不要启用编译优化,必要局部变量建议使用volatile关键字,用-Wextra选项可提示本小节相关部分警告信息。

setjmp/longjmp

setjmp调用为后续longjmp调用确立了跳转目标。setjmp将当前进程环境各种信息保存到env参数中,调用longjmp时将发起longjmp调用的函数与之前调用setjmp函数之间的函数栈帧从栈上剥离,称为解栈。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <setjmp.h>
#define setjmp(env) _setjmp (env)
typedef long int __jmp_buf[8];
typedef struct {
unsigned long int __val[_SIGSET_NWORDS];
} __sigset_t;
struct __jmp_buf_tag {
/* NOTE: The machine-dependent definitions of `__sigsetjmp' assume that a `jmp_buf' begins with a `__jmp_buf' and that `__mask_was_saved' follows it. Do not move these members or add others before it. */
__jmp_buf __jmpbuf; /* Calling environment. */
int __mask_was_saved; /* Saved the signal mask? */
__sigset_t __saved_mask; /* Saved signal mask. */
};
int _setjmp (
struct __jmp_buf_tag __env[1]
); //初始化返回0 longjmp调用时返回非0
void longjmp (
struct __jmp_buf_tag __env[1],
int __val
);

例子如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <setjmp.h>
//...
static jmp_buf env;
static void f2(void){
longjmp(env,2);
};
static void f1(int argc){
if(argc==1)
longjmp(env,1);
f2();
};
int main(int argc,char* argv[]){
switch(setjmp(env)){
case 0:
printf("calling f1()\n");
f1(argc);
break;
case 1:
printf("back from f1()\n");
break;
case 2:
printf("back from f2()\n");
break;
};
exit(EXIT_SUCCESS);
};

结果大概为:

1
2
3
4
5
6
./longjmp 
calling f1()
back from f1()
./longjmp x
calling f1()
back from f2()