用户进程,用户线程,内核线程

详细:http://blog.163.com/zhe_wang_2009/blog/static/17228212120123971418489/

总的示意图如下:

用户进程,用户线程,内核线程 - wanny - wanny


Location:arch/x86/kernel/process.c(linux 2.6.38)

238 int sys_fork(struct pt_regs *regs) 239 { 240 return do_fork(SIGCHLD, regs->sp, regs, 0, NULL, NULL); 241 }

Location:arch/x86/kernel/process.c(linux 2.6.38)

253 int sys_vfork(struct pt_regs *regs) 254 { 255 return do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, regs->sp, regs, 0, 256 NULL, NULL); 257 }

Location:arch/x86/kernel/process.c(linux 2.6.38)

259 long 260 sys_clone(unsigned long clone_flags, unsigned long newsp, 261 void __user *parent_tid, void __user *child_tid, struct pt_regs * regs) 262 { 263 if (!newsp) 264 newsp = regs->sp; 265 return do_fork(clone_flags, newsp, regs, 0, parent_tid, child_tid); 266 }

Location:kernel/fork.c

1399 long do_fork(unsigned long clone_flags, 1400 unsigned long stack_start, 1401 struct pt_regs *regs, 1402 unsigned long stack_size, 1403 int __user *parent_tidptr, 1404 int __user *child_tidptr) 1405 { 1406 struct task_struct *p; 1407 int trace = 0; 1408 long nr;

 进程,线程,内核线程在内核中都是通过do_fork()完成创建的,那do_fork()是如何体现其功能的多样性的呢?

 主要发挥作用的是do_fork()的第一个参数,clone_flags

下面介绍几个常见的clone_flags的取值:

CLONE_VM :子进程共享父进程内存描述符和所有的页表
CLONE_FS :子进程共享父进程所在文件系统的根目录和当前工作目录
CLONE_FILES :子进程共享父进程打开的文件
CLONE_SIGHAND :子进程共享父进程的信号处理程序、阻塞信号和挂起的信号,
                               使用该标志必须同时设置 CLONE_VM 标志

fork() :由于 do_fork() 中 clone_flags 参数除了子进程结束时返
回给父进程的 SIGCHLD 信号外并无其他特性标志,因此由 fork()
创建的进程不会共享父进程的任何资源。通常子进程会完全复制父
进程的资源,也就是说父子进程相对独立

do_fork()中的参数:
 clone_flags :进程各种特性的标志。低字节指定子进程结
束时发送给父进程的信号代码,一般为 SIGCHLD 信号,剩
余三个字节是若干个标志或运算的结果

 regs :指向通用寄存器值的指针,当进程从用户态切换到
内核态时通用寄存器中的值会被保存到内核态堆栈中

vfork() : do_fork() 中的 clone_flags 使用了 CLONE_VFORK 和 CLONE_VM 两个标志
 CLONE_VFORK 标志使得子进程先于父进程执行,父进程会阻塞到子进程结束或执行新的程序
CLONE_VM 标志使得子进程共享父进程的内存地址空间(父进程的页表项除外)

clone() :与前两个函数不同, clone 通常用于创建轻量级进程.
使用 clone 函数时候通常是自定义的传入 flags 标志,一般
flags 的取值为 CLONE_VM|CLONE_FS|CLONE_FILES|
CLONE_SIGHAND
由上述标志可以看到,轻量级进程通常共享父进程的内存地址
空间、父进程所在文件系统的根目录以及工作目录信息、父进
程当前打开的文件以及父进程所拥有的信号处理函数

通过 pthread_create() 创建的线程最终在内核中是
通过 clone() 完成创建的,而 clone() 最终调用
do_fork 函数

关于kernel_thread()函数(location::arch/x86/kernel/process.c(linux 2.6.38))

278 int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags) 279 { 280 struct pt_regs regs; 281 282 memset(&regs, 0, sizeof(regs)); 283 284 regs.si = (unsigned long) fn; 285 regs.di = (unsigned long) arg; 286 287 #ifdef CONFIG_X86_32 288 regs.ds = __USER_DS; 289 regs.es = __USER_DS; 290 regs.fs = __KERNEL_PERCPU; 291 regs.gs = __KERNEL_STACK_CANARY; 292 #else 293 regs.ss = __KERNEL_DS; 294 #endif 295 296 regs.orig_ax = -1; 297 regs.ip = (unsigned long) kernel_thread_helper; 298 regs.cs = __KERNEL_CS | get_kernel_rpl(); 299 regs.flags = X86_EFLAGS_IF | 0x2; 300 301 /* Ok, create the new process.. */ 302 return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, &regs, 0, NULL, NULL); 303 } 304 EXPORT_SYMBOL(kernel_thread);

从上面的组合的 flag 可以看出,新的内核线程至少会共享父内核
线程的内存地址空间。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值