· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
do_fork

do_fork( ) makes use of an auxiliary function called copy_process( ) to set up the process descriptor and any other kernel data structure required for child's execution. Here are the main steps performed by do_fork( )

  1. Allocates a new PID for the child by looking in the pidmap_array bitmap
  2. Checks the ptrace field of the parent (current->ptrace): if it is not zero, the parent process is being traced by another process, thus do_fork( ) checks whether the debugger wants to trace the child on its own (independently of the value of the CLONE_PTRACE flag specified by the parent); in this case, if the child is not a kernel thread (CLONE_UNTRACED flag cleared), the function sets the CLONE_PTRACE flag.
  3. Invokes copy_process() to make a copy of the process descriptor. If all needed resources are available, this function returns the address of the task_struct descriptor just created. This is the workhorse of the forking procedure, and we will describe it right after do_fork( ).
  4. If either the CLONE_STOPPED flag is set or the child process must be traced, that is, the PT_PTRACED flag is set in p->ptrace, it sets the state of the child to TASK_STOPPED and adds a pending SIGSTOP signal to it (see the section "The Role of Signals" in Chapter 11). The state of the child will remain TASK_STOPPED until another process (presumably the tracing process or the parent) will revert its state to TASK_RUNNING, usually by means of a SIGCONT signal.
  5. If the CLONE_STOPPED flag is not set, it invokes the wake_up_new_task( ) function, which performs the following operations:
    1. Adjusts the scheduling parameters of both the parent and the child
    2. If the child will run on the same CPU as the parent,[1] and parent and child do not share the same set of page tables (CLONE_VM flag cleared), it then forces the child to run before the parent by inserting it into the parent's runqueue right before the parent.This simple step yields better performance if the child flushes its address space and executes a new program right after the forking. If we let the parent run first, the Copy On Write mechanism would give rise to a series of unnecessary page duplications.
    3. Otherwise, if the child will not be run on the same CPU as the parent, or if parent and child share the same set of page tables (CLONE_VM flag set), it inserts the child in the last position of the parent's runqueue
  6. If the CLONE_STOPPED flag is set, it puts the child in the TASK_STOPPED state.
  7. If the parent process is being traced, it stores the PID of the child in the ptrace_message field of current and invokes ptrace_notify( ), which essentially stops the current process and sends a SIGCHLD signal to its parent. The "grandparent" of the child is the debugger that is tracing the parent; the SIGCHLD signal notifies the debugger that current has forked a child, whose PID can be retrieved by looking into the current->ptrace_message field.
  8. If the CLONE_VFORK flag is specified, it inserts the parent process in a wait queue and suspends it until the child releases its memory address space (that is, until the child either terminates or executes a new program).
  9. Terminates by returning the PID of the child.

The copy_process( ) function

The copy_process( ) function sets up the process descriptor and any other kernel data structure required for a child's execution. Its parameters are the same as do_fork( ), plus the PID of the child. Here is a description of its most significant steps:

  1. Checks whether the flags passed in the clone_flags parameter are compatible.
  2. Performs any additional security checks by invoking security_task_create( ) and, later, security_task_alloc( ).
  3. Invokes dup_task_struct( ) to get the process descriptor for the child. This function performs the following actions
    1. Invokes _ _unlazy_fpu( ) on the current process to save, if necessary, the contents of the FPU, MMX, and SSE/SSE2 registers in the thread_info structure of the parent. Later, dup_task_struct( ) will copy these values in the thread_info structure of the child.
    2. Executes the alloc_task_struct( ) macro to get a process descriptor (task_struct structure) for the new process, and stores its address in the tsk local variable.
    3. Executes the alloc_thread_info macro to get a free memory area to store the thread_info structure and the Kernel Mode stack of the new process, and saves its address in the ti local variable
    4. Copies the contents of the current's process descriptor into the task_struct structure pointed to by tsk, then sets tsk->thread_info to ti.
    5. Copies the contents of the current's thread_info descriptor into the structure pointed to by ti, then sets ti->task to tsk
    6. Sets the usage counter of the new process descriptor (tsk->usage) to 2 to specify that the process descriptor is in use and that the corresponding process is alive (its state is not EXIT_ZOMBIE or EXIT_DEAD).
    7. Returns the process descriptor pointer of the new process (tsk).
  4. Checks whether the value stored in current->signal->rlimRLIMIT_NPROC.rlim_cur is smaller than or equal to the current number of processes owned by the user. If so, an error code is returned, unless the process has root privileges. The function gets the current number of processes owned by the user from a per-user data structure named user_struct. This data structure can be found through a pointer in the user field of the process descriptor
´ÙÀ½ ³»¿ëµéÀº ÇöÀç º°·Î °ü½É»ç°¡ ¾Æ´Ô



ID
Password
Join
A plucked goose doesn't lay golden eggs.


sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2006-05-28 16:46:07
Processing time 0.0045 sec