Chinaunix首页 | 论坛 | 博客
  • 博客访问: 620420
  • 博文数量: 168
  • 博客积分: 1053
  • 博客等级: 少尉
  • 技术积分: 1187
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-30 17:20
个人简介

公众号【嵌入式er笔记】持续记录和分享C/C++、Linux、ARM、Android、IoT等技术相关知识,以及职场、生活经验和感悟。

文章分类

全部博文(168)

分类: LINUX

2013-08-16 16:03:32

原文地址:内核创建进程粗解 作者:steven_miao

内核进程粗解
谨以此文纪念过往的岁月。
在内核中可以通过kthread_run来创建一个新的线程
一.kthread_run
这个实际上说不上是函数其实是一个宏定义。其定义如下:
#define kthread_run(threadfn, data, namefmt, ...)      \
({            \
 struct task_struct *__k         \
  = kthread_create(threadfn, data, namefmt, ## __VA_ARGS__); \
 if (!IS_ERR(__k))         \
  wake_up_process(__k);        \
 __k;           \
})
以下所描述的函数均在/kernel/kthread.c中
kthread_create函数实现
struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char namefmt[],...)
{
 struct kthread_create_info create;
 create.threadfn = threadfn;
 create.data = data;
 init_completion(&create.started);
 init_completion(&create.done);
 spin_lock(&kthread_create_lock);                      --kthread_create_lock为当前文件全局变量,锁定自旋锁
 list_add_tail(&create.list, &kthread_create_list);    --将其加入kthread_create_list的链表中,真正的kthread创建在kthreadadd中
 spin_unlock(&kthread_create_lock);                    --解锁
 wake_up_process(kthreadd_task);                       --唤醒kthread线程,kthreadd_task是根据rest_init中创建线程时返回的pid得到的线程信息。   
 wait_for_completion(&create.done);                    --等待创建完成
 if (!IS_ERR(create.result)) {
  va_list args;
  va_start(args, namefmt);
  vsnprintf(create.result->comm, sizeof(create.result->comm),namefmt, args);
  va_end(args);
 }
 return create.result;                                 --返回创建线程的信息
}
下面的函数其实在rest_init中就被运行,创建了新的线程。这个函数在系统启动时就会成为后台程序运行。
int kthreadd(void *unused)
{
 struct task_struct *tsk = current;
 /* Setup a clean context for our children to inherit. */
 set_task_comm(tsk, "kthreadd");
 ignore_signals(tsk);
 set_user_nice(tsk, KTHREAD_NICE_LEVEL);
 set_cpus_allowed_ptr(tsk, CPU_MASK_ALL_PTR);
 current->flags |= PF_NOFREEZE | PF_FREEZER_NOSIG;
 for (;;) {                                              --这个函数是一直循环的
  set_current_state(TASK_INTERRUPTIBLE);
  if (list_empty(&kthread_create_list))                 
   schedule();                         
  __set_current_state(TASK_RUNNING);                     
  spin_lock(&kthread_create_lock);      
  while (!list_empty(&kthread_create_list)) {           --当kthread_create_list有值时
   struct kthread_create_info *create;
   create = list_entry(kthread_create_list.next,struct kthread_create_info, list);   --container_of
   list_del_init(&create->list);                       --将create->list从kthread_create_list中删除并从新初始化。
   spin_unlock(&kthread_create_lock);
   create_kthread(create);                             --创建一个线程
   spin_lock(&kthread_create_lock);
  }
  spin_unlock(&kthread_create_lock);
 }
 return 0;
}
static void create_kthread(struct kthread_create_info *create)
{
 int pid;
 /* We want our own signal handler (we take no signals by default). */
 pid = kernel_thread(kthread, create, CLONE_FS | CLONE_FILES | SIGCHLD);   --创建一个新的kthread线程,调用threadfn
 if (pid < 0) {
  create->result = ERR_PTR(pid);
 } else {
  struct sched_param param = { .sched_priority = 0 };
  wait_for_completion(&create->started);                                  --等待kthread进程中完成
  read_lock(&tasklist_lock);
  create->result = find_task_by_pid_ns(pid, &init_pid_ns);                --根据pid返回thread的信息
  read_unlock(&tasklist_lock);
  /*
   * root may have changed our (kthreadd's) priority or CPU mask.
   * The kernel thread should not inherit these properties.
   */
  sched_setscheduler(create->result, SCHED_NORMAL, ¶m);
  set_user_nice(create->result, KTHREAD_NICE_LEVEL);
  set_cpus_allowed_ptr(create->result, CPU_MASK_ALL_PTR);
 }
 complete(&create->done);                                                  --创建完成
}
static int kthread(void *_create)
{
 struct kthread_create_info *create = _create;
 int (*threadfn)(void *data);
 void *data;
 int ret = -EINTR;
 /* Copy data: it's on kthread's stack */
 threadfn = create->threadfn;                                        --真正需要实现的函数
 data = create->data;
 /* OK, tell user we're spawned, wait for stop or wakeup */
 __set_current_state(TASK_UNINTERRUPTIBLE);                          --设置当前进程睡眠
 complete(&create->started);
 schedule();                --调度其他进程,即唤醒父线程,新建的线程只运行到此,需要在其后wake_up_process中唤醒
 if (!kthread_should_stop())                                         --如果函数没有返回或者没有调用kthread_stop来结束线程,则会一直运行下去
  ret = threadfn(data);
 /* It might have exited on its own, w/o kthread_stop.  Check. */
 if (kthread_should_stop()) {                                        --只是判断是否stop kthread
  kthread_stop_info.err = ret;
  complete(&kthread_stop_info.done);
 }
 return 0;
}
int kthread_should_stop(void)
{
 return (kthread_stop_info.k == current);
}
int kthread_stop(struct task_struct *k)
{
 int ret;
 mutex_lock(&kthread_stop_lock);
 /* It could exit after stop_info.k set, but before wake_up_process. */
 get_task_struct(k);
 trace_sched_kthread_stop(k);
 /* Must init completion *before* thread sees kthread_stop_info.k */
 init_completion(&kthread_stop_info.done);
 smp_wmb();
 /* Now set kthread_should_stop() to true, and wake it up. */
 kthread_stop_info.k = k;                      
 wake_up_process(k);
 put_task_struct(k);
 /* Once it dies, reset stop ptr, gather result and we're done. */
 wait_for_completion(&kthread_stop_info.done);
 kthread_stop_info.k = NULL;
 ret = kthread_stop_info.err;
 mutex_unlock(&kthread_stop_lock);
 trace_sched_kthread_stop_ret(ret);
 return ret;
}
以上的函数其实很好理解。
以主进程A(调用kthread_run的进程),守护进程B(kthread)
A调用kthread_run,仅仅将create->list加入kthread_create_list中,然后等待create.done,唤醒进程B。B进程一直查询kthread_create_list是否为空,如果不为空调用
create_thread在create_thread新建一个进程C(kthread),同时等待create->started.在C进程中并没有直接运行A进程传替的函数,而是complete(create->started)
之后睡眠进程C,同时唤醒B进程。在B进程中实现complete(&create->done),唤醒A进程同时将进程B睡眠。在进程A中会调用wake_up_porcess将进程C唤醒。这样一个
进程就开始运行了。在进程A中调用kthread_stop可以将进程C结束。
在kthread_run中其实真正实现创建进程的是kernel_thread。
阅读(1290) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~