Beispiel #1
0
/*
 * Create a new thread based on an existing one.
 * The new thread has name NAME, and starts executing in function FUNC.
 * DATA1 and DATA2 are passed to FUNC.
 */
int
thread_fork(const char *name, 
	    void *data1, unsigned long data2,
	    void (*func)(void *, unsigned long),
	    pid_t *ret)
{
	struct thread *newguy;
	int s, result;

	/* Allocate a thread */
	newguy = thread_create(name);
	if (newguy==NULL) {
		return ENOMEM;
	}

	/* ASST1: Allocate a pid */
	result = pid_alloc(&newguy->t_pid);
	if (result != 0) {
	  kfree(newguy->t_name);
	  kfree(newguy);
	  return result;
	}

	/* Allocate a stack */
	newguy->t_stack = kmalloc(STACK_SIZE);
	if (newguy->t_stack==NULL) {
		pid_unalloc(newguy->t_pid); /* ASST1: cleanup pid on fail */
		kfree(newguy->t_name);
		kfree(newguy);
		return ENOMEM;
	}

	/* stick a magic number on the bottom end of the stack */
	newguy->t_stack[0] = 0xae;
	newguy->t_stack[1] = 0x11;
	newguy->t_stack[2] = 0xda;
	newguy->t_stack[3] = 0x33;

	/* Inherit the current directory */
	if (curthread->t_cwd != NULL) {
		VOP_INCREF(curthread->t_cwd);
		newguy->t_cwd = curthread->t_cwd;
	}

	/* ASST1: copy address space if there is one */
	if (curthread->t_vmspace != NULL) {
		result = as_copy(curthread->t_vmspace, &newguy->t_vmspace);
		if (result) {
			pid_unalloc(newguy->t_pid); 
			kfree(newguy->t_name);
			kfree(newguy->t_stack);
			kfree(newguy);			
			return ENOMEM;
		}
	}


	/* Set up the pcb (this arranges for func to be called) */
	md_initpcb(&newguy->t_pcb, newguy->t_stack, data1, data2, func);

	/* Interrupts off for atomicity */
	s = splhigh();

	/*
	 * Make sure our data structures have enough space, so we won't
	 * run out later at an inconvenient time.
	 */
	result = array_preallocate(sleepers, numthreads+1);
	if (result) {
		goto fail;
	}
	result = array_preallocate(zombies, numthreads+1);
	if (result) {
		goto fail;
	}

	/* Do the same for the scheduler. */
	result = scheduler_preallocate(numthreads+1);
	if (result) {
		goto fail;
	}

	/* Make the new thread runnable */
	result = make_runnable(newguy);
	if (result != 0) {
		goto fail;
	}

	/*
	 * Increment the thread counter. This must be done atomically
	 * with the preallocate calls; otherwise the count can be
	 * temporarily too low, which would obviate its reason for
	 * existence.
	 */
	numthreads++;

	/* Done with stuff that needs to be atomic */
	splx(s);

	/*
	 * Return new thread structure if it's wanted.  Note that
	 * using the thread structure from the parent thread should be
	 * done only with caution, because in general the child thread
	 * might exit at any time.
	 */
	if (ret != NULL) {
		*ret = newguy->t_pid; /* ASST1 return pid, not thread struct */
	} else {
		/* Not returning the pid... better detach the new thread */
		result = thread_detach(newguy->t_pid);
		assert(result == 0); /* can't fail. */
	}

	return 0;

 fail:
	splx(s);

	/* ASST1: cleanup pid and vmspace on fail */
	pid_unalloc(newguy->t_pid); 

	if (newguy->t_vmspace) {
		as_destroy(newguy->t_vmspace);
	}

	if (newguy->t_cwd != NULL) {
		VOP_DECREF(newguy->t_cwd);
	}
	kfree(newguy->t_stack);
	kfree(newguy->t_name);
	kfree(newguy);

	return result;
}
Beispiel #2
0
/*
 * Create a new thread based on an existing one.
 * The new threaD has name NAME, and starts executing in function FUNC.
 * DATA1 and DATA2 are passed to FUNC.
 */
int
thread_fork(const char *name, 
	    void *data1, unsigned long data2,
	    void (*func)(void *, unsigned long),
	    struct thread **ret)
{
	
	struct thread *newguy;
	int s, result;

	/* Allocate a thread */
	newguy = thread_create(name);
	if (newguy==NULL) {
		return ENOMEM;
	}

	/* Allocate a stack */
	newguy->t_stack = kmalloc(STACK_SIZE);
	if (newguy->t_stack==NULL) {
		kfree(newguy->t_name);
		kfree(newguy);
		return ENOMEM;
	}

