嵌入式操作系统原理及应用
上QQ阅读APP看本书,新人免费读10天
设备和账号都新为新人

4.9 内核线程

例如,μLinux内核中新线程的建立可以用kernel_thread函数实现,该函数在kernel/fork.c中定义:

long kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)

fn:内核线程主函数。

arg:线程主函数的参数。

flags:建立线程的标志。

内核线程函数通常都调用daemonize()进行后台化作为一个独立的线程运行,然后设置线程的一些参数,如名称、信号处理等,这不是必要的。之后就进入一个死循环,这是线程的主体部分,这个循环不能一直在运行,否则系统就死在这里了。它或者是某种事件驱动的,在事件到来前是睡眠的,事件到来后唤醒进行操作,操作完后继续睡眠;或者是定时睡眠,醒后操作完再睡眠;或者加入等待队列,通过schedule()调度获得执行时间。总之这个线程不能一直占着MCU。

以下是内核线程的一个示例,取自kernel/context.c。

int start_context_thread(void)
{
    static struct completion startup __initdata=COMPLETION_INITIALIZER(startup);
    kernel_thread(context_thread, &startup, CLONE_FS | CLONE_FILES);
    wait_for_completion(&startup);
    return 0;
}
static int context_thread(void *startup)
{
    struct task_struct *curtask=current;
    DECLARE_WAITQUEUE(wait, curtask);
    struct k_sigaction sa;
    daemonize();
    strcpy(curtask->comm, "keventd");
    keventd_running=1;
    keventd_task=curtask;
    spin_lock_irq(&curtask->sigmask_lock);
    siginitsetinv(&curtask->blocked, sigmask(SIGCHLD));
    recalc_sigpending(curtask);
    spin_unlock_irq(&curtask->sigmask_lock);
    complete((struct completion *)startup);
    /* Install a handler so SIGCLD is delivered */
    sa.sa.sa_handler=SIG_IGN;
    sa.sa.sa_flags=0;
    siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
    do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
    /*
    * If one of the functions on a task queue re-adds itself
    * to the task queue we call schedule() in state TASK_RUNNING
    */
    for (;;)
     {
        set_task_state(curtask, TASK_INTERRUPTIBLE);
        add_wait_queue(&context_task_wq, &wait);
        if (TQ_ACTIVE(tq_context))
        set_task_state(curtask, TASK_RUNNING);
        schedule();
        remove_wait_queue(&context_task_wq, &wait);
        run_task_queue(&tq_context);
        wake_up(&context_task_done);
        if (signal_pending(curtask))
        {
            while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0)
        ;
            spin_lock_irq(&curtask->sigmask_lock);
            flush_signals(curtask);
            recalc_sigpending(curtask);
            spin_unlock_irq(&curtask->sigmask_lock);
        }
    }
}