2016-12-31

来自本人的旧博客: http://blog.163.com/awaken_ing/blog/static/12061319720151129103139710

1. 问题

linux-3.10.86/kernel/kthread.c

static int kthread(void *_create)
{
...
    /* we can't just return, we must preserve "self" on stack */
    do_exit(ret);
}

这里注释说不能省略do_exit(), why?

2. 解

2.1 内核创建

内核创建的部分流程为: _switchto -> retfromfork -> kthread

linux-3.10.86/arch/arm/kernel/entry-common.S

/*
 * This is how we return from a fork.
 */
ENTRY(ret_from_fork)
    bl  schedule_tail
    cmp r5, #0
    movne   r0, r4
    adrne   lr, BSYM(1f)
    movne   pc, r5
1:  get_thread_info tsk
    b   ret_slow_syscall
ENDPROC(ret_from_fork)

movne pc, r5 执行kthread()

2.2 如果没有do_exit

linux-3.10.86/kernel/exit.c

void do_exit(long code) 
{
... 
    schedule(); 
    BUG(); 
    /* Avoid "noreturn function does return".  */
    for (;;)
        cpu_relax();    /* For when BUG is null */
}

doexit()最后执行schedule(), 所以, 就不会调用到 retfromfork中的retslowsyscall. 看下retslow_syscall的汇编代码:

(gdb) disass ret_slow_syscall
Dump of assembler code for function ret_to_user:
...
   0x8000e630 <+16>:     ldr   lr,[sp, #60]!    ; 0x3c   @get pc
...
   0x8000e63c <+28>:    ldmdb   sp, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, sp, lr}^
   0x8000e640 <+32>:    nop         ; (mov r0, r0)
   0x8000e644 <+36>:    add sp, sp, #12
   0x8000e648 <+40>:    movs    pc, lr
End of assembler dump.

内核线程可能是在内核启动过程中创建的, 并不是由用户态触发而创建的, 故不应该执行ldr lr,[sp, #60]! , ldmdb sp, {... }^以及movs pc, lr. 所以, 需要调用doexit(). 这里也解释了内核线程的两种退出方式: call doexit() directly or return when 'kthreadshouldstop()' .

本文地址: https://awakening-fong.github.io/posts/other/arm_kthread_do_exit

转载请注明出处: https://awakening-fong.github.io


若无法评论, 请打开JavaScript, 并通过proxy.


blog comments powered by Disqus