	/* stick a magic number on the bottom end of the stack */
	newguy->t_stack[0] = 0xae;
	newguy->t_stack[1] = 0x11;
	newguy->t_stack[2] = 0xda;
	newguy->t_stack[3] = 0x33;

	/* Inherit the current directory */
	if (curthread->t_cwd != NULL) {
		VOP_INCREF(curthread->t_cwd);
		newguy->t_cwd = curthread->t_cwd;
	}
	
	/* Set up the pcb (this arranges for func to be called) */
	md_initpcb(&newguy->t_pcb, newguy->t_stack, data1, data2, func);

	/* Interrupts off for atomicity */
	s = splhigh();
	
	/*
	 * Make sure our data structures have enough space, so we won't
	 * run out later at an inconvenient time.
	 */
	result = array_preallocate(sleepers, numthreads+1);
	if (result) {
		goto fail;
	}
	result = array_preallocate(zombies, numthreads+1);
	if (result) {
		goto fail;
	}

	/* Do the same for the scheduler. */
	result = scheduler_preallocate(numthreads+1);
	if (result) {
		goto fail;
	}

	/* Make the new thread runnable */
	result = make_runnable(newguy);
	if (result != 0) {
		goto fail;
	}

	/*
	 * Increment the thread counter. This must be done atomically
	 * with the preallocate calls; otherwise the count can be
	 * temporarily too low, which would obviate its reason for
	 * existence.
	 */
	numthreads++;

	//The child's Parent PID (curthread->pid) is stored in its PPID
	newguy->parent_pid = curthread->pid;


	struct pid_node *temp;
	struct pid_node *temp2;	
	
	temp = find_node(curthread->pid); //return the pid_node of the parent.
		
	temp2 = find_node(newguy->pid); //return the pid_node of the forked child.

	if (temp->next_children == NULL) //this means that the parent has no children.
	{
		temp->next_children = temp2;
	}	
	else{ //HAS CHILDREN.
		temp = temp->next_children;
		while (temp->next_siblings != NULL){
			temp = temp->next_siblings;
		}
		temp->next_siblings = temp2;		
	
	}	
	

	/* Done with stuff that needs to be atomic */
	splx(s);

	/*
	 * Return new thread structure if it's wanted.  Note that
	 * using the thread structure from the parent thread should be
	 * done only with caution, because in general the child thread
	 * might exit at any time.
	 */
	 
	
	
	if (ret != NULL) {
		*ret = newguy;
	}

	return 0;
	

 fail:
	splx(s);
	if (newguy->t_cwd != NULL) {
		VOP_DECREF(newguy->t_cwd);
	}
	kfree(newguy->t_stack);
	kfree(newguy->t_name);
	kfree(newguy);

	return result;
}
Beispiel #3
0
/*
 * Create a new thread based on an existing one.
 * The new thread has name NAME, and starts executing in function FUNC.
 * DATA1 and DATA2 are passed to FUNC.
 */
int
thread_fork(const char *name, 
	    void *data1, unsigned long data2,
	    void (*func)(void *, unsigned long),
	    struct thread **ret)
{
    
	struct thread *newguy;
	int s, result;

	/* Allocate a thread */
	newguy = thread_create(name);
	if (newguy==NULL) {
		return ENOMEM;
	}

	/* Allocate a stack */
	newguy->t_stack = kmalloc(STACK_SIZE);
	if (newguy->t_stack==NULL) {
		kfree(newguy->t_name);
		kfree(newguy);
		return ENOMEM;
	}

	/* stick a magic number on the bottom end of the stack */
	newguy->t_stack[0] = 0xae;
	newguy->t_stack[1] = 0x11;
	newguy->t_stack[2] = 0xda;
	newguy->t_stack[3] = 0x33;

	/* Inherit the current directory */
	if (curthread->t_cwd != NULL) {
		VOP_INCREF(curthread->t_cwd);
		newguy->t_cwd = curthread->t_cwd;
	}


        #if OPT_A2
        result = conSetup(newguy);
        if(result) goto exit;
           
        // pid
        pid_t pid = newguy->pid;
        struct process* child = p_table[pid];
        assert(child != NULL);
 
        if (call_from_fork){
           int i;
           for (i = 3 ; i < MAX_FILE ; ++i) {
              if (curthread->ft[i] != NULL) {
                 newguy->ft[i] = (struct filetable*)copy_ft(curthread->ft[i]);
                 if (newguy->ft[i] == NULL) return ENOMEM;
              }
           }
           child->ppid = curthread->pid;
           call_from_fork = 0;
        }

        assert(call_from_fork == 0);
        #endif
       
	/* Set up the pcb (this arranges for func to be called) */
	md_initpcb(&newguy->t_pcb, newguy->t_stack, data1, data2, func);

	/* Interrupts off for atomicity */
	s = splhigh();

	/*
	 * Make sure our data structures have enough space, so we won't
	 * run out later at an inconvenient time.
	 */
	result = array_preallocate(sleepers, numthreads+1);
	if (result) {
		goto fail;
	}
	result = array_preallocate(zombies, numthreads+1);
	if (result) {
		goto fail;
	}

	/* Do the same for the scheduler. */
	result = scheduler_preallocate(numthreads+1);
	if (result) {
		goto fail;
	}

	/* Make the new thread runnable */
	result = make_runnable(newguy);
	if (result != 0) {
		goto fail;
	}




//kprintf("gonna run fork func\n");
	/*
	 * Increment the thread counter. This must be done atomically
	 * with the preallocate calls; otherwise the count can be
	 * temporarily too low, which would obviate its reason for
	 * existence.
	 */
	numthreads++;

	/* Done with stuff that needs to be atomic */
	splx(s);

	/*
	 * Return new thread structure if it's wanted.  Note that
	 * using the thread structure from the parent thread should be
	 * done only with caution, because in general the child thread
	 * might exit at any time.
	 */
	if (ret != NULL) {
		*ret = newguy;
                //kprintf("new thread returns\n");
	}
      //  kprintf("comfirm the new pid is %d\n",(*ret)->pid);
	return 0;

 fail:
	splx(s);
 exit:	if (newguy->t_cwd != NULL) {
		VOP_DECREF(newguy->t_cwd);
	}
	kfree(newguy->t_stack);
	kfree(newguy->t_name);
	kfree(newguy);

	return result;
}
Beispiel #4
0
/*
 * Create a new thread based on an existing one.
 * The new thread has name NAME, and starts executing in function FUNC.
 * DATA1 and DATA2 are passed to FUNC.
 */
int
thread_fork(const char *name,
            void *data1, unsigned long data2,
            void (*func)(void *, unsigned long),
            struct thread **ret)
{
	struct thread *newguy;
	int s, result;
    
	/* Allocate a thread */
	newguy = thread_create(name);
	if (newguy==NULL) {
		return ENOMEM;
	}
    
	/* Allocate a stack */
	newguy->t_stack = kmalloc(STACK_SIZE);
	if (newguy->t_stack==NULL) {
		kfree(newguy->t_name);
		kfree(newguy);
		return ENOMEM;
	}
    
	/* stick a magic number on the bottom end of the stack */
	newguy->t_stack[0] = 0xae;
	newguy->t_stack[1] = 0x11;
	newguy->t_stack[2] = 0xda;
	newguy->t_stack[3] = 0x33;
    
	/* Inherit the current directory */
	if (curthread->t_cwd != NULL) {
		VOP_INCREF(curthread->t_cwd);
		newguy->t_cwd = curthread->t_cwd;
	}
    
#if OPT_A2
    
    if(curthread->forkcalled) {
        int i, res, spl;
        //copy address space
        res = as_copy(curthread->t_vmspace,&newguy->t_vmspace);
        if (res) {
            //kprintf("as_copy failed in thread_fork, curthread_vmspace_addr: %p, newguy_vmspace_addr: %p\n", curthread->t_vmspace, newguy->t_vmspace);
            return res;
        }
        as_activate(curthread->t_vmspace); /* FIXME if wrong comment this out and retry */
        //copy vnodes
//        spl = splhigh();
        for(i=3;i<MAX_OPENED_FILES;i++) {
            if(curthread->files[i]!=NULL) {
                newguy->files[i] = files_create(kstrdup(curthread->files[i]->filename), curthread->files[i]->vn, curthread->files[i]->flags);
                VOP_INCOPEN(newguy->files[i]->vn);
                VOP_INCREF(newguy->files[i]->vn);
            } else {
                break;
            }
        }
//        splx(spl);
        
        curthread->forkcalled = 0;
    }
#endif
    
	/* Set up the pcb (this arranges for func to be called) */
	md_initpcb(&newguy->t_pcb, newguy->t_stack, data1, data2, func);
    
	/* Interrupts off for atomicity */
	s = splhigh();
    
	/*
	 * Make sure our data structures have enough space, so we won't
	 * run out later at an inconvenient time.
	 */
	result = array_preallocate(sleepers, numthreads+1);
	if (result) {
		goto fail;
	}
	result = array_preallocate(zombies, numthreads+1);
	if (result) {
		goto fail;
	}
    
	/* Do the same for the scheduler. */
	result = scheduler_preallocate(numthreads+1);
	if (result) {
		goto fail;
	}
    
	/* Make the new thread runnable */
	result = make_runnable(newguy);
	if (result != 0) {
		goto fail;
	}
    
	/*
	 * Increment the thread counter. This must be done atomically
	 * with the preallocate calls; otherwise the count can be
	 * temporarily too low, which would obviate its reason for
	 * existence.
	 */
	numthreads++;
    
	/* Done with stuff that needs to be atomic */
	splx(s);
    
	/*
	 * Return new thread structure if it's wanted.  Note that
	 * using the thread structure from the parent thread should be
	 * done only with caution, because in general the child thread
	 * might exit at any time.
	 */
	if (ret != NULL) {
		*ret = newguy;
	}
    
	return 0;
    
fail:
	splx(s);
	if (newguy->t_cwd != NULL) {
		VOP_DECREF(newguy->t_cwd);
	}
	kfree(newguy->t_stack);
	kfree(newguy->t_name);
	kfree(newguy);
    
	return result;
}
Beispiel #5
0
/*
 * Create a new thread based on an existing one.
 * The new thread has name NAME, and starts executing in function FUNC.
 * DATA1 and DATA2 are passed to FUNC.
 */
int
thread_fork(const char *name,
            void *data1, unsigned long data2,
            void (*func)(void *, unsigned long),
            struct thread **ret)
{
    struct thread *newguy;
    int s, result;

    /* Allocate a thread */
    newguy = thread_create(name);
    //kprintf("New thread created\n");
    if (newguy == NULL)
    {
        return ENOMEM;
    }

    /* Allocate a stack */
	    //newguy->t_stack = kmalloc(sizeof(char*));
	//kprintf("%d\n",sizeof(char*));
	//kprintf("%d\n",STACK_SIZE);	
    newguy->t_stack = kmalloc(STACK_SIZE);
    //kprintf("stack allocated!!!\n");
    if (newguy->t_stack == NULL)
    {
	kprintf("new guy have a null stack?!\n");
        kfree(newguy->t_name);
        kfree(newguy);
        return ENOMEM;
    }

    /* stick a magic number on the bottom end of the stack */
    newguy->t_stack[0] = 0xae;
    newguy->t_stack[1] = 0x11;
    newguy->t_stack[2] = 0xda;
    newguy->t_stack[3] = 0x33;

    /* Inherit the current directory */
    //kprintf("inheritting current directory...\n");
    if (curthread->t_cwd != NULL)
    {
        VOP_INCREF(curthread->t_cwd);
        newguy->t_cwd = curthread->t_cwd;
    }
    //kprintf("start setting up pcb!!!\n");
    /* Set up the pcb (this arranges for func to be called) */
    md_initpcb(&newguy->t_pcb, newguy->t_stack, data1, data2, func);

    /* Interrupts off for atomicity */
    s = splhigh();

    // create process for this thread
    result = create_process (newguy);
   // kprintf("process created!!!\n");
    if (result)
    {
        goto fail;
    }

    /*
     * Make sure our data structures have enough space, so we won't
     * run out later at an inconvenient time.
     */
    result = array_preallocate(sleepers, numthreads + 1);
    if (result)
    {
        goto fail;
    }
    result = array_preallocate(zombies, numthreads + 1);
    if (result)
    {
        goto fail;
    }

    /* Do the same for the scheduler. */
    result = scheduler_preallocate(numthreads + 1);
    if (result)
    {
        goto fail;
    }

    /* Make the new thread runnable */
	//kprintf("before make_runcable! - pid %d\n", curthread->t_pid);
    result = make_runnable(newguy);
	//kprintf("magical make_runcable! - pid %d\n", curthread->t_pid);
    if (result != 0)
    {
        goto fail;
    }

    /*
     * Increment the thread counter. This must be done atomically
     * with the preallocate calls; otherwise the count can be
     * temporarily too low, which would obviate its reason for
     * existence.
     */
    numthreads++;

    /* Done with stuff that needs to be atomic */
    splx(s);

    /*
     * Return new thread structure if it's wanted.  Note that
     * using the thread structure from the parent thread should be
     * done only with caution, because in general the child thread
     * might exit at any time.
     */
    if (ret != NULL)
    {
        *ret = newguy;
    }

    return 0;

fail:
    splx(s);
    if (newguy->t_cwd != NULL)
    {
        VOP_DECREF(newguy->t_cwd);
    }
    kfree(newguy->t_stack);
    kfree(newguy->t_name);
    kfree(newguy);

    return result;
}