上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); } } }