- 论坛徽章:
- 0
|
[启动内核进程和内核线程时要用到的数据结构]:
- /********************************************************************************
- * A kernel process descriptor; used to start "internal" daemons.
- *
- * Note: global_procpp may be NULL for no global save area.
- struct kproc_desc类型的数据对象:
- 内核进程描述符,用来启动一个内部守护进程,一般静态定义一个
- struct kproc_desc类型的数据对象并初始化其成员,然后传递给kproc_start
- 函数。
- arg0:一个字符串,一般为内核进程的name。
- func:函数地址,当内核线程开始运行时,将执行该函数。
- global_procpp:如果非空,那么 *global_procpp将指向描述内核进程的struct proc
- 数据对象的地址。
- *
- ***************************************/
- 39 struct kproc_desc {
- 40 char *arg0; /* arg 0 (for 'ps' listing) */
- 41 void (*func)(void); /* "main" for kernel process */
- 42 struct proc **global_procpp;/* ptr to proc ptr save area */
- 43 };
- /**********************************************************************
- * A kernel thread descriptor; used to start "internal" daemons.
- 类似于struct kproc_desc对象。
- 内核线程描述符,用来启动一个内部的守护线程。一般静态定义一个
- struct kthread_desc数据对象并初始化其成员,然后传递给kthread_start
- 函数。
- arg0:一个字符串,一般为内核线程的name。
- func:函数地址,当内核线程开始运行时,将执行该函数。
- global_threadpp:如果非空,那么 *global_threadpp将指向描述内核线程的
- struct thread数据对象的地址。
- *
- **************************************/
- 46 struct kthread_desc {
- 47 char *arg0; /* arg 0 (for 'ps' listing) */
- 48 void (*func)(void); /* "main" for kernel thread */
- 49 struct thread **global_threadpp; /* ptr to thread ptr save area */
- 50 };
复制代码
函数kproc_start和kthread_start实现大概看了一下,区别如下:
函数kproc_start同时要创建一个描述内核进程的struct proc对象,以及相关联的struct thread对象。
函数kthread_start只创建一个描述内核线程的struct thread对象,并将其和proc0关联起来。
下面看看pagedaemon这个内核进程是如何start的,定义的struct kproc_desc类型的数据对象如下:
- struct proc *pageproc;
- 120 static struct kproc_desc page_kp = {
- 121 "pagedaemon", //arg0成员
- 122 vm_pageout, //func成员
- 123 &pageproc //global_procpp成员
- 124 };
- 125 SYSINIT(pagedaemon, SI_SUB_KTHREAD_PAGE, SI_ORDER_FIRST, kproc_start,
- 126 &page_kp);
复制代码
[函数kproc_start]:
- /*******************************************************************************
- * Start a kernel process. This is called after a fork() call in
- * mi_startup() in the file kern/init_main.c.
- *
- * This function is used to start "internal" daemons and intended
- * to be called from SYSINIT().
- 从这里可以看出,kproc_start函数是通过SYSINIT机制来调用的。
- 参数描述:
- udata:这里就为&page_kp。
- 将以下面的参数调用kproc_create函数:
- kproc_create(vm_pageout, NULL,&pageproc, 0, 0, "%s", "pagedaemon");
- ******************************/
- 56 void
- 57 kproc_start(udata)
- 58 const void *udata;
- 59 {
- 60 const struct kproc_desc *kp = udata;
- 61 int error;
- 62
- 63 error = kproc_create((void (*)(void *))kp->func, NULL,
- 64 kp->global_procpp, 0, 0, "%s", kp->arg0);
- 65 if (error)
- 66 panic("kproc_start: %s: error %d", kp->arg0, error);
- 67 }
复制代码
[函数kproc_create]:
- /**********************************************************************************************
- * Create a kernel process/thread/whatever. It shares its address space
- * with proc0 - ie: kernel only.
- *
- * func is the function to start.
- * arg is the parameter to pass to function on first startup.
- * newpp is the return value pointing to the thread's struct proc.
- * flags are flags to fork1 (in unistd.h)
- * fmt and following will be *printf'd into (*newpp)->p_comm (for ps, etc.).
- 函数描述:
- kproc_create函数将创建一个内核进程,新创建的内核进程和thread0共享
- 地址空间,即使用的是内核地址空间。
- 参数描述:
- func:pagedaemon进程被调度运行时将要执行的函数地址,这里为函数vm_pageout。
- arg:传递给func函数的参数,这里为NULL。
- procptr:描述pagedaemon进程的struct proc对象通过*procptr返回,这里为&pageproc。
- flags:传递给fork1函数的标志,这里为0。
- pages:内核线程的内核栈大小,即多少个page,这里为0,那么内核站的默认大小为2个page。
- fmt:可变参数列表,这里为("%s", "pagedaemon")
- ***********************************************/
- 79 int
- 80 kproc_create(void (*func)(void *), void *arg,
- 81 struct proc **newpp, int flags, int pages, const char *fmt, ...)
- 82 {
- 83 int error;
- 84 va_list ap;
- 85 struct thread *td;
- 86 struct proc *p2;
- 87
- 88 if (!proc0.p_stats)
- 89 panic("kproc_create called too soon");
- 90
- /************************************************************************************
- * 91-94:
- 调用fork1函数创建进程,注意这里设置了
- #define RFMEM (1<<5) /* share `address space' */
- #define RFSTOPPED (1<<17) /* leave child in a stopped state */
- 这说明了pagedaemon进程将使用内核地址空间,并且fork1函数不会将其添加到cpu的运行
- 队列中
- *****************************/
- 91 error = fork1(&thread0, RFMEM | RFFDG | RFPROC | RFSTOPPED | flags,
- 92 pages, &p2, NULL, 0);
- 93 if (error)
- 94 return error;
- 95
- 96
- /*******************************************************************
- * save a global descriptor, if desired。
- 97-98:
- 返回描述pagedaemon内核进程的struct proc数据对象,即pageproc将
- 指向描述pagedaemon内核进程的struct proc数据对象。
- *************************/
- 97 if (newpp != NULL)
- 98 *newpp = p2;
- 99
- 100
- /*********************************************************************************
- * this is a non-swapped system process
- 101-108:设置相关的标志。
- #define PS_NOCLDWAIT 0x0001 No zombies if child dies
- #define P_SYSTEM 0x00200 System proc: no sigs, stats or swapping.
- #define P_KTHREAD 0x00004 Kernel thread (*).
- #define TDP_KTHREAD 0x00200000 This is an official kernel thread
- ********************/
- 101 PROC_LOCK(p2);
- 102 td = FIRST_THREAD_IN_PROC(p2);
- 103 p2->p_flag |= P_SYSTEM | P_KTHREAD;
- 104 td->td_pflags |= TDP_KTHREAD;
- 105 mtx_lock(&p2->p_sigacts->ps_mtx);
- 106 p2->p_sigacts->ps_flag |= PS_NOCLDWAIT;
- 107 mtx_unlock(&p2->p_sigacts->ps_mtx);
- 108 PROC_UNLOCK(p2);
- 109
- /*****************************************************
- * 110-117:
- struct proc对象的p_comm成员,struct thread对象的
- td_name成员都设置为"pagedaemon"。
- *********************************/
- 110 /* set up arg0 for 'ps', et al */
- 111 va_start(ap, fmt);
- 112 vsnprintf(p2->p_comm, sizeof(p2->p_comm), fmt, ap);
- 113 va_end(ap);
- 114 /* set up arg0 for 'ps', et al */
- 115 va_start(ap, fmt);
- 116 vsnprintf(td->td_name, sizeof(td->td_name), fmt, ap);
- 117 va_end(ap);
- 118 #ifdef KTR
- 119 sched_clear_tdname(td);
- 120 #endif
- 121
- 122
- /**********************************************************************
- * call the processes' main()...
- 123:
- 修改线程的硬件上下文,主要更新下面struct pcb对象中下面的两个成员:
- td->td_pcb->pcb_esi = (int) func; /* 这里设置为vm_pageout */
- td->td_pcb->pcb_ebx = (int) arg; /* 这里设置为NULL */
- ***************************/
- 123 cpu_set_fork_handler(td, func, arg);
- 124
- 125
- /***************************************************************
- * Avoid inheriting affinity from a random parent.
- #define TD_SET_CAN_RUN(td) (td)->td_state = TDS_CAN_RUN
- #define PVM (PRI_MIN_KERN + 4) 84
- #define PUSER (PRI_MIN_TIMESHARE) 120
- 126:函数cpuset_setthread忽略。
- 129:函数sched_prio更新td的优先级,即更新td_priority成员。
- 130:函数sched_user_prio更新td_user_pri,td_base_user_pri
- 两个成员。
- **********************************/
- 126 cpuset_setthread(td->td_tid, cpuset_root);
- 127 thread_lock(td);
- 128 TD_SET_CAN_RUN(td);
- 129 sched_prio(td, PVM);
- 130 sched_user_prio(td, PUSER);
- 131
- 132
- /******************************************************
- * Delay putting it on the run queue until now.
- 133-134:
- 此时调用ULE调度程序的sched_add函数将pagedaemon进程
- 添加到cpu的运行队列中。
- *****************************/
- 133 if (!(flags & RFSTOPPED))
- 134 sched_add(td, SRQ_BORING);
- 135 thread_unlock(td);
- 136
- 137 return 0;
- 138 }
复制代码
|
|