免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 3163 | 回复: 0
打印 上一主题 下一主题

[FreeBSD] freebsd9.2-如何start一个内核守护进程 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2014-06-27 00:32 |只看该作者 |倒序浏览
[启动内核进程和内核线程时要用到的数据结构]:
  1. /********************************************************************************
  2. * A kernel process descriptor; used to start "internal" daemons.
  3. *
  4. * Note: global_procpp may be NULL for no global save area.

  5. struct kproc_desc类型的数据对象:
  6. 内核进程描述符,用来启动一个内部守护进程,一般静态定义一个
  7. struct kproc_desc类型的数据对象并初始化其成员,然后传递给kproc_start
  8. 函数。

  9. arg0:一个字符串,一般为内核进程的name。
  10. func:函数地址,当内核线程开始运行时,将执行该函数。
  11. global_procpp:如果非空,那么 *global_procpp将指向描述内核进程的struct proc
  12. 数据对象的地址。
  13. *
  14. ***************************************/
  15. 39 struct kproc_desc {
  16. 40 char *arg0; /* arg 0 (for 'ps' listing) */
  17. 41 void (*func)(void); /* "main" for kernel process */
  18. 42 struct proc **global_procpp;/* ptr to proc ptr save area */
  19. 43 };


  20. /**********************************************************************
  21. * A kernel thread descriptor; used to start "internal" daemons.
  22. 类似于struct kproc_desc对象。

  23. 内核线程描述符,用来启动一个内部的守护线程。一般静态定义一个
  24. struct kthread_desc数据对象并初始化其成员,然后传递给kthread_start
  25. 函数。

  26. arg0:一个字符串,一般为内核线程的name。
  27. func:函数地址,当内核线程开始运行时,将执行该函数。
  28. global_threadpp:如果非空,那么 *global_threadpp将指向描述内核线程的
  29. struct thread数据对象的地址。
  30. *
  31. **************************************/
  32. 46 struct kthread_desc {
  33. 47 char *arg0; /* arg 0 (for 'ps' listing) */
  34. 48 void (*func)(void); /* "main" for kernel thread */
  35. 49 struct thread **global_threadpp; /* ptr to thread ptr save area */
  36. 50 };
复制代码

函数kproc_start和kthread_start实现大概看了一下,区别如下:
函数kproc_start同时要创建一个描述内核进程的struct proc对象,以及相关联的struct thread对象。
函数kthread_start只创建一个描述内核线程的struct thread对象,并将其和proc0关联起来。

下面看看pagedaemon这个内核进程是如何start的,定义的struct kproc_desc类型的数据对象如下:
  1. struct proc *pageproc;
  2. 120 static struct kproc_desc page_kp = {
  3. 121 "pagedaemon", //arg0成员
  4. 122 vm_pageout, //func成员
  5. 123 &pageproc //global_procpp成员
  6. 124 };
  7. 125 SYSINIT(pagedaemon, SI_SUB_KTHREAD_PAGE, SI_ORDER_FIRST, kproc_start,
  8. 126 &page_kp);
复制代码

[函数kproc_start]:
  1. /*******************************************************************************
  2. * Start a kernel process. This is called after a fork() call in
  3. * mi_startup() in the file kern/init_main.c.
  4. *
  5. * This function is used to start "internal" daemons and intended
  6. * to be called from SYSINIT().
  7. 从这里可以看出,kproc_start函数是通过SYSINIT机制来调用的。

  8. 参数描述:
  9. udata:这里就为&page_kp。

  10. 将以下面的参数调用kproc_create函数:
  11. kproc_create(vm_pageout, NULL,&pageproc, 0, 0, "%s", "pagedaemon");

  12. ******************************/
  13. 56 void
  14. 57 kproc_start(udata)
  15. 58 const void *udata;
  16. 59 {
  17. 60 const struct kproc_desc *kp = udata;
  18. 61 int error;
  19. 62
  20. 63 error = kproc_create((void (*)(void *))kp->func, NULL,
  21. 64 kp->global_procpp, 0, 0, "%s", kp->arg0);
  22. 65 if (error)
  23. 66 panic("kproc_start: %s: error %d", kp->arg0, error);
  24. 67 }
复制代码

[函数kproc_create]:
  1. /**********************************************************************************************
  2. * Create a kernel process/thread/whatever. It shares its address space
  3. * with proc0 - ie: kernel only.
  4. *
  5. * func is the function to start.
  6. * arg is the parameter to pass to function on first startup.
  7. * newpp is the return value pointing to the thread's struct proc.
  8. * flags are flags to fork1 (in unistd.h)
  9. * fmt and following will be *printf'd into (*newpp)->p_comm (for ps, etc.).

  10. 函数描述:
  11. kproc_create函数将创建一个内核进程,新创建的内核进程和thread0共享
  12. 地址空间,即使用的是内核地址空间。

  13. 参数描述:
  14. func:pagedaemon进程被调度运行时将要执行的函数地址,这里为函数vm_pageout。
  15. arg:传递给func函数的参数,这里为NULL。
  16. procptr:描述pagedaemon进程的struct proc对象通过*procptr返回,这里为&pageproc。
  17. flags:传递给fork1函数的标志,这里为0。
  18. pages:内核线程的内核栈大小,即多少个page,这里为0,那么内核站的默认大小为2个page。
  19. fmt:可变参数列表,这里为("%s", "pagedaemon")
  20. ***********************************************/
  21. 79 int
  22. 80 kproc_create(void (*func)(void *), void *arg,
  23. 81 struct proc **newpp, int flags, int pages, const char *fmt, ...)
  24. 82 {
  25. 83 int error;
  26. 84 va_list ap;
  27. 85 struct thread *td;
  28. 86 struct proc *p2;
  29. 87
  30. 88 if (!proc0.p_stats)
  31. 89 panic("kproc_create called too soon");
  32. 90
  33. /************************************************************************************
  34. * 91-94:
  35. 调用fork1函数创建进程,注意这里设置了
  36. #define RFMEM (1<<5) /* share `address space' */
  37. #define RFSTOPPED (1<<17) /* leave child in a stopped state */

  38. 这说明了pagedaemon进程将使用内核地址空间,并且fork1函数不会将其添加到cpu的运行
  39. 队列中
  40. *****************************/
  41. 91 error = fork1(&thread0, RFMEM | RFFDG | RFPROC | RFSTOPPED | flags,
  42. 92 pages, &p2, NULL, 0);
  43. 93 if (error)
  44. 94 return error;
  45. 95
  46. 96
  47. /*******************************************************************
  48. * save a global descriptor, if desired。
  49. 97-98:
  50. 返回描述pagedaemon内核进程的struct proc数据对象,即pageproc将
  51. 指向描述pagedaemon内核进程的struct proc数据对象。
  52. *************************/
  53. 97 if (newpp != NULL)
  54. 98 *newpp = p2;
  55. 99
  56. 100
  57. /*********************************************************************************
  58. * this is a non-swapped system process
  59. 101-108:设置相关的标志。
  60. #define PS_NOCLDWAIT 0x0001 No zombies if child dies
  61. #define P_SYSTEM 0x00200 System proc: no sigs, stats or swapping.
  62. #define P_KTHREAD 0x00004 Kernel thread (*).
  63. #define TDP_KTHREAD 0x00200000 This is an official kernel thread
  64. ********************/
  65. 101 PROC_LOCK(p2);
  66. 102 td = FIRST_THREAD_IN_PROC(p2);
  67. 103 p2->p_flag |= P_SYSTEM | P_KTHREAD;
  68. 104 td->td_pflags |= TDP_KTHREAD;
  69. 105 mtx_lock(&p2->p_sigacts->ps_mtx);
  70. 106 p2->p_sigacts->ps_flag |= PS_NOCLDWAIT;
  71. 107 mtx_unlock(&p2->p_sigacts->ps_mtx);
  72. 108 PROC_UNLOCK(p2);
  73. 109
  74. /*****************************************************
  75. * 110-117:
  76. struct proc对象的p_comm成员,struct thread对象的
  77. td_name成员都设置为"pagedaemon"。
  78. *********************************/
  79. 110 /* set up arg0 for 'ps', et al */
  80. 111 va_start(ap, fmt);
  81. 112 vsnprintf(p2->p_comm, sizeof(p2->p_comm), fmt, ap);
  82. 113 va_end(ap);
  83. 114 /* set up arg0 for 'ps', et al */
  84. 115 va_start(ap, fmt);
  85. 116 vsnprintf(td->td_name, sizeof(td->td_name), fmt, ap);
  86. 117 va_end(ap);
  87. 118 #ifdef KTR
  88. 119 sched_clear_tdname(td);
  89. 120 #endif
  90. 121
  91. 122
  92. /**********************************************************************
  93. * call the processes' main()...
  94. 123:
  95. 修改线程的硬件上下文,主要更新下面struct pcb对象中下面的两个成员:
  96. td->td_pcb->pcb_esi = (int) func; /* 这里设置为vm_pageout */
  97. td->td_pcb->pcb_ebx = (int) arg; /* 这里设置为NULL */

  98. ***************************/
  99. 123 cpu_set_fork_handler(td, func, arg);
  100. 124
  101. 125
  102. /***************************************************************
  103. * Avoid inheriting affinity from a random parent.

  104. #define TD_SET_CAN_RUN(td) (td)->td_state = TDS_CAN_RUN
  105. #define PVM (PRI_MIN_KERN + 4) 84
  106. #define PUSER (PRI_MIN_TIMESHARE) 120

  107. 126:函数cpuset_setthread忽略。
  108. 129:函数sched_prio更新td的优先级,即更新td_priority成员。
  109. 130:函数sched_user_prio更新td_user_pri,td_base_user_pri
  110. 两个成员。
  111. **********************************/
  112. 126 cpuset_setthread(td->td_tid, cpuset_root);
  113. 127 thread_lock(td);
  114. 128 TD_SET_CAN_RUN(td);
  115. 129 sched_prio(td, PVM);
  116. 130 sched_user_prio(td, PUSER);
  117. 131
  118. 132
  119. /******************************************************
  120. * Delay putting it on the run queue until now.
  121. 133-134:
  122. 此时调用ULE调度程序的sched_add函数将pagedaemon进程
  123. 添加到cpu的运行队列中。
  124. *****************************/
  125. 133 if (!(flags & RFSTOPPED))
  126. 134 sched_add(td, SRQ_BORING);
  127. 135 thread_unlock(td);
  128. 136
  129. 137 return 0;
  130. 138 }
复制代码

您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

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

清除 Cookies - ChinaUnix - Archiver - WAP - TOP