Process Creation, #1:由 shell 執行外部程式《基本觀念與範例》

jollen 發表於 December 31, 2006 8:14 PM

本系列專欄是「了解 ELF 動態時期行為」的前導專欄,建議您先行爬文「理解 dynamic loader 內部原理的幾個先備知識(下):Kernel 端的議題」。

Shell 執行外部程式的觀念

在 2006 年的最後一天,就先來解說一下「下指令後、程式怎麼載入與執行」的觀念。首先,您必須知道並具備以下的 Linux 系統程式觀念:

1. fork() 系統呼叫:用來建立 child process。
2. exec 系列系統呼叫:以一個「外部程式」來取代自己(current process)的執行空間
3. parent process、child process 與 Linux process tree。

了解以上三個主題後,就可以很容易理解「下指令後、程式怎麼載入與執行」的過程;這是很重要且基本的三個議題,若您不是很清楚這三個議題的觀念,可以查詢「Linux Systems Programming」的相關文件。

接下來,首先我們要知道的是,Linux 並沒有提供 "spawn" 的 system call;再來,shell 執行外部程式的做法是使用「spawn 版」的 fork() 實作。

好像又把大家搞胡塗了。所謂的「spawn 版fork()」,用對照的方式來說明會很清楚:

1. 真正的 spawn() 是「建立一個外部程式的 child process」;
2. 而 Linux 下討論的 fork() 則是「建立一個與父程序(parent process)完全相同的 process」。

也就是說,Linux 下的 fork() 是「non-spawn behavior」,因為他不會去跑一個外部程式,而是「複製 parent process 成為 child process」;那麼,要怎麼做出「spawn behavior」的 fork() 呢?方法很簡單:

1. 我們已經學過, exec 系列系統呼叫會以一個「外部程式」來取代 current process 的執行空間,所以不能在 parent process 裡叫用 exec system call 來跑外部程式;否則 parent process 會消失。
2. fork() 可以建立 child process,並且不讓 parent process 消失。
3. 所以,如果先 fork() 出 child process,再讓外部程式取代 child process,那麼就可以實作出「spawn style 的 fork()」了。

小結

Jollen 一開始就打算以邏輯思考(理論推演)的方式來介紹「觀念」,所以講了這麼多,希望不會造成您閱讀上的困擾。引用「書上寫的」應可以勝過以上的長篇大論:

Shell 執行外部程式的做法是先 fork 出自己的 child process,然後在 child process 裡使用 exec 系統呼叫外部程式,以執行外部程式。

很簡單的概念,只是記結論的話多少會少掉一些思考的樂趣。依此來看,邏輯上(Linux programming view)「可視 spawn 為 fork + exec」;實際上,若由 kernel view 來解讀,spawn 並不等於 fork + exec。

程式範例

看此範例需要知道 fork() 與 exec 系列函數的用法,您可參考「Linux Systems Programming」相關文件。

/*
 * Copyright(c) 2003,2004,2005,2006 www.jollen.org
 *
 * Spawn-style Linux fork().
 *
 * This file is GPLed.
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>

int spawn(char *prog, char **arg_list)
{
   pid_t child;

   child = fork();

   if (child != 0) {
      return child;
   } else {
      execvp(prog, arg_list);
      fprintf(stderr, "spawn error\n");
      return -1;
   }
}

int main()
{
   char *arg_list[] = {	
      "ls",  
      "-l",
      "/tmp",
      NULL };	

   spawn("ls", arg_list);

   return 0;
}

以上範例可由「http://tw.jollen.org/elf-programming/spawn_fork.c」下載。

Happy New Year ;-)

Jollen's Blog 使用 Github issues 與讀者交流討論。請點擊上方的文章專屬 issue,或 open a new issue

您可透過電子郵件 jollen@jollen.org,或是 Linkedin 與我連絡。更歡迎使用微信,請搜尋 WeChat ID:jollentw