slj_win

  博客园 :: 首页 :: 新随笔 :: 联系 :: 订阅 :: 管理 ::

ARM-Linux移植之(三)——init进程启动流程分析

我们通常使用Busybox来构建根文件系统的必要的应用程序。Busybox通过传入的参数来决定执行何种操作。当init进程启动时,实际上调用的是Busybox的init_main()函数,下面我们来分析这个函数,看init进程究竟是怎样一个流程。我分析的Busybox源码是 1.7.0版本的,其他版本会略有不同。部分代码省略我们只看关键性代码。

 

首先看init_main函数

 

  1. int init_main(int argc, char **argv); 
  2. int init_main(int argc, char **argv) 
  3.     …………………………….. 
  4.     …………………………….. 
  5.     //初始化控制台 
  6.     console_init(); 
  7.     ……………………………… 
  8.  
  9.     if (argc >
  10.      && (!strcmp(argv[1], "single") || !strcmp(argv[1], "-s") || LONE_CHAR(argv[1], '1')) 
  11.     ) { 
  12.         new_init_action(RESPAWN, bb_default_login_shell, ""); 
  13.     } else { 
  14.         //因为我们启动的init进程没有任何参数,所有argc==1,执行的是这一句 
  15.         parse_inittab(); 
  16.     } 
  17.     ………………………………………… 
  18.     ………………………………………… 
  19.     run_actions(SYSINIT);   //运行inittab配置文件中acthion为SYSINIT的进程 
  20.     run_actions(WAIT);  //运行inittab配置文件中action为WAIT的进程 
  21.  
  22.  
  23.     run_actions(ONCE);  //运行inittba配置文件中action为ONCE的进程 
  24.     ……………………………………………… 
  25.     while (1) { 
  26.         /* 
  27.         运行inittab配置文件中action为RESPAWN和ASKFIRST的进程,一旦退出则重新启动 
  28.         */ 
  29.         run_actions(RESPAWN);    
  30.         run_actions(ASKFIRST); 
  31.  
  32.         wpid = wait(NULL); 
  33.         while (wpid > 0) { 
  34.                     a->pid = 0
  35.             } 
  36.             wpid = waitpid(-1, NULL, WNOHANG); 
  37.          
  38.     } 

parse_inittab实际上对/etc/inittab文件里面的配置进行解释,如果没有,则设置一些默认设置。

我们先来看看这个inittab这个文件里面的配置格式,这个在busybox文件里面的inittab文件里面有说明

<id>:<runlevels>:<action>:<process>

id表示输出输入设备,这个不需要设置,因为/etc/console已经设为标准输入输出了,如不设置,则从控制台输入输出。

runlevels 这个参数完全忽略

action 运行时机,它表示inittab解释后的运行顺序,它有sysinit, respawn, askfirst, wait, once,restart, ctrlaltdel, andshutdown.这个值可选择。

process 就是要启动的进程。

 

下面来看prase_inittab这个函数

  1. static void parse_inittab(void) 
  2. ………………………………………………… 
  3. ………………………………………………… 
  4.  
  5.     /*INITTAB是一个宏 #define INITTAB      "/etc/inittab"    
  6.     可以看得出来它打开了/etc/inittab这个文件*/ 
  7.  
  8.     file = fopen(INITTAB, "r"); 
  9.  
  10.     //如果没有这个文件,则调用new_init_action进行一些默认的操作 
  11.     if (file == NULL) { 
  12.         new_init_action(CTRLALTDEL, "reboot", ""); 
  13.         new_init_action(SHUTDOWN, "umount -a -r", ""); 
  14.         if (ENABLE_SWAPONOFF) new_init_action(SHUTDOWN, "swapoff -a", ""); 
  15.         new_init_action(RESTART, "init", ""); 
  16.         new_init_action(ASKFIRST, bb_default_login_shell, ""); 
  17.         new_init_action(ASKFIRST, bb_default_login_shell, VC_2); 
  18.         new_init_action(ASKFIRST, bb_default_login_shell, VC_3); 
  19.         new_init_action(ASKFIRST, bb_default_login_shell, VC_4);                         new_init_action(SYSINIT, INIT_SCRIPT, ""); 
  20.  
  21.         return; 
  22.     } 
  23.     ………………………………………………… 
  24. ………………………………………………… 
  25.         /*果inittab文件里面有内容就将里面的内容一行一行读出来,然后调用new_init_action进行操作*/ 
  26.     while (fgets(buf, INIT_BUFFS_SIZE, file) != NULL) { 
  27.         /* Ok, now process it */ 
  28.         for (a = actions; a->name != 0; a++) { 
  29.             if (strcmp(a->name, action) == 0) { 
  30.                 if (*id != '\0') { 
  31.                     if (strncmp(id, "/dev/", 5) == 0) 
  32.                         id += 5; 
  33.                     strcpy(tmpConsole, "/dev/"); 
  34.                     safe_strncpy(tmpConsole + 5, id, 
  35.                         sizeof(tmpConsole) - 5); 
  36.                     id = tmpConsole
  37.                 } 
  38.                 new_init_action(a->action, command, id); 
  39.                 break; 
  40.             } 
  41.         } 
  42.     ………………………………………………… 
  43. ………………………………………………… 
  44.     } 
  45.     fclose(file); 

这个new_init_action函数,它实际上是将inittab里面的action相同的操作串成一个链表。

下面我们再来分析init_main执行prase_inittab之后执行的操作

可以看出init_main执行prase_initab对inittab文件里面的配置进行解释之后,会先执行运行时机为 SYSINIT的进程,让执行WAIT时机的,接着是ONCE的,然后在一个while(1)函数里面运行RESPAWN和ASKFIRST时机的,一旦这两个时机里面的进程被杀死,就会把他们的pid赋为0,然后跳到while(1)函数的开始处又去启动他们。所有说运行时机为RESPAWN和 ASKFIRST的进程永远无法杀死,除非reboot或者shutdown。

 

下面我们来总结一下init进程的启动过程 1.初始化控制台 2.解释inittab 3.执行inittab运行时机为SYSINIT的进程 4.执行inittab运行时机为WAIT的进程 5.执行inittab运行时机为ONCE的进程 6.执行inittab运行时机为RESPAWN和ASKFRIST的进程,有退出的则重新执行。

 

posted on 2011-11-03 10:19  slj_win  阅读(549)  评论(0)    收藏  举报