免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2781 | 回复: 0

[FreeBSD] freebsd9.2-init进程-创建 [复制链接]

论坛徽章:
0
发表于 2014-06-24 00:50 |显示全部楼层
本帖最后由 71v5 于 2014-06-25 13:39 编辑

1号进程,即init进程,大家最熟悉不过了,不过这个init进程到底是怎么被创建的,下面简要分析一下其创建过程。

init进程派生出系统中其它全部进程,1号进程创建分两步完成:

step1:创建1号进程,但是不把1号进程添加到cpu的运行队列中。
step2:将1号进程添加到cpu的运行队列中,等待被调度执行。



[step1]:
  1. SI_SUB_CREATE_INIT        = 0x2500000,        /* create init process*/

  2. 837: SYSINIT(init, SI_SUB_CREATE_INIT, SI_ORDER_FIRST, create_init, NULL);
  3. [the above rsults in file /usr/src/sys/kern/init_main.c]
复制代码
创建1号进程的任务由函数create_init来完成:
  1. /********************************************************
  2. * 全局变量initproc指向描述1号进程的struct proc数据对象。
  3. ***********/
  4. struct        proc *initproc;

  5.    801        /***********************************************************************
  6.    802         * Like kproc_create(), but runs in it's own address space.
  7.    803         * We do this early to reserve pid 1.
  8.    804         *
  9.    805         * Note special case - do not make it runnable yet.  Other work
  10.    806         * in progress will change this more.

  11.                 从create_init函数的实现来看,因为在调用fork1函数时,第二个flags
  12.                 参数设置了RFSTOPPED标志,1号进程被创建后,并不会被添加到合适cpu的
  13.            运行队列中,在初始化过程的末尾阶段,才会将1号进程添加到合适cpu的
  14.            运行队列中。将1号进程添加到合适cpu运行队列的任务由函数kick_init来
  15.            完成。
  16.    807         */
  17.    808        static void
  18.    809        create_init(const void *udata __unused)
  19.    810        {
  20.    811                struct ucred *newcred, *oldcred;
  21.    812                int error;
  22. /*********************************************************************
  23.   * #define        RFFDG        (1<<2)         copy fd table
  24.      #define        RFPROC        (1<<4)         change child (else changes curproc)
  25.      #define        RFSTOPPED  (1<<17) leave child in a stopped state

  26.       fork1函数的实现请参考"9.2-进程创建-阶段2-fork1"中的描述。

  27.     由此可见,进程0是进程1的父进程,进程1对应的struct proc对象
  28.     通过全局变量initproc返回。
  29. ******************/
  30.    814                error = fork1(&thread0, RFFDG | RFPROC | RFSTOPPED, 0, &initproc,
  31.    815                    NULL, 0);
  32.    816                if (error)
  33.    817                        panic("cannot fork init: %d\n", error);
  34.    818                KASSERT(initproc->p_pid == 1, ("create_init: initproc->p_pid != 1"));
  35. /************************************************
  36.    * 820-824:
  37.       divorce init's credentials from the kernel's
  38.       给进程1分配一个新的struct ucred数据对象,并且
  39.     更新p_ucred和td_ucred成员,这两个成员将指向
  40.     新分配的struct ucred对象。
  41.     当进程调用setuid,seteuid等系统调用时,会
  42.     修改struct ucred对象中相应的成员。
  43.   ******************/
  44.    820                newcred = crget();
  45.    821                PROC_LOCK(initproc);
  46. /********************************************************************************
  47.   * #define        P_SYSTEM  0x00200        System proc: no sigs, stats or swapping.
  48.      #define        P_INMEM          0x10000000    Loaded into memory.
  49.   *******************/
  50.    822                initproc->p_flag |= P_SYSTEM | P_INMEM;
  51.    823                oldcred = initproc->p_ucred;
  52.    824                crcopy(newcred, oldcred);
  53.    825        #ifdef MAC
  54.    826                mac_cred_create_init(newcred);
  55.    827        #endif
  56.    828        #ifdef AUDIT
  57.    829                audit_cred_proc1(newcred);
  58.    830        #endif
  59.    831                initproc->p_ucred = newcred;
  60.    832                PROC_UNLOCK(initproc);
  61.    833                crfree(oldcred);
  62.    834                cred_update_thread(FIRST_THREAD_IN_PROC(initproc));
  63. /*******************************************************
  64. * 835:
  65.    函数cpu_set_fork_handler修改保存在进程1内核栈上
  66.    的硬件上下文(esi和ebx寄存器),做下面的设置:
  67.    pcb_esi被设置为函数start_init的地址,当进程1被调度
  68.    运行时就会执行该函数:
  69.    td->td_pcb->pcb_esi = (int) func;       start_init

  70.     pcb_ebx成员被设置为和进程1相关联的第一个线程对应
  71.    struct thread对象的地址,作为函数start_init的参数:
  72.    td->td_pcb->pcb_ebx = (int) arg;        NULL
  73. ********************/
  74.    835                cpu_set_fork_handler(FIRST_THREAD_IN_PROC(initproc), start_init, NULL);
  75.    836        }
复制代码
[step2]:

当函数create_init执行完后,进程1已经被成功创建,但是还没有将其添加到cpu的运行队列中,在内核初始化最后阶段,函数kick_init将进程1添加到cpu运行队列中,
这样在将来的某个时刻,进程1将被调度运行:
  1. SI_SUB_KTHREAD_INIT        = 0xe000000,        /* init process*/

  2. 853: SYSINIT(kickinit, SI_SUB_KTHREAD_INIT, SI_ORDER_FIRST, kick_init, NULL);
  3. [the above rsults in file /usr/src/sys/kern/init_main.c]

  4.    839        /******************************************************************
  5.    840         * Make it runnable now.
  6.                  函数kick_init完成的主要任务就是将进程1相关联的第一个thread
  7.                 添加到cpu的运行队列中。
  8.            847:
  9.            宏FIRST_THREAD_IN_PROC返回initproc关联的第一个thread

  10.                 849:
  11.            #define TD_SET_CAN_RUN(td)  (td)->td_state = TDS_CAN_RUN

  12.                 850:
  13.            调用和调度程序相关的sched_add函数将td添加到cpu的运行队列中
  14.   841         ***********/
  15.    842        static void
  16.    843        kick_init(const void *udata __unused)
  17.    844        {
  18.    845                struct thread *td;
  19.    846       
  20.    847                td = FIRST_THREAD_IN_PROC(initproc);
  21.    848                thread_lock(td);
  22.    849                TD_SET_CAN_RUN(td);
  23.    850                sched_add(td, SRQ_BORING);
  24.    851                thread_unlock(td);
  25.    852        }
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP