进程标识pid
id=0的是调度进程(swapper),该进程是内核的一部分,并不执行磁盘的任何的程序,也被称为系统进程 id=1 是init进程,属于用户态进程,但是以超级用户特权运行,是所有孤儿进程的父进程
#include <unistd.h> pid_t getpid(void); Returns: process ID of calling process pid_t getppid(void); Returns: parent process ID of calling process uid_t getuid(void); Returns: real user ID of calling process uid_t geteuid(void); Returns: effective user ID of calling process gid_t getgid(void); Returns: real group ID of calling process gid_t getegid(void); Returns: effective group ID of calling process
#include <unistd.h> int setuid(uid_t uid); int setgid(gid_t gid); Both return: 0 if OK, ?1 on error
#include <unistd.h> int setreuid(uid_t ruid, uid_t euid); int setregid(gid_t rgid, gid_t egid); Both return: 0 if OK, ?1 on error
fork
#include <unistd.h> pid_t fork(void); Returns: 0 in child, process ID of child in parent, ?1 on error
fork函数调用一次,返回两次,其中返回0是child进程,pid>0则是子进程的pid.内核一般保存父进程的区域堆栈,数据段的完全副本,且副本的访问权限只读,父进程或者子进程试图修改的话,内核就会建立修改区域的副本,(Copyy-On-Write)
wait and waitpid
#include <sys/wait.h> pid_t wait(int *statloc); pid_t waitpid(pid_t pid, int *statloc, int options); /* Wait for a child to die. When one does, put its status in *STAT_LOC and return its process ID. For errors, return (pid_t) -1.
This function is a cancellation point and therefore not marked with __THROW. */ extern __pid_t wait (int *__stat_loc);
void tl::testProcess(){
auto preStatus = [](int status)->void {
if (WIFEXITED(status))
printf("normal termination, exit status = %d\n",
WEXITSTATUS(status));
else if (WIFSIGNALED(status))
printf("abnormal termination, signal number = %d%s\n",
WTERMSIG(status),
#ifdef WCOREDUMP
WCOREDUMP(status) ? " (core file generated)" : "");
#else
"");
#endif
else if (WIFSTOPPED(status))
printf("child stopped, signal number = %d\n",
WSTOPSIG(status));
};
pid_t pid;
int status;
if ((pid = fork()) < 0) {
err_sys("fork error");
}
else if (pid == 0)
exit(7);
if (wait(&status) != pid)
err_sys("wait error");
preStatus(status);
if ((pid = fork()) < 0) {
err_sys("fork error");
}
else if (pid == 0)
abort();
if (wait(&status) != pid)
err_sys("wait error");
preStatus(status);
if ((pid = fork()) < 0) {
err_sys("fork error");
}
else if (pid == 0)
status /= 0;
if (wait(&status) != pid)
err_sys("wait error");
preStatus(status);
exit(0);
}
result:
└─$ ./tl.out
normal termination, exit status = 7
abnormal termination, signal number = 6
abnormal termination, signal number = 8
exec
该函数会创建一个进程,该进程完全取代原来的进程,从新进程的main开始执行
#include <unistd.h> int execl(const char *pathname, const char arg0, … / (char *)0 */ ); int execv(const char *pathname, char *const argv[]); int execle(const char *pathname, const char arg0, … / (char *)0, char *const envp[] */ ); int execve(const char *pathname, char *const argv[], char *const envp[]); int execlp(const char *filename, const char arg0, … / (char *)0 */ ); int execvp(const char *filename, char *const argv[]); int fexecve(int fd, char *const argv[], char *const envp[]); All seven return: ?1 on error, no return on success
#include "log/logx.h"
#include <error.h>
#include<sys/wait.h>
#include <sys/resource.h>
#include <string.h>
void test();
int main() {
test();
}
void test() {
if (execl("/usr/bin/cal", "cal",nullptr) < 0) {
LOGXF("error", strerror(errno));
}
else LOGXA("start succeed");
}
用户标识
char *getlogin(void); char *getuid(void);
#include "log/logx.h"
#include <error.h>
#include<sys/wait.h>
void test();
int main() {
test();
}
void test() {
LOGXA(VAR_DATA(getlogin()));
LOGXA(VAR_DATA(getuid()));
}
进程调度
int nice(int incr); Returns: new nice value ? NZERO if OK, ?1 on error 只会影响自己的值,不会影响其他进程的,incr越小优先级越大,系统会自动调整到合适的值
#include <sys/resource.h> int getpriority(int which, id_t who); Returns: nice value between ?NZERO and NZERO?1 if OK, ?1 on error
#include <sys/resource.h> int setpriority(int which, id_t who, int value); Returns: 0 if OK, ?1 on error
#include "log/logx.h"
#include <error.h>
#include<sys/wait.h>
#include <sys/resource.h>
void test();
int main() {
test();
}
void test() {
int result = nice(20);
LOGXA(VAR_DATA(result));
result = getpriority(PRIO_PROCESS, 0);
LOGXA(VAR_DATA(result));
result= setpriority(PRIO_PROCESS, 0, 25);
LOGXA(VAR_DATA(result));
result = getpriority(PRIO_PROCESS, 0);
LOGXA(VAR_DATA(result));
}
┌──(kali?kali)-[~/…/TestLinux/bin/x64/Debug]
└─$ ./TestLinux.out
[+] log construction, can use it /home/kali/projects/TestLinux/bin/x64/Debug/_log/log.html
[0]09:01:18[info][140028126343552] [test] result: 19 (test_main.cpp:14)
[1]09:01:18[info][140028126343552] [test] result: 19 (test_main.cpp:16)
[2]09:01:18[info][140028126343552] [test] result: 0 (test_main.cpp:18)
[3]09:01:18[info][140028126343552] [test] result: 19 (test_main.cpp:20)
[+] ~log deconstruction
进程关系
进程组
pid_t getpgrp(void); //获取进程组的gid
#include "log/logx.h"
#include <error.h>
#include<sys/wait.h>
#include <sys/resource.h>
void test();
int main() {
test();
}
void test() {
while (true){
LOGXD(getpgrp());
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
pid_t getpgid(pid_t pid); getpgid(0) == getpgrp() int setpgid(pid_t pid, pid_t pgid);
#include "log/logx.h"
#include <error.h>
#include<sys/wait.h>
#include <sys/resource.h>
void test();
int main() {
test();
}
void test() {
while (true){
LOGXD(VAR_DATA(getpgid(0)),VAR_DATA(getpgrp()),VAR_DATA(getpgid(139656)));
std::this_thread::sleep_for(std::chrono::seconds(1));
}
}
session
一个session由一个或多个进程组组成
pid_t setsid(void); 该进程如果不是进程组的组长,则会新建会话,如果该进程是组长了则返回错误,解决的办法是fork进程,然后子进程会有单独的pid
void test() {
if (setsid() == -1) {
auto pid=fork();
if (pid == 0) {
LOGXD("child", getpid());
LOGXD(VAR_DATA(setsid()));
LOGXD(VAR_DATA(getsid(getpgid(0))));
}
else {
LOGXD("parent", getpid());
}
}
}
controlling Terminal
会话会存在一个控制终端,让会话和控制终端联系的叫控制进程,每个控制终端将会话分成一个前台进程组和若干后台进程组
需要有一种方法来通知内核哪一个进程组是前台进程组,这样,终端设备驱动程序就能了解将终端输入和终端产生的信号送到何处。
#include <unistd.h> pid_t tcgetpgrp(int filedes); //返回值:若成功则返回前台进程组的进程组ID,出错则返回-1. int tcsetpgrp(int filedes, pid_t pgrpid); //返回值:成功则返回0,出错则返回-1.
void test() {
LOGXD("now_process_group_id:", VAR_DATA(getpgrp()));
LOGXD("pre_process_group_id:" VAR_DATA(tcgetpgrp(STDIN_FILENO)));
if (tcsetpgrp(STDIN_FILENO, getpgrp()) == 0) {
LOGXD("pre_process_group_id:" VAR_DATA(tcgetpgrp(STDIN_FILENO)));
}
else {
LOGXW("set fail");
}
}
job control
后台运行: xx &—(在后面加上&) 查看后台程序:jobs 将后台转入前台:fg %[后台序号]
如果没有tcsetpgrp(STDIN_FILENO, getpgrp()) == 0这里,该程序是不会stop的,只因为设置了改进程是前台,但是他属于后台了,so
shell 执行程序
ps -o pid,ppid,pgid,sid,comm | cat1 | cat2
PID PPID PGID SID COMMAND
949 947 949 949 sh
1988 949 949 949 cat2
1989 1988 949 949 ps
1990 1988 949 949 cat1
|