init進程_處理子進程終止2

繼續上一講,分析handle_signal

1.init進程–>分析init.rc–>獲得服務列表–>依次啓動服務子進程
在init啓動的進程中,除了一小部分外,其他大部分進程出現意外終止時,init進程要重新啓動他們。

這裏寫圖片描述

子進程終止–>向父進程init傳遞SIGCHLD信號–>檢查進程選項是否設置爲oneshot–>放棄重啓或者重啓進程

2.代碼分析
上節講到,收到SIGCHLD信號後,調用與之相對應的處理函數
sigchld_handler–>signal_fd套接字寫1,signal_recv_fd套接字對應有1–>poll監聽到
–>handle_signal函數調用–>wait_for_one_process函數調用,如下圖:
這裏寫圖片描述

wait_for_one_process函數在產生SIGCHLD信號的進程的服務列表中,檢查進程的設置選項,若選項非oneshot(SVC_ONE_SHOT)則添加重啓選項(SVC_RESTARTING)。否則不會被重啓。

static int wait_for_one_process(int block)
{
...
/*waitpid函數用來回收進程所佔用的資源,第一個參數爲-1,代表查看所有子進程是否發出SIGCHLD信號,返回值即是產生SIGCHLD信號的進程pid號*/
    while ( (pid = waitpid(-1, &status, block ? 0 : WNOHANG)) == -1 && errno == EINTR );

    svc = service_find_by_pid(pid);//取出進程號爲pid的服務項目
 ...
//如果是要重啓,先殺死pid的所有子進程
    if (!(svc->flags & SVC_ONESHOT) || (svc->flags & SVC_RESTART)) {
        kill(-pid, SIGKILL);
        //傳送信號給指定的進程,pid爲負數將信號傳給進程組識別碼爲負數絕對值的所有進程
        NOTICE("process '%s' killing any children in process group\n", svc->name);
    }

    /* remove any sockets we may have created,刪除進程持有的所有sockDescriptor */
    for (si = svc->sockets; si; si = si->next) {
        char tmp[128];
        snprintf(tmp, sizeof(tmp), ANDROID_SOCKET_DIR"/%s", si->name);
        unlink(tmp);
    }

    svc->pid = 0;
    svc->flags &= (~SVC_RUNNING); //刪除svc_running

    /* oneshot processes go into the disabled state on exit,except when manually restarted. 不重啓的,設置爲SVC_DISABLED*/
    if ((svc->flags & SVC_ONESHOT) && !(svc->flags & SVC_RESTART)) {
        svc->flags |= SVC_DISABLED;
    }

        /* disabled and reset processes do not get restarted automatically */
    if (svc->flags & (SVC_DISABLED | SVC_RESET) )  {
        notify_service_state(svc->name, "stopped");
        return 0;//不重啓的,退出
    }
...
    svc->flags &= (~SVC_RESTART);
   //添加SVC_RESTARTING,此標記應用在for循環中的restart_processes()中,用來確定待重啓的進程
    svc->flags |= SVC_RESTARTING;

    /* Execute all onrestart commands for this service. 檢查待重啓的進程在init.rc文件中是否帶有onrestart選項,如果有,執行它們*/
    list_for_each(node, &svc->onrestart.commands) {
        cmd = node_to_item(node, struct command, clist);
        cmd->func(cmd->nargs, cmd->args);
    }
    notify_service_state(svc->name, "restarting");//設置服務屬性
    return 0;
}
//回到for循環中,執行restart_processes();
static void restart_processes()
{
    process_needs_restart = 0;
    service_for_each_flags(SVC_RESTARTING,restart_service_if_needed);
}
static void restart_service_if_needed(struct service *svc)
{
...
    if (next_start_time <= gettime()) {
        svc->flags &= (~SVC_RESTARTING);  //清除flags中的restarting位
        service_start(svc, NULL);         //重啓此服務 
        return;
    }
...
}
發佈了23 篇原創文章 · 獲贊 12 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章