• linux 内核层进程创建do_fork分析


    0、说明

            应用层调用fork来创建进程的时候,内核层通过do_fork实现,相对来说应用层太容易了。而内核层创建fork做了很多工作。系统调用进入do_fork,这篇主要分析do_fork的实现。

    1、do_fork总览

            fork、vfork都调用了clone系统调用,clone在内核中调用了 do_fork()函数实现,因此重点在于do_fork的分析。

            代码如下,do_fork主要工作:

    • 基于父进程拷贝出子进程的相关资源,copy_process
    • 子进程资源的初始化
    • 给子进程分配pid,get_task_pid
    • 子进程加入到调度队列中,wake_up_new_task 

    clone系统调用:

    1. SYSCALL_DEFINE5(clone, unsigned long, clone_flags, unsigned long, newsp,
    2. int __user *, parent_tidptr,
    3. int, tls_val,
    4. int __user *, child_tidptr)
    5. {
    6. return do_fork(clone_flags, newsp, 0, parent_tidptr, child_tidptr);
    7. }

    do_fork内核层实现:

    1. /*
    2. * Ok, this is the main fork-routine.
    3. *
    4. * It copies the process, and if successful kick-starts
    5. * it and waits for it to finish using the VM if required.
    6. */
    7. long do_fork(unsigned long clone_flags,
    8. unsigned long stack_start,
    9. unsigned long stack_size,
    10. int __user *parent_tidptr,
    11. int __user *child_tidptr)
    12. {
    13. struct task_struct *p;
    14. int trace = 0;
    15. long nr;
    16. /*
    17. * Determine whether and which event to report to ptracer. When
    18. * called from kernel_thread or CLONE_UNTRACED is explicitly
    19. * requested, no event is reported; otherwise, report if the event
    20. * for the type of forking is enabled.
    21. */
    22. //标志解析
    23. if (!(clone_flags & CLONE_UNTRACED)) {
    24. if (clone_flags & CLONE_VFORK)
    25. trace = PTRACE_EVENT_VFORK;
    26. else if ((clone_flags & CSIGNAL) != SIGCHLD)
    27. trace = PTRACE_EVENT_CLONE;
    28. else
    29. trace = PTRACE_EVENT_FORK;
    30. if (likely(!ptrace_event_enabled(current, trace)))
    31. trace = 0;
    32. }
    33. //主要就是这一个函数copy_process
    34. p = copy_process(clone_flags, stack_start, stack_size,
    35. child_tidptr, NULL, trace);
    36. /*
    37. * Do this prior waking up the new thread - the thread pointer
    38. * might get invalid after that point, if the thread exits quickly.
    39. */
    40. if (!IS_ERR(p)) {
    41. struct completion vfork;
    42. struct pid *pid;
    43. trace_sched_process_fork(current, p);
    44. //产生分配给子进程的pid
    45. pid = get_task_pid(p, PIDTYPE_PID);
    46. nr = pid_vnr(pid);
    47. if (clone_flags & CLONE_PARENT_SETTID)
    48. put_user(nr, parent_tidptr);
    49. if (clone_flags & CLONE_VFORK) {
    50. p->vfork_done = &vfork;
    51. init_completion(&vfork);
    52. get_task_struct(p);
    53. }
    54. //子进程加入到调度队列中取,等待调度
    55. wake_up_new_task(p);
    56. /* forking complete and child started to run, tell ptracer */
    57. if (unlikely(trace))
    58. ptrace_event_pid(trace, pid);
    59. if (clone_flags & CLONE_VFORK) {
    60. //如果有CLONE_VFORK 需要子进程先运行
    61. if (!wait_for_vfork_done(p, &vfork))
    62. ptrace_event_pid(PTRACE_EVENT_VFORK_DONE, pid);
    63. }
    64. put_pid(pid);
    65. } else {
    66. nr = PTR_ERR(p);
    67. }
    68. return nr;
    69. }

    2、copy_process实现

            复制父进程资源,得出子进程task_struct。

    p = copy_process(clone_flags, stack_start, stack_size, child_tidptr, NULL, trace);

    dup_task_struct

            基于父进程资源,产生一个子进程task_struct

    1. dup_task_struct
    2. tsk = alloc_task_struct_node
    3. kmem_cache_alloc_node(task_struct_cachep, GFP_KERNEL, node)
    4. ti = alloc_thread_info_node(tsk, node)
    5. alloc_kmem_pages_node(node, THREADINFO_GFP, THREAD_SIZE_ORDER);
    6. arch_dup_task_struct(tsk, orig)
    7. *dst = *src; //父进程资源给子进程
    8. tsk->stack = ti
    9. setup_thread_stack(tsk, orig) //父进程栈给子进程
    10. clear_user_return_notifier(tsk);//清除一些标志
    11. clear_tsk_need_resched(tsk);//清除一些标志
    12. set_task_stack_end_magic(tsk)//设置栈底标志
    13. atomic_set(&tsk->usage, 2);

    copy_creds

            拷贝父进程证书

    1. /* Perform scheduler related setup. Assign this task to a CPU. */
    2. retval = sched_fork(clone_flags, p);
    3. if (retval)
    4. goto bad_fork_cleanup_policy;
    5. retval = perf_event_init_task(p);
    6. if (retval)
    7. goto bad_fork_cleanup_policy;
    8. retval = audit_alloc(p);
    9. if (retval)
    10. goto bad_fork_cleanup_perf;
    11. /* copy all the process information */
    12. shm_init_task(p);
    13. retval = copy_semundo(clone_flags, p);
    14. if (retval)
    15. goto bad_fork_cleanup_audit;
    16. retval = copy_files(clone_flags, p);
    17. if (retval)
    18. goto bad_fork_cleanup_semundo;
    19. retval = copy_fs(clone_flags, p);
    20. if (retval)
    21. goto bad_fork_cleanup_files;
    22. retval = copy_sighand(clone_flags, p);
    23. if (retval)
    24. goto bad_fork_cleanup_fs;
    25. retval = copy_signal(clone_flags, p);
    26. if (retval)
    27. goto bad_fork_cleanup_sighand;
    28. retval = copy_mm(clone_flags, p);
    29. if (retval)
    30. goto bad_fork_cleanup_signal;
    31. retval = copy_namespaces(clone_flags, p);
    32. if (retval)
    33. goto bad_fork_cleanup_mm;
    34. retval = copy_io(clone_flags, p);
    35. if (retval)
    36. goto bad_fork_cleanup_namespaces;
    37. retval = copy_thread(clone_flags, stack_start, stack_size, p);
    38. if (retval)
    39. goto bad_fork_cleanup_io;
    40. if (pid != &init_struct_pid) {
    41. pid = alloc_pid(p->nsproxy->pid_ns_for_children);
    42. if (IS_ERR(pid)) {
    43. retval = PTR_ERR(pid);
    44. goto bad_fork_cleanup_io;
    45. }
    46. }

    copy_mm

  • 相关阅读:
    前端培训丁鹿学堂:vue3中setup语法糖特性写法总结
    vue2.0 监听用户无操作页面停留时长然后弹窗提示
    【数据分类】GRNN数据分类 广义回归神经网络数据分类【Matlab代码#30】
    复制交易为什么用经纪商信号?anzo capital昂首资本3点理由心服口服
    [Python进阶] 操纵鼠标:Pynput
    ​面试经典150题——LRU 缓存
    创建Vue项目的常用npm插件总结
    SpringBoot实现多数据源(四)【集成多个 Mybatis 框架】
    软考的网络工程师对就业有用吗?
    WPF Frame content binding page(Using MVVM)
  • 原文地址:https://blog.csdn.net/fengyuwuzu0519/article/details/126439202