Talking about the whole process of creating new process of Linux kernel _linux

Source: Internet
Author: User
Tags goto

Process description

    • Process Descriptor (TASK_STRUCT)

The data structure used to describe a process can be understood as a property of a process. such as the state of the process, the identity of the process (PID), etc., are encapsulated in the process descriptor of the data structure, the data structure is defined as Task_struct

    • Process Control block (PCB)

is a data structure in the core of the operating system, which mainly represents the process state.

    • Process status

    • Fork ()

Fork () is returned once in the parent, child process. Returns the PID of a subprocess in the parent process, returning 0 in the subprocess.

Fork code for a child process

#include <stdio.h>

#include <stdlib.h>

#include <unistd.h>

int main (int argc, char * Argv[])
{
int pid;
/* Fork Another process

/pid = fork ();
if (PID < 0) 
{/ 
  * error occurred *
  /fprintf (stderr, "Fork failed!");
  Exit ( -1);
} 
else if (PID = = 0) 
{/
  * child process *
  /printf ("This is Child process!\n");
} 
else 
{ 
  /* parent Process
  /printf ("This is parent process!\n");
  /* Parent would wait for the child to complete*/wait
  (NULL);
  printf ("Child complete!\n");
}


Process creation

1. General process

Fork through the 0x80 interrupt (System call) to the kernel, the system provided by the corresponding system call to complete the process creation.

FORK.C//fork #ifdef __arch_want_sys_fork syscall_define0 (fork) {#ifdef Config_mmu return do_fork (sigchld, 0, 0, NULL,
NULL);
#else/* Can not support in Nommu mode */return-einval; #endif} #endif//vfork #ifdef __arch_want_sys_vfork syscall_define0 (vfork) {return do_fork Clone_vfork | CLONE_VM |
SIGCHLD, 0, 0, NULL, NULL); #endif//clone #ifdef __arch_want_sys_clone #ifdef config_clone_backwards syscall_define5 (clone, unsigned long, clone_ Flags, unsigned long, newsp, int __user *, parent_tidptr, int, tls_val, int __user *, child_tidptr) #elif D efined (CONFIG_CLONE_BACKWARDS2) syscall_define5 (CLONE, unsigned long, newsp, unsigned long, clone_flags, int __user * , parent_tidptr, int __user *, child_tidptr, int, tls_val) #elif defined (CONFIG_CLONE_BACKWARDS3) syscall_define 6 (clone, unsigned long, clone_flags, unsigned long, newsp, int, stack_size, int __user *, parent_tidptr, int _ _user *, child_tidptr, int, tls_val) #elSe syscall_define5 (clone, unsigned long, clone_flags, unsigned long, newsp, int __user *, parent_tidptr, int __u Ser *, child_tidptr, int, tls_val) #endif {return do_fork (clone_flags, newsp, 0, Parent_tidptr, child_tidptr);

 endif

By looking at the code above, we can see clearly that the process is created either by using fork or vfork, and ultimately through the Do_fork () method. Next we can trace the code to Do_fork ():

Long do_fork (unsigned long clone_flags, unsigned long stack_start, unsigned long stack_size, int __user *p

    arent_tidptr, int __user *child_tidptr) {//Create process descriptor pointer struct task_struct *p;
    ...//copy process descriptor, the return value of Copy_process () is a task_struct pointer.

    p = copy_process (Clone_flags, Stack_start, Stack_size, Child_tidptr, NULL, Trace);
      if (!is_err (p)) {struct completion vfork;

      struct PID *pid;

      Trace_sched_process_fork (current, p);
      Gets the PID PID in the newly created process descriptor = Get_task_pid (P, pidtype_pid);

      NR = PID_VNR (PID);

      if (Clone_flags & Clone_parent_settid) Put_user (NR, parent_tidptr);
      If the Vfork () method is invoked, initialization vfork completes processing information.
        if (Clone_flags & clone_vfork) {P->vfork_done = &vfork;
        Init_completion (&vfork);
      Get_task_struct (P);

      ////Add the child process to the scheduler, allocate the CPU for it, and prepare to execute Wake_up_new_task (p); Fork completes, the subprocess is about to begin running if (unlikely (trace)) Ptrace_Event_pid (Trace, PID); If it is vfork, add the parent process to the wait queue and wait for the child process to complete the IF (Clone_flags & clone_vfork) {if (!wait_for_vfork_done p, &vfork)
      ) Ptrace_event_pid (Ptrace_event_vfork_done, PID);
    } put_pid (PID);
    else {nr = Ptr_err (p);
} return nr;

 }

2, Do_fork process

    • Call copy_process to copy a process information for a child process
    • If it is vfork initialization completes processing information
    • Call Wake_up_new_task to add the child process to the scheduler and allocate the CPU
    • If it is vfork, the parent process waits for the child process to complete exec to replace its own address space

3, copy_process process

Trace copy_process Code (partial)

static struct task_struct *copy_process (unsigned long clone_flags, unsigned long stack_start, Unsigne

  D long stack_size, int __user *child_tidptr, struct PID *pid, int trace) {int retval;

  Create a process descriptor pointer struct task_struct *p;

  ...//Copy the current task_struct p = dup_task_struct;

  ..//Initialize mutually exclusive variable rt_mutex_init_task (p); Check if the number of processes exceeds the limit, defined by the operating system if (Atomic_read (&p->real_cred->user->processes) >= task_rlimit (p, RLIMIT_NPR OC)) {if (P->real_cred->user!= init_user &&!capable (cap_sys_resource) &&!capable (cap_s
  ys_admin)) goto Bad_fork_free;

  ///... check if the process count exceeds max_threads by memory size if (nr_threads >= max_threads) goto Bad_fork_cleanup_count;
  ...//Initialize spin lock Spin_lock_init (&p->alloc_lock);
  Initialization of the suspend signal init_sigpending (&p->pending);


  Initialize CPU timer posix_cpu_timers_init (p); ...//Initialize process data structure and set process status to task_running RETval = sched_fork (Clone_flags, p);

  Copy all process information, including file system, signal processing function, signal, memory management, etc. if (retval) goto bad_fork_cleanup_policy;
  retval = Perf_event_init_task (p);
  if (retval) goto bad_fork_cleanup_policy;
  retval = Audit_alloc (p);
  if (retval) goto Bad_fork_cleanup_perf;
  /* Copy all the process information/shm_init_task (p);
  retval = Copy_semundo (Clone_flags, p);
  if (retval) goto Bad_fork_cleanup_audit;
  retval = Copy_files (Clone_flags, p);
  if (retval) goto Bad_fork_cleanup_semundo;
  retval = Copy_fs (Clone_flags, p);
  if (retval) goto bad_fork_cleanup_files;
  retval = Copy_sighand (Clone_flags, p);
  if (retval) goto bad_fork_cleanup_fs;
  retval = copy_signal (Clone_flags, p);
  if (retval) goto Bad_fork_cleanup_sighand;
  retval = copy_mm (Clone_flags, p);
  if (retval) goto bad_fork_cleanup_signal;
  retval = Copy_namespaces (Clone_flags, p);
  if (retval) goto bad_fork_cleanup_mm;

  retval = Copy_io (Clone_flags, p); Initializing child process kernel stack RetvAl = Copy_thread (Clone_flags, Stack_start, Stack_size, p);
    Assigns a new PID if (PID!= &init_struct_pid) {retval =-enomem to the new process;
    PID = Alloc_pid (P->nsproxy->pid_ns_for_children);
  if (!pid) goto bad_fork_cleanup_io;


  //Set SUB process pid P->pid = PID_NR (PID);

 ..//Return to the structure p returns p;
    • Call Dup_task_struct Copy the current task_struct
    • Check if the number of processes exceeds the limit
    • Initialize spin lock, suspend signal, CPU timer, etc.
    • Invokes the Sched_fork initialization process data structure and sets the process state to task_running
    • Copy all process information, including file system, signal processing function, signal, memory management, etc.
    • Call Copy_thread initialization subprocess kernel stack
    • Assigning and setting a new PID for a new process

4, dup_task_struct process

static struct task_struct *dup_task_struct (struct task_struct *orig)
{struct task_struct
  ;
  struct Thread_info *ti;
  int node = Tsk_fork_get_node (orig);
  int err;

  Assigns a task_struct node
  tsk = alloc_task_struct_node (node);
  if (!tsk) return
    NULL;

  Assign a Thread_info node that contains the kernel stack of the process, TI is the stack bottom
  ti = Alloc_thread_info_node (tsk, node);
  if (!ti)
    goto Free_tsk;

  The stack
  tsk->stack = Ti, which assigns the bottom value of the stack to the new node;

  ..... return tsk;

}

Call Alloc_task_struct_node Assign a task_struct node
Call Alloc_thread_info_node allocate a thread_info node, in fact, is allocated a thread_union consortium, the bottom of the stack back to Ti

Union thread_union {
  struct thread_info thread_info;
 unsigned long stack[thread_size/sizeof (long)];

Finally, we assign the value ti to the stack of the new node.
After the dup_task_struct is finished, the child process is the same except for the Tsk->stack pointer!
5, sched_fork process

Core.c

int sched_fork (unsigned long clone_flags, struct task_struct *p)
{
  unsigned long flags;
  int cpu = GET_CPU ();

  __sched_fork (Clone_flags, p);

  Sets the child process state to task_running
  p->state = task_running;

  ..... Allocate CPU
  SET_TASK_CPU (p, CPU) for child processes;

  Put_cpu ();
  return 0;
}

We can see that Sched_fork has roughly completed two important tasks, one is to set the child process state to task_running, and the other is to allocate CPU for it
6, Copy_thread process

int Copy_thread (unsigned long clone_flags, unsigned long sp, unsigned long arg, struct task_struct *p) {//Get register information
  struct Pt_regs *childregs = Task_pt_regs (p);
  struct Task_struct *tsk;

  int err;
  P-&GT;THREAD.SP = (unsigned long) childregs;
  P->thread.sp0 = (unsigned long) (childregs+1);

  memset (p->thread.ptrace_bps, 0, sizeof (p->thread.ptrace_bps));
    if (Unlikely (P->flags & Pf_kthread)) {//Kernel thread memset (childregs, 0, sizeof (struct pt_regs));
    P->thread.ip = (unsigned long) ret_from_kernel_thread;
    Task_user_gs (p) = __kernel_stack_canary;
    Childregs->ds = __user_ds;
    Childregs->es = __user_ds;
    Childregs->fs = __KERNEL_PERCPU; CHILDREGS-&GT;BX = SP;
    /* Function */childregs->bp = arg;
    Childregs->orig_ax =-1; Childregs->cs = __kernel_cs |
    GET_KERNEL_RPL (); Childregs->flags = x86_eflags_if |
    x86_eflags_fixed;
    P->thread.io_bitmap_ptr = NULL;
  return 0; ///Copy current register information to child process *chIldregs = *current_pt_regs ();
  The subprocess eax 0, so the fork returns 0 Childregs->ax = 0 in the subprocess;

  if (sp) childregs->sp = SP;

  The child process IP is set to Ret_from_fork, so the subprocess executes P->thread.ip = (unsigned long) ret_from_fork from Ret_from_fork;
... return err;

 }

Copy_thread This code explains two very important questions!
One is why fork returns 0 in the subprocess because childregs->ax = 0; This code assigns the eax of the child process to 0
The second is,P->thread.ip = (unsigned long) ret_from_fork, the IP of the child process is set to the first address of ret_form_fork, so the child process starts from the Ret_from_fork
Summary

The implementation of the new process stems from the following prerequisites:

    • A new stack is assigned to it in the dup_task_struct
    • Called the sched_fork and placed it as task_running
    • Copy_thread copies the register context of the parent process to the child process, ensuring that the stack information for parent-child processes is consistent
    • Set the Ret_from_fork address to the value of the EIP register

The final subprocess is executed from the ret_from_fork.

The above is the Linux kernel to create a new process of the detailed analysis of the process, I hope that the study has helped.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.