C程序布局
在文件中:正文段(机器指令) text,初始化数据段 data,未初始化数据段 bss
在内存中:(低地址)text,data,bss,堆(向高地址生长)……(向低地址生长)栈,命令行参数,环境变量(高地址)
环境变量
char *getenv (const char *__name);
int putenv (char *__string);
int setenv (const char *__name, const char *__value, int __replace);
int unsetenv (const char *__name);
int clearenv (void);
退出程序
int atexit (void (*__func) (void));
void exit (int __status);
void _Exit (int __status);
void _exit (int __status);
setjmp()和longjmp()
int _setjmp (struct __jmp_buf_tag __env[1]);
void longjmp (struct __jmp_buf_tag __env[1], int __val);
jmp_buf jmpbuffer;
int main() {
volatile int volaval; // 内存变量,寄存器变量无法恢复上下文
switch(setjmp(jmpbuffer)) { // label_0
case 0: // label_1
longjmp(jmpbuffer, 1); // goto label_0, label_2
case 1: // label_2
longjmp(jmpbuffer, 2); // goto label_0, label_3
case 2: // label_3
// ...
}
}
进程标识
// 进程 ID
__pid_t getpid (void);
// 父进程 ID
__pid_t getppid (void);
// 实际用户 ID
__uid_t getuid (void);
// root 设置实际用户 ID、有效用户 ID、保存的设置用户 ID;非 root 只设置有效用户 ID 且 uid 必须等于实际用户 ID 或保存的设置用户 ID
int setuid (__uid_t __uid);
// 实际组 ID
__gid_t getgid (void);
// 类似 setuid()
int setgid (__gid_t __gid);
// 有效用户 ID
__uid_t geteuid (void);
// 设置有效用户 ID,非 root 时 uid 必须等于实际用户 ID 或保存的设置用户 ID
int seteuid (__uid_t __uid);
// 有效组 ID
__gid_t getegid (void);
// 类似 seteuid()
int setegid (__gid_t __gid);
// 交换实际用户 ID 和有效用户 ID
int setreuid (__uid_t __ruid, __uid_t __euid);
// 类似 setreuid()
int setregid (__gid_t __rgid, __gid_t __egid);
// 进程组 ID
__pid_t getpgrp (void);
__pid_t getpgid (__pid_t __pid);
// 将 pid 加入 pgid,如果相等表示创建新的进程组
int setpgid (__pid_t __pid, __pid_t __pgid);
fork()后子进程继承父进程的:
- 打开文件(文件描述符,相当于直接dup,共享同一偏移量)
- 实际用户ID、实际组ID、有效用户ID、有效组ID、附属组ID
- 进程组ID、会话ID
- 控制终端
- 设置用户ID标志和设置组ID标志
- 当前目录和根目录
- 文件模式创建屏蔽字(umask)
- 信号屏蔽和安排
- 对任意打开文件描述符的的close-on-exec标志
- 环境
- 连接的共享存储段
- 存储映像
- 资源限制
exec()系列函数
int execl (const char *__path, const char *__arg, ... /*, NULL */);
int execle (const char *__path, const char *__arg, ... /*, NULL, char *const __envp[] */);
int execlp (const char *__file, const char *__arg, ... /*, NULL */);
int execv (const char *__path, char *const __argv[]);
int execve (const char *__path, char *const __argv[], char *const __envp[]);
int execvp (const char *__file, char *const __argv[]);
int fexecve (int __fd, char *const __argv[], char *const __envp[]);
wait()系列函数
#define WIFEXITED(status)
#define WIFSIGNALED(status)
#define WIFSTOPPED(status)
#define WIFCONTINUED(status)
__pid_t wait (__WAIT_STATUS __stat_loc);
__pid_t waitpid (__pid_t __pid, int *__stat_loc, int __options /* = WNOHANG */);
int waitid (idtype_t __idtype /* = P_PID or P_PGID or P_ALL */, __id_t __id, siginfo_t *__infop, int __options);
__pid_t wait3 (__WAIT_STATUS __stat_loc, int __options, struct rusage * __usage);
__pid_t wait4 (__pid_t __pid, __WAIT_STATUS __stat_loc, int __options, struct rusage *__usage);
进程调度(优先级)、进程时间
int nice (int __inc);
int getpriority (__priority_which_t __which, id_t __who);
int setpriority (__priority_which_t __which, id_t __who, int __prio);
clock_t times (struct tms *__buffer);
解释器文件
假设解释器文件内容是:
#! /bin/awk -f
...
调用时:
# myscript arg1 arg2
实际调用:
# /bin/awk -f myscript arg1 arg2
进程组织
- 会话包含多个进程组,进程组包含多个进程
- 一个会话有一个控制终端(比如 shell),有一个前台进程组,多个后台进程组,只有前台进程组才能接收到 CTRL+C 之类的信号
- 终端输入和产生的信号会向前台进程组中所有进程发送
- 作业与会话类似,shell 中用 & 启动进程时,实际是就是后台进程组,用 | 管道连接时,这条命令中所有进程属于同一个进程组