打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
关于kernel_thread的补充说明
kernel_thread会产生一个task_struct实例出来,所以应该算是内核进程了,x86上的实现代码是:

<arch/x86/kernel/process.c>
int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
{
struct pt_regs regs;

memset(&regs, 0, sizeof(regs));

regs.si = (unsigned long) fn;
regs.di = (unsigned long) arg;

#ifdef CONFIG_X86_32
regs.ds = __USER_DS;
regs.es = __USER_DS;
regs.fs = __KERNEL_PERCPU;
regs.gs = __KERNEL_STACK_CANARY;
#else
regs.ss = __KERNEL_DS;
#endif

regs.orig_ax = -1;
regs.ip = (unsigned long) kernel_thread_helper;
regs.cs = __KERNEL_CS | get_kernel_rpl();
regs.flags = X86_EFLAGS_IF | 0x2;

/* Ok, create the new process.. */
return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
}

期间的关键节点有:
1. do_fork在调用的copy_process函数里生成一个新的task_struct实例p,代表一个新进程
2. 通过alloc_pages为新进程生成一个独立的内核栈(栈大小8KB):alloc_thread_info_node,之后将父进程内核栈的内容copy到新进程内核栈中。
3. p加入运行队列等待调度
4. copy_thread:
struct pt_regs *childregs;
*childregs = *regs;
p->thread.sp = (unsigned long) childregs;
p->thread.sp0 = (unsigned long) (childregs+1);
p->thread.ip = (unsigned long) ret_from_fork;
因此,新进程拥有自己的堆栈且会根据regs中的内容进行修改。

5. p被调度运行,因为p->thread.ip = (unsigned long) ret_from_fork,所以从ret_from_fork开始执行(在新进程上下文中)
6. ret_from_fork最后调用syscall_exit,后者最后以INTERRUPT_RETURN(也就是ia32中iret指令或者是x86_64中的iretq指令)返回,因此将从当前堆栈中找到返回地址,该地址在上面的第4步中被赋值为regs.ip = (unsigned long) kernel_thread_helper,所以kernel_thread_helper将在新进程环境中被调用。

简单的总结就是:kernel_thread产生一个新进程p,p->thread.ip=ret_from_fork,所以当新进程被调度执行时将从ret_from_fork函数开始执行(原因在进程切换用的switch_to代码中),ret_from_fork执行的最后执行iret,因为堆栈中的ip被指向了regs.ip = (unsigned long) kernel_thread_helper,所以将执行kernel_thread_helper函数。

接下来的过程可参考解密Linux kernel中的内核线程 ,本帖实际上是该贴的一个补充。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
浅谈Linux内核创建新进程的全过程
linux 的进程与线程
Linux中断处理体系结构分析 第3页
Linux mem 2.3 内核页表隔离 (KPTI) 详解
Linux内核线程之深入浅出
Linux内核Crash分析
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服