sys_fork() in os161

$Id: os161-sys_fork.html,v 1.5 2005/10/07 02:43:44 george Exp $

sys_fork() in os161

Description

fork duplicates the currently running process. The two copies are identical, except that one (the "new" one, or "child"), has a new, unique process id, and in the other (the "parent") the process id is unchanged.

The process id must be greater than 0.

The two processes do not share memory or open file tables; this state is copied into the new process, and subsequent modification in one process does not affect the other.

However, the file handle objects the file tables point to are shared, so, for instance, calls to lseek in one process can affect the other.

Return Values

On success, fork returns twice, once in the parent process and once in the child process. In the child process, 0 is returned. In the parent process, the process id of the new child process is returned.

On error, no new process is created, fork only returns once, returning -1, and errno is set according to the error encountered.

Step

When doing a fork there are a number of things to do for the child process. Copy the currently running thread:

  1. Create child process.
    	newguy = thread_create( curthread->t_name );
  2. Create a new kernel stack in t_stack.
  3. Copy cwd.
    	/* Inherit the current directory */
    if (curthread->t_cwd != NULL) {
    VOP_INCREF(curthread->t_cwd);
    newguy->t_cwd = curthread->t_cwd;
    }
  4. Clone the open file handles, this is implementation specific and relatively easy to do.

    for-loop works for the simple condition.

  5. Copy user stack, text and data segments from parent process to child process.
    	/* Allocate a stack */
    newguy->t_stack = kmalloc(STACK_SIZE);
    if (newguy->t_stack==NULL) {
    kfree(newguy->t_name);
    kfree(newguy);
    return ENOMEM;
    }
  6. Create a new pcb by running md_initpcb.

    md_forkentry is looking promising as the function.

    	/* Set up the pcb (this arranges for func to be called) */
    newguy->t_pcb = curthread->t_pcb;

    md_initpcb( &newguy->t_pcb, newguy->t_stack, tf, 0, md_forkentry );

  7. Copy the trapframe onto the new threads kernel stack in md_forkentry().
  8. Make the new thread runnable and let it return via md_forkentry.

Race Condition

When debuging, It is a very interesting that scheduler doesn't schedule child process to run although child process is in the runqueue until parent process completes printing text. So we should lock off parent process prior to child process setup.

md_entry( struct trapframe * parent_tf ) is the very function called when child process starts to run.

child process trapframe can only be declared on child process kernel stack like md_usermode() does.

parent_tf points to the specific address which is the same in every exception handling. It is too late to access the original parent process's trapframe when child process is running. Because parent process call printf function which invokes several system call sys_write one for each character in printf.

Parent process trapframe at that time is different from the one in sys_fork() which is what child process actually needs. In order to preserve that trapframe, we should set up child process own trapframe and copy parent process trapframe before parent process invokes any other system call.

Lock off parent process using P( forksem ) before sys_fork() return and V( forksem ) in md_forkentry() after child process trapframe set.

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章