Exemple #1
0
/*
 * ft_create()
 * Creates a file table that is attached to the thread library.
 * 
 */
struct filetable *ft_create() {
    //Allocate memory for the filetable structures
    struct filetable *ft = kmalloc(sizeof (struct filetable));
    if (ft == NULL) {
        return NULL;
    }
    ft->size = 0;
    //Allocate memory for the array of file descriptors
    ft->filedescriptor = array_create();
    if (ft->filedescriptor == NULL) {
        ft_destroy(ft);
        return NULL;
    }
    //preallocate the array to 20 files
    array_preallocate(ft->filedescriptor, 20);
    //Reserve the first three file descriptors for in out err.
    array_add(ft->filedescriptor, NULL);
    array_add(ft->filedescriptor, NULL);
    array_add(ft->filedescriptor, NULL);
    //Return the file table
    return ft;
}
Exemple #2
0
struct array *ftab_init(void){
	struct vnode *v;
	struct fildes *fdes;
	struct array *OFtable;

	OFtable = array_create();
	array_setsize(OFtable, OPEN_MAX);
	array_preallocate(OFtable, OPEN_MAX);


	/* Open console as stdout and stderr */
	int result = vfs_open((char *)"con:", O_WRONLY, 0777, &v);
	(void)result;

	fdes = fd_init(v, 0777, 0);
	if(fdes){
		/* Attach stdout/stderr to file table */
		ftab_set(OFtable, fdes, 1);
		ftab_set(OFtable, fdes, 2);
	}

	return OFtable;
}
int
array_setsize(struct array *a, int nguys)
{
	int result, i;

	assert(a->num >=0 && a->num <= a->max);

	if (nguys > a->max) {
		result = array_preallocate(a, nguys);
		if (result) {
			return result;
		}
	}
	else if (nguys==0 && a->max > 16) {
		assert(a->v!=NULL);
		kfree(a->v);
		a->v = NULL;
		a->max = 0;
	}
	for (i = a->num; i < nguys; i++) a->v[i] = NULL;
	a->num = nguys;

	return 0;
}
Exemple #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),
	    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;
}
Exemple #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);
	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;
}
Exemple #6
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;
}
Exemple #7
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;
}
/*
 * Create a proc structure.
 */
static struct proc *
proc_create(const char *name) {
	struct proc *proc;

	proc = kmalloc(sizeof(*proc));
	if (proc == NULL) {
		return NULL;
	}
	proc->p_name = kstrdup(name);
	if (proc->p_name == NULL) {
		kfree(proc);
		return NULL;
	}

	proc->p_numthreads = 0;
	spinlock_init(&proc->p_lock);

	/* VM fields */
	proc->p_addrspace = NULL;

	/* VFS fields */
	proc->p_cwd = NULL;

	/** file table */

	proc->p_filetable = array_create();
	//kprintf("TEMPPP: Newly created filetable %p\n",proc->p_filetable);
	if (proc->p_filetable == NULL) {
		spinlock_cleanup(&proc->p_lock);
		kfree(proc->p_name);
		kfree(proc);
		return NULL;
	}
	if(array_preallocate(proc->p_filetable, 1024) == ENOMEM) {
		array_destroy(proc->p_filetable);
		spinlock_cleanup(&proc->p_lock);
		kfree(proc->p_name);
		kfree(proc);
		return NULL;
	}
	proc->p_waitcvlock = lock_create(name);
	if (proc->p_waitcvlock == NULL) {
		array_destroy(proc->p_filetable);
		spinlock_cleanup(&proc->p_lock);
		kfree(proc->p_name);
		kfree(proc);
		return NULL;
	}

	proc->p_waitcv = cv_create(name);
	if (proc->p_waitcv == NULL) {
		lock_destroy(proc->p_waitcvlock);
		array_destroy(proc->p_filetable);
		spinlock_cleanup(&proc->p_lock);
		kfree(proc->p_name);
		kfree(proc);
		return NULL;
	}

	proc->p_opslock = lock_create(name);
	if (proc->p_opslock == NULL) {
		cv_destroy(proc->p_waitcv);
		lock_destroy(proc->p_waitcvlock);
		array_destroy(proc->p_filetable);
		spinlock_cleanup(&proc->p_lock);
		kfree(proc->p_name);
		kfree(proc);
		return NULL;
	}
	proc->p_state = PS_RUNNING;

	proc->p_returnvalue = -1;

	proc->p_fdcounter = 0;

	// add the process to the process table

	return proc;
}
Exemple #9
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;
}