[APUE] 再讀之進程關係


本章是最爲難懂,最爲晦澀的一章。主要講解進程組,session, 終端,作業之間關係和概念。


1. 終端登錄

終端登錄由init自舉fork getty進程,getty 調用類似execle("/usr/bin/login","login","-p",username,(char*)0,envp)這樣的語句來完成登錄過程。

正確登錄後,login 就將當前工作目錄更改爲用戶的起始目錄(chdir),調用chown改變終端的所有權。調用setgid及initgroups設置進程的組ID。然後login所得到的所以信息初始化環境:起始目錄,shell,用戶名以及默認系統路徑PATH,最後login 進程改變爲登錄用戶的用戶ID(setuid)並調用該用戶的登錄sheel.

execl("/bin/sh","-sh", (char*)0)

2. 進程組概念

#include <sys/types.h>
#include <unistd.h>
pid_t getpgrp(void);
int setpgid(pid_t pid, pid_t pgid)
一個改變和設置組ID的例子

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

int main()
{
    pid_t pid;
    if((pid=fork())<0)
    {
        printf("fork error\n");
        return 1;
    }
    else if(pid==0)
    {
        printf("Child pid=%d,gid=%d\n", getpid(),getpgrp());
        sleep(3);
        setpgid(pid,pid);
        printf("Child pid=%d,gid=%d\n", getpid(),getpgrp());
    }
    else
    {
        printf("Parent pid=%d,gid=%d\n", getpid(),getpgrp());
        if(wait(NULL)==-1)
        {
            printf("wait error\n");
        }
        printf("Parent pid=%d,gid=%d\n", getpid(),getpgrp());
    }
}


3. session 概念

可以通過setsid來脫離原有session 創建新的session. 組長進程不能調用setsid,否則出錯。調用後新session脫離原有控制終端。

setsid的一般會在創建精靈進程時被調用。


4. session ,控制終端和進程組關係

  • 一個session可以有一個控制終端,也可以一個沒有
  • 建立與控制終端連接的對話期首進程,爲控制終端
  • session中有一個前臺進程組合若干個後臺進程組
  • SIGINT和SIGQUIT將發送到所有前臺進程
  • 如果終端界面檢測到連接斷開,將會發送掛斷信號到控制進程

5. 孤兒進程組

父進程終止的進程組稱爲孤兒進程組。父進程終止後,子進程由init進程領養。父進程結束後,kernel 會向子進程發送SIGHUP 和SIGCONT信號。

下面demo,如果子進程不註冊接收SIGHUP的signal 函數,那子進程將會被終止。

子進程試圖讀終端會失敗。

#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
static void pr_ids(char* name)
{
    printf("%s: pid=%d, ppid=%d, pgid=%d\n",name, getpid(),getppid(),getpgrp());
    fflush(stdout);
}
static void sig_hup(int signo)
{
    printf("Received signal hup\n");
    return;
}
int main()
{
    pid_t pid;
    if((pid=fork())<0)
    {
        printf("fork error\n");
        exit(-1);
    }
    else if (pid>0) //parent
    {
        sleep(5);
        exit(0);
    }
    else
    {
        pr_ids("child");
        /*
        if (signal(SIGHUP,sig_hup)==SIG_ERR)
        {
            printf("signal error\n");
            return -1;
        }
        */
        kill(getpid(),SIGTSTP);
        pr_ids("child");
        char c;
        if(read(0,&c,1)!=1)
            printf("read error, errno =%d, reason=%s\n", errno, strerror(errno));
        exit(0);
    }
}




發佈了45 篇原創文章 · 獲贊 0 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章