Beispiel #1
0
pid_t fork(struct trapframe *ptf, int *error)
{
	struct trapframe *ctf = NULL;
	ctf = kmalloc(sizeof(struct trapframe));
	if(ctf == NULL){
		*error = ENOMEM;
		return -1;
	}
	memcpy(ctf, ptf, sizeof(struct trapframe));

	struct addrspace *caddr = kmalloc(sizeof(struct addrspace));
	*error = as_copy(curthread->t_addrspace, &caddr);

	// new
	if(*error > 0){
		return -1;
	}

	struct thread *child_thread;
	*error = thread_fork("fork",
			child_fork_entry,
			ctf,
			(unsigned long)caddr,
			&child_thread);

	if(child_thread == NULL){
		*error = ENOMEM;
		return -1;
	}
	if(*error > 0){
		return -1;
	}

	return child_thread->pid;
}
Beispiel #2
0
pid_t sys_fork(struct trapframe *tf)
{
	struct trapframe *newtrapframe =kmalloc(sizeof(struct trapframe ));
	*newtrapframe = *tf;
	//memcpy(newtrapframe,tf ,sizeof(struct trapframe ));
	int result ;

	struct addrspace *newaddrspace;
	result = as_copy(curthread->t_addrspace,&newaddrspace);

	if(result)
	{
		return result;
	}

	struct thread *newthread ;

	result = thread_fork("childthread", child_process_entry, newtrapframe,(unsigned long)newaddrspace,&newthread);
	if (result)
	{
		return result ;
	}

	tf->tf_v0 = newthread->pid;
	tf->tf_a3 = 0;

	return -(newthread->pid) ;
}
Beispiel #3
0
pid_t sys_fork(struct trapframe * tf, int *retval)
{
	struct trapframe *ntf;
	int result;

	ntf = (struct trapframe *)kmalloc(sizeof(struct trapframe));
	
	if (ntf==NULL) {
		return ENOMEM;
	}
	
	memcpy(ntf,tf,sizeof(struct trapframe));

	struct thread * child;
	struct fork_data * fork_data = (struct fork_data*) kmalloc(sizeof(struct fork_data));

	fork_data->tf = ntf;

	as_copy(curthread->t_vmspace, &fork_data->addr);

	result = thread_fork(curthread->t_name, fork_data, 0, md_forkentry, &child);

	*retval = child->pid;

	return 0;
}
Beispiel #4
0
int sys_fork(struct trapframe* tf, pid_t* retval) {
	int errcheck;    //this is to check if there's error in some funcitons
	//first creating a new proc
	struct proc* child = proc_create_runprogram("child123");
   //proctable_insert(child);
	if(child == NULL) {
		return ENOMEM;
	}
	curproc->child_pid = child->pid;
	curproc->child = child;      ///////////////
	child->parent = curproc;     //////////////
	
	//now, copying the address space
	struct addrspace* newas;
	errcheck = as_copy(curproc_getas(), &newas);
	if(errcheck != 0) {    //there's an error
		return errcheck;
	}
	child->p_addrspace = newas;
	
	//now copying the trapframe to the child
	struct trapframe* newtf = kmalloc(sizeof(struct trapframe));
	if(newtf == NULL) {
		return ENOMEM;
	}
	*newtf = *tf;
	//now, do the thread_fork
	errcheck = thread_fork("child2", child, enter_forked_process, newtf, 0);
	if(errcheck != 0) {
		return errcheck;
	}
	*retval = child->pid;
	return(0);
}
Beispiel #5
0
int sys_fork(struct trapframe *tf, int * retval){
	int spl = splhigh();
	struct addrspace * child_vmspace;
	// copy the parent's address space
	int result = as_copy(curthread->t_vmspace, &child_vmspace);
	if(result){
		splx(spl);
		return result;
	}
	struct thread *child_thread = NULL;
	// duplicate the parent's trapframe, which is on this kernel thread's stack
	// we need to copy the trapframe to kernel heap
	struct  trapframe* child_tf = kmalloc(sizeof(struct trapframe));

	if (child_tf == NULL) {
		splx(spl);
		return ENOMEM;
	}	
	*child_tf = *tf; 


	// create child thread/process
	result =  thread_fork("child_process", 
		(void*)child_tf, (unsigned long)child_vmspace, 
		md_forkentry,
		&child_thread);

	assert(child_thread != NULL);
	// parent returns the child pID
	*retval = child_thread->pID;
	splx(spl);
	return 0;

}
Beispiel #6
0
// -----------------------------------------------------------------
// Copy self-dual scalar fields in the site struct
void scalar_field_copy(field_offset src, field_offset dest) {
  register int i;
  register site *s;

  FORALLSITES(i, s)
    as_copy((antisym *)F_PT(s, src), (antisym *)F_PT(s, dest));
}
Beispiel #7
0
int sys_fork(struct trapframe *tf)
{
         struct thread* newthread;
         struct trapframe* newtf; 
         struct addrspace* newas; 
         int result;
     
         
       	 newtf = (struct trapframe*) kmalloc(sizeof(struct trapframe));
	 if (newtf == NULL){
          return  ENOMEM;
} 
        *newtf = *tf;

        int err;

        err= as_copy(curthread->t_vmspace,&newas);

        if (err){
        return ENOMEM;
}
        as_activate(curthread->t_vmspace);
      
         result = thread_fork(curthread->t_name, newtf,(unsigned long)newas,
                 (void (*)(void *, unsigned long)) md_forkentry,&newthread);

	
         if (result) 
         	return -ENOMEM;
         return newthread->t_pid;
}
Beispiel #8
0
void 
md_forkentry(void * data1, unsigned long unused) {
	//(void)unused;
	struct fork_info * info = data1;
	struct addrspace * new_as;
	struct trapframe new_tf;
	/* copy address space */
	if (as_copy(info->parent->t_vmspace, &new_as)) {
		info->child_pid = ENOMEM; // Means no memory for process
		V(info->sem);	// child is done, parent should resume.
		thread_exit();
	}
	curthread->t_vmspace = new_as;
	as_activate(new_as);

	/* copy trap frame  */
	memcpy(&new_tf, info->tf, sizeof(struct trapframe));
	/* change tf's registers to return values for syscall */
	new_tf.tf_v0 = 0;
	new_tf.tf_a3 = 0;
	new_tf.tf_epc += 4;
	/* create process and get the pid */
	struct thread *new_process = kmalloc(sizeof(struct thread));
	 new_process->parent_pid = curthread->t_pid;
	proc_table++; 
	new_process->t_pid = create_tpid();
	proc_table++;
	

	V(info->sem);
	mips_usermode(&new_tf);
	/* mips_usermode does not return */
}
int sys_fork(struct trapframe *tf, pid_t *retval){

  const char* name = "Anonymous student's process";


// create process struct for child
  struct proc *childp = proc_create_runprogram(name);
  if(childp == NULL){
    return ENOMEM; //OUT OF MEMORY
  }

// create and copy as to child
  struct addrspace* childas = kmalloc(sizeof(struct addrspace));
  if(childas == NULL){
    proc_destroy(childp);
    return ENOMEM;
  }

  if(as_copy(curproc->p_addrspace, &childas)){
    kfree(childas);
    as_destroy(childas);
    proc_destroy(childp);
    return ENOMEM;
  }
// attach new as to child proc
  childp->p_addrspace = childas;
  
// create parent child relationship
  struct procinfo *pi = array_get(procinfotable, childp->pid - 1);
  if(pi == NULL){
    kfree(childas);
    as_destroy(childas);
    proc_destroy(childp);
    return ECHILD; // NO SUCH CHILD IN THE INFO TABLE
  }
  pi->parent_pid = curproc->pid;

// create thread for child and pass it tf
  struct trapframe *childtf = kmalloc(sizeof(struct trapframe));
  memcpy(childtf,tf,sizeof(struct trapframe));

  void ** data = kmalloc(2*sizeof(void*));
  data[0] = (void*)childtf;
  data[1] = (void*)childas; 

  int err = thread_fork(name, childp,(void *)enter_forked_process, data, 0);
  if(err){
    kfree(childas);
    kfree(childtf);
    as_destroy(childas);
    proc_destroy(childp);
    kfree(childtf);
    return ENOMEM;
  }


  *retval = childp->pid;
  return 0;
}
Beispiel #10
0
/*
  Duplicates the currently running process
  The two copies are identical except for the child having a new pid
*/
int
sys_fork(struct trapframe *tf, int32_t *retval) {

  // Prevent interrupts so address space doesn't change before getting
  // copied
  int spl = splhigh();

  // Store trapframe on the heap for copying to child
  // thread later
  struct trapframe *child_tf;
  child_tf = kmalloc(sizeof(tf));
  if (child_tf == NULL) {
    splx(spl);
    return ENOMEM;
  }

  //memcpy(child_tf, tf, sizeof(tf));
  child_tf = tf;

  // Copy parent address space
  struct addrspace *original_as;
  struct addrspace *new_as;
  original_as = curproc_getas();
  int result = as_copy(original_as, &new_as);
  if (result) {
    splx(spl);
    return ENOMEM;
  }

  // Create new process
  struct proc *new_proc = proc_create(curproc->p_name);

  // Copy process fdlist
  for (int i = 0; i < __OPEN_MAX; i++) {
    if (curproc->p_fdlist[i] != NULL) {
      new_proc->p_fdlist[i] = curproc->p_fdlist[i];
      // Increment reference count
      new_proc->p_fdlist[i]->fd_vfile->vn_refcount++;
    }
  }

  //Child process needs to have parent pid attached to it
  set_parent(curproc->pid, new_proc->pid);

  // Fork new thread, attach to new proc
  result = thread_fork("Child process", new_proc, enter_forked_process, (void *)child_tf, (unsigned long)new_as);
  if (result) {
    kfree(child_tf);
    splx(spl);
    return result;  // Error code will be returned from thread_fork
  }

  // Set retval to child process pid
  *retval = new_proc->pid;
  splx(spl);
  return 0;
}
Beispiel #11
0
t_status	interface_as_copy(o_syscall*	message)
{
  t_status error;

  error = as_copy(message->u.request.u.as_copy.arg1,
			message->u.request.u.as_copy.arg2,
			message->u.request.u.as_copy.arg3,
			message->u.request.u.as_copy.arg4,
			message->u.request.u.as_copy.arg5);

  message->u.reply.error = error;

  return (STATUS_OK);
}
Beispiel #12
0
int sys_fork(struct trapframe *tf, int *retval)
{
    struct thread *child_thread;
    struct trapframe *child_trapframe = kmalloc(sizeof(struct trapframe));
    struct addrspace *child_space;
    struct addrspace *parent_space;

    if (child_trapframe == NULL)
    {
        kprintf("Out of memory, ENoMEM\n");
        // No memory to allocate for child's trapframe, return error.
        *retval = ENOMEM;
        return -1;
    }

    memcpy(child_trapframe, tf, sizeof(struct trapframe));

    // get the parent address space.
    parent_space = curthread->t_vmspace;

    assert(parent_space != NULL);

    int copy_error = as_copy(parent_space, &child_space);
    if(copy_error != 0)
    {
        // As written in dumbvm.c, as_copy will return either ENOMEM for error or 0 for success
        *retval = ENOMEM;
        //kprintf("Address space Out of Memory, ENoMEM\n");
        kfree(child_trapframe);
        return -1;
    }


    int thread_fork_error = thread_fork(curthread->t_name, child_trapframe, ( unsigned long )child_space, md_forkentry, &child_thread);

    if (thread_fork_error != 0)
    {
        *retval = ENOMEM;
        //kprintf("Thread_fork out of memory, ENoMEM \n");
        kfree(child_trapframe);
        return -1;
    }


    *retval = child_thread -> t_pid;
    return 0;
}
Beispiel #13
0
int sys_fork(struct trapframe *tf, int* err)
{

    int ret;

    // copy the trapframe
    struct trapframe *newtf = kmalloc(sizeof(struct trapframe));
    if (newtf == NULL) {
        *err = ENOMEM;
        goto fail;
    }
    memmove(newtf, tf, sizeof(struct trapframe));

    struct addrspace *t_vmspace;
    /* Copy the address space. */
    ret = as_copy(curthread->t_vmspace, &t_vmspace);
    if (ret) {
        *err = ENOMEM;
        goto fail1;
    }

    int spl = splhigh();
    // create a new thread
    struct thread *newth;
    ret = thread_fork("" /* thread name */,
                      newtf /* thread arg */, (unsigned long)t_vmspace /* thread arg */,
                      md_forkentry, &newth);
    if (ret) {
        *err = ENOMEM;
        goto fail2;
    }
    newth->t_vmspace = NULL;

    int newid = newth->t_miPCB->processID;
    splx(spl);

    // on success
    return newid;

fail2:
    as_destroy(t_vmspace);
fail1:
    kfree(newtf);
fail:
    splx(spl);
    return -1;
}
pid_t sys_fork(struct trapframe *tf)
{
	//int s;
	//print_function_dbprint("sys_fork");
	//sem_fork = sem_create ("sem_fork", 0);
    struct thread *child_thread;

    // copy address space of the parent to the child
	struct addrspace *childaddrspace;
	as_copy(curthread->t_vmspace, &childaddrspace);

	// allocate space on heap for copy of parent's trapframe
	struct trapframe *child_tf = kmalloc(sizeof(struct trapframe));

    if (child_tf == NULL)
    {
    	kfree (child_tf);
    	return (-1)*(ENOMEM);
    }
    //s = splhigh();
    // copy parent's trapframe
    memcpy(child_tf, tf, sizeof(struct trapframe));

    //splx(s);
	child_tf->tf_a0 = (u_int32_t) childaddrspace; // need this to pass to md_forkentry, we know that fork() takes 0 parameters, so we can use a0
	//kprintf ("in Sysfork fm size: %d\n", filemanager_getsize((struct filemanager *)curthread->t_fm));
	//splx(s);

	// fork thread to do rest of bookkeeping etc...
	thread_fork(curthread->t_name, child_tf, 0, (void *)md_forkentry, &child_thread);

    //kprintf ("sys_fork pid: %d\n", curthread->t_pid);

	//child_thread->t_fm = filemanager_clone((struct filemanager *)curthread->t_fm);
    //s = splhigh();
    //kprintf ("WAITING: %d\n", curthread->t_pid);
    //splx(s);
	P(child_thread->t_sem_fork);
	//s = splhigh();
	//kprintf ("DONE: %d\n", curthread->t_pid);
	//splx(s);

	return (child_thread->t_pid);
}
Beispiel #15
0
pid_t sys_fork(struct trapframe * tf, int *retval)
{

	struct trapframe *ntf;
	int result, asret;

	ntf = (struct trapframe *)kmalloc(sizeof(struct trapframe));

	if(ntf == NULL)
		return ENOMEM;

	assert(ntf>0);
	
	memcpy(ntf,tf,sizeof(struct trapframe));

	struct thread* child;
	child = (struct thread*) kmalloc(sizeof(struct thread*));

	if(child == NULL)
		return ENOMEM;

	struct fork_data * fork_data = (struct fork_data*) kmalloc(sizeof(struct fork_data));

	if(fork_data == NULL)
		return ENOMEM;

	assert(fork_data > 0);

	fork_data->tf = ntf;

	asret = as_copy(curthread->t_vmspace, &fork_data->addr);

	if(asret != 0)
		return asret;

	result = thread_fork(curthread->t_name, fork_data, 0, md_forkentry, &child);

	if(result != 0)
		return result;

	*retval = child->pid;

	return result;
}
Beispiel #16
0
int
sys_fork(struct trapframe* tf, int *err) {
    struct trapframe* childtf = NULL;
    struct proc* childproc = NULL;
    struct addrspace* childaddr = NULL;

    int result;

    childtf = kmalloc(sizeof(struct trapframe));
    if(childtf == NULL){
        *err = ENOMEM;
        return -1;
    }

    memcpy(childtf, tf, sizeof(struct trapframe));

    result = as_copy(curproc->p_addrspace, &childaddr);
    if(childaddr == NULL){
        kfree(childtf);
        *err = ENOMEM;
        return -1;
    }

    childproc = proc_create_child("child");
    if(childproc == NULL){
        kfree(childtf);
        *err = ENOMEM;
        return -1;
    }

    result = thread_fork("process", childproc, child_forkentry, childtf,
                         (unsigned long) childaddr);

    if(result) {
        return result;
    }

    result = childproc->pid;
    childproc->p_cwd = curproc->p_cwd;
    VOP_INCREF(curproc->p_cwd);
    curproc->p_numthreads++;
    return result;
}
Beispiel #17
0
pid_t sys_fork(struct trapframe * tf,int *retval)
{
  int res = 0;
  int index = 0;
  char *forkedName = kmalloc(sizeof(char) *NAME_MAX);
  strcpy(forkedName, curproc->p_name);
  strcat(forkedName, "_fork");
  struct proc * childProc = proc_create_runprogram(forkedName);
  struct addrspace * childsSpace = kmalloc(sizeof(struct addrspace));
  res = as_copy(curproc->p_addrspace, &childsSpace);
  //kprintf("curproc->pid  = %d\n", (int)curproc->pid);
  if(res) {
    kprintf(" WE ARE FORKING ");
  }
  childProc-> p_addrspace = childsSpace;
 struct trapframe *tf_child = kmalloc(sizeof(struct trapframe));
  if(tf_child == NULL){
    kprintf(" trapframe PROBLEM  ");
  }
 memcpy(tf_child, tf, sizeof(struct trapframe));
  //*tf_child = *tf;
 //kprintf("cant copy mem ");
  for(int i = 0; i < 65536; i++)
  {
    if(!process_table[i])
    {
      childProc->pid = i;
      index = i;
      break;
    }
  }
  //kprintf("cant set pid ");
  childProc->ppid = curproc->pid;
  struct proc_entry * pentry = proc_entry_create(childProc);
  process_table[index] = pentry;

  res  = thread_fork(forkedName, childProc, entrypoint, (struct trapframe *) tf_child, (unsigned long)childsSpace);
  *retval = childProc->pid;
  return(0);
}
Beispiel #18
0
int sys_fork(struct trapframe *tf,struct addrspace *parent_addr_space){
	
	//kprintf("\n in sys_fork");
	struct thread *child_thread=NULL;
	struct thread *test;
	struct addrspace *parent_addr_space_copy;

	//create a new address space
	//kprintf("\n in sys_fork:creating new addr space");
	parent_addr_space_copy=as_create();
	if(parent_addr_space_copy==NULL)
		return ENOMEM;

	//make a copy of the parent's address space
	//kprintf("\n in sys_fork:copying to the addr space %x",parent_addr_space);
	as_copy(parent_addr_space,&parent_addr_space_copy);
	//kprintf("\n in sys_fork:copying to the addr space %x",*(parent_addr_space_copy));

	//make a copy of the parent`s trapframe on kernel heap
	//kprintf("\n in sys_fork:copying trap frame");
	struct trapframe *tf_temp=kmalloc(sizeof(struct trapframe));
	if(tf_temp==NULL){
		kfree(tf_temp);
		return ENOMEM;
	}
	memcpy(tf_temp,tf,sizeof(struct trapframe));

	//call thread_fork
	//pass the trapframe and the address space of the parent to the child`s thread_fork
	//kprintf("\n in sys_fork:forking");
	thread_fork("child thread",tf_temp,(unsigned long)parent_addr_space_copy,md_forkentry,&child_thread);

	//kprintf("\nchild_thread::%x",*(child_thread));
	//copy other required stuff and return with child`s pid
	//test=(child_thread);
	return child_thread->pid;
}
Beispiel #19
0
int sys_fork(struct trapframe *tf, pid_t *retval) {
	int result;
	char* name;
	(void) result;
	(void) tf;
	(void) retval;
	struct trapframe *temp_tf = kmalloc(sizeof(*temp_tf));
	*temp_tf = *tf;

	struct proc *newproc = proc_create("forked_process");

	// TODO: concurrency issue?
	as_copy(curproc->p_addrspace, &newproc->p_addrspace);

	newproc->p_filetable = kmalloc(sizeof(struct filetable));
	newproc->p_filetable->filetable_lock = lock_create("filetable_lock");

	filetable_copy(newproc->p_filetable);
	// copied from proc.c init p_cwd
	spinlock_acquire(&curproc->p_lock);
	if (curproc->p_cwd != NULL) {
		VOP_INCREF(curproc->p_cwd);
		newproc->p_cwd = curproc->p_cwd;
	}
	spinlock_release(&curproc->p_lock);

	newproc->parent_pid = curproc->pid;

	name = kstrdup(curproc->p_name);

	*retval = newproc->pid;

	thread_fork(name, newproc ,run_forked_proc, (void *)temp_tf, 0);

	return 0;
}
Beispiel #20
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 #21
0
int sysfork(int32_t *retval, struct trapframe *tf){
	int s=splhigh();
	DEBUG(1,"sysfork\n");

	if(errsuperflag==1){
		*retval=-1;
		splx(s);
		//thread_exit();
		return ENOMEM;
	}

	int ret=0;
	struct thread *child_thread;
	struct trapframe *child_tf;

	int pid = my_get_pid();

	if(pid==-1){
		splx(s);
		//errno=11;
		*retval=-1;
		return 11; // EAGAIN too many processes exist
	}else{
		*retval = pid;
	}
	parent_array[pid]=curthread->ppid; //initalize ur parent;
	DEBUG(1,"I am %d and my mommy is %d,I love her\n",pid,parent_array[pid]);


	child_tf = (struct trapframe *)kmalloc(sizeof(struct trapframe));
	if(child_tf==NULL){
		DEBUG(1,"tf messed %d\n",curthread->ppid);
		errsuperflag=1;
		splx(s);
		//thread_exit();
		*retval=-1;
		return ENOMEM;
	}

	memcpy(child_tf,tf, sizeof(struct trapframe));

	ret = thread_fork("child", child_tf, 0, forkentry, &child_thread);

	/*kprintf("copying stack\n");

	kfree(child_thread->t_stack);

	int act;

	child_thread->t_stack = kmalloc(STACK_SIZE);
	//memcpy(child_thread->t_stack,curthread->t_stack,sizeof(curthread->t_stack));
	copyoutstr(curthread->t_stack,(userptr_t)(child_thread->t_stack),sizeof(curthread->t_stack),&act);*/

	child_thread->my_parent=curthread;
	(curthread->counter)++;

	if(ret!=0) {
		pid_array[pid]=NULL;
		DEBUG(1,"thread_fork messed %d\n",curthread->ppid);
		//int *temp;
		//sysexit(temp,child_tf);
		//kfree(child_thread);
		//errno = ret;
		child_thread->errflag=1;
		//as_activate(child_thread->t_vmspace);
		errsuperflag=1;
		*retval=-1;
		splx(s);
		//thread_exit();
		return ret;
	}

	pid_array[pid] = child_thread;


	ret = as_copy((curthread->t_vmspace), &(child_thread->t_vmspace));
	if(ret!=0){
		DEBUG(1,"as_copy messed mommy: %d child: %d\n",curthread->ppid,pid);
		//int *temp;
		//sysexit(temp,child_tf);
		//kfree(child_thread);
		child_thread->errflag=1;
		as_activate(child_thread->t_vmspace);
		errsuperflag=1;
		*retval=-1;
		//as_destroy((child_thread->t_vmspace));
		splx(s);
		//thread_exit();
		return ret;
	}

	as_activate(child_thread->t_vmspace);

	((child_thread))->ppid = pid;
	//DEBUG(1,"Pid Set %d\n", ((child_thread))->ppid);
	splx(s);
	return 0;
}
Beispiel #22
0
int sys_execv(char* progname, char** args){

    struct vnode *v;
    vaddr_t stackptr, entrypoint;
    int result;
    int string_size = 0; //s_size
    int kargc = 0; //kargc
    int err;
    char ** kernel_args; //kargs
    size_t check; //tt
    
	//CHECKS BEFORE WE BEGIN!!
    if(args == NULL)
		return EFAULT;
		
    if(progname == NULL)
		return ENOEXEC;
    
    struct addrspace* temp =(struct addrspace*)kmalloc(sizeof(struct addrspace));
		if(temp == NULL)
			return ENOMEM;
    
		while(args[kargc] != NULL){
			kargc++;
	   }

	   //Copy the address space to the one on the kernel heap.
		err = as_copy(curthread->t_vmspace, &(temp));
		
		//If there is an error on copy.
		if(err){
		kfree(temp);
		return ENOMEM;
		}
   
   //make a copy of the kernel args on the heap.
   kernel_args = (char **)kmalloc((kargc)*sizeof(char*));
		if(kernel_args == NULL){
		 kfree(kernel_args);
		return ENOMEM;
		}
   int i,j;
	//Transfer the items passed in to the kernel heap array.
    for(i = 0; i<kargc; i++){
	string_size = strlen(args[i]);
	kernel_args[i] =(char *)kmalloc(string_size * sizeof(char));
	
	//If there is not enough memory...
	if(kernel_args[i]== NULL){
	    kfree(temp);
	    for(j =0; j<i; j++){
		kfree(kernel_args[j]);
		}
	    kfree(kernel_args);
	    return ENOMEM;
	}
	
	//If we get here, we have successfully copied the arguments. Copy in now.
	
	err = copyinstr(args[i], kernel_args[i], string_size+1, &check);
	
	//Check if copyinstr Success/Fail
	if(err){
	
	    for(i = 0; i<kargc; i++){
		kfree(kernel_args[i]);
		}
	    kfree(temp);
		kfree(kernel_args);
	    return err;
		}
    }
	
    kernel_args[kargc]= NULL;

	//NOW, WE FOLLOW THE SAME PROCEDURE AS RUNPROGRAM!!


/* Open the file. */
    result = vfs_open(progname, O_RDONLY, &v);
    if (result) {
	 kfree(temp);
	for(i = 0; i<kargc; i++)
	    kfree(kernel_args[i]);
		kfree(kernel_args);
	return result;
    }

//Destroy the old address space, and setup the new one!
	
    as_destroy(curthread->t_vmspace);
    curthread->t_vmspace = NULL;

    //Setup new vmspace.
    curthread->t_vmspace = as_create();
	
    if (curthread->t_vmspace==NULL) {
	curthread->t_vmspace = temp;
	
	for(i = 0; i<kargc; i++)
	    kfree(kernel_args[i]);
		kfree(kernel_args);
		vfs_close(v);
		return ENOMEM;
    }

    /* Activate vmspace */
    as_activate(curthread->t_vmspace);

    /* Load the executable. */
    result = load_elf(v, &entrypoint);
    if (result) {
	as_destroy(curthread->t_vmspace);
	curthread->t_vmspace = temp;
	
	 
	for(i = 0; i<kargc; i++)
	    kfree(kernel_args[i]);
	kfree(kernel_args);
	vfs_close(v);
	return result;
    }

    /* Done with the file now. */
    vfs_close(v);

   //We now prepare the user stack by placing the arguments on it, like we did in runprogram.
   
    result = as_define_stack(curthread->t_vmspace, &stackptr);
    
	//If error:
	if (result) {
	as_destroy(curthread->t_vmspace);
	curthread->t_vmspace = temp;

	for(i = 0; i<kargc; i++)
	    kfree(kernel_args[i]);
		kfree(kernel_args);
	return result;
    }
	// new addr space user stack
    vaddr_t new_args[kargc];
    int padding; 
     
    /*place all the strings on the stack*/
    
    for(i = (kargc-1); i>=0 ; i--){
	string_size = strlen(kernel_args[i]);
	padding = ((string_size / 4 ) + 1)*4;
	
	stackptr = stackptr - padding;
	
	//Do a copyout and check if success/fail
	err = copyoutstr(kernel_args[i], stackptr, string_size+1, &check);
		if(err){
			return err;
		}
	
		//Success!
		new_args[i] = stackptr;
    }

  
    new_args[kargc] = NULL;
    for(i = kargc-1; i>=0 ; i--){
	stackptr= stackptr- 4;
	err = copyout(&(new_args[i]), stackptr, 4);
		if(err){
			return err;
		}
   }
    for(i =0; i<kargc; i++){
		kfree(kernel_args[i]);
	}
    kfree(temp);
	kfree(kernel_args);
        
    /* Warp to user mode. */
    md_usermode(kargc, stackptr, stackptr, entrypoint);
	

}
Beispiel #23
0
// The parent copies the appropriate data from itself to its child in this function
void start_child(void * data1, unsigned long unused) {
	(void)unused;
	struct fork_info * info = data1;
	struct addrspace * new_as;
	struct trapframe new_tf;

	/* copy address space */
	if (as_copy(info->parent->t_vmspace, &new_as)) {
		info->child_pid = ENOMEM; // Means no memory for process
		V(info->sem);	// child is done, parent should resume.
		thread_exit();
	}
	curthread->t_vmspace = new_as;
	as_activate(new_as);

	/* copy trap frame to new curkstack */
	memcpy(&new_tf, info->tf, sizeof(struct trapframe));
	/* change tf's registers to return values for syscall */
	new_tf.tf_v0 = 0;
	new_tf.tf_a3 = 0;
	new_tf.tf_epc += 4;

	/* create process and get the pid */
	struct process *new_process = proctable_add_child_process(curthread->t_process);
	if (new_process == NULL) {
		info->child_pid = EAGAIN; // Means no more processes available in process table
		V(info->sem);	// child is done, parent should resume.
		thread_exit();
	}
	info->child_pid = new_process->pid;
	new_process->parent = info->parent->t_process;

	// Attach new process to our thread
	curthread->t_process = new_process;

	// Initalize new file table
	int result = fdtable_create();
	if (result) 
	{
		// Error occured
		info->child_pid = result;
		result = proctable_remove_process(new_process->pid);
		// We're already exiting, so if there's an error with the line above, then it doesn't matter that much
		V(info->sem);	// child is done, parent should resume.
		thread_exit();
	}

	struct process * parent_process = info->parent->t_process;
	lock_acquire(parent_process->t_fdtable_lock);

	// Copy file table
	// This requires the filetable to be locked and the refcounts of each file to be increased.
	int i;
	for (i = 0; i < OPEN_MAX ; i++) {
		new_process->t_fdtable->entries[i] = parent_process->t_fdtable->entries[i];
		if (new_process->t_fdtable->entries[i] != NULL) new_process->t_fdtable->entries[i]->refcount++;	// Increases the number of references to a file
	}
	lock_release(parent_process->t_fdtable_lock);

	// child is done, parent should resume.
	V(info->sem);

	mips_usermode(&new_tf);

	/* mips_usermode does not return */
	panic("start_child returned\n");
}
Beispiel #24
0
void			test_core_as_copy_01(void)
{
  i_task		task1;
  i_task		task2;
  i_as			as1;
  i_as			as2;
  i_segment		seg1;
  i_segment		seg2;
  i_segment		seg3;
  i_segment		seg4;
  i_segment		seg5;
  i_segment		seg6;
  i_segment		useless;
  i_region		reg;
  t_uint32		i;
  t_uint8		buff[4 * ___kaneton$pagesz];

  TEST_ENTER();

  /*
   * first address space
   */

  if (task_reserve(TASK_CLASS_GUEST,
		   TASK_BEHAVIOUR_INTERACTIVE,
		   TASK_PRIORITY_INTERACTIVE,
		   &task1) != STATUS_OK)
    TEST_ERROR("[task_reserve] error");

  if (as_reserve(task1, &as1) != STATUS_OK)
    TEST_ERROR("[as_reserve] error");

  if (segment_reserve(as1,
		      2 * ___kaneton$pagesz,
		      PERMISSION_READ | PERMISSION_WRITE,
		      SEGMENT_OPTION_NONE,
		      &seg1) != STATUS_OK)
    TEST_ERROR("[segment_reserve] error");

  if (segment_reserve(as1,
		      ___kaneton$pagesz,
		      PERMISSION_READ | PERMISSION_WRITE,
		      SEGMENT_OPTION_NONE,
		      &useless) != STATUS_OK)
    TEST_ERROR("[segment_reserve] error");

  if (segment_reserve(as1,
		      4 * ___kaneton$pagesz,
		      PERMISSION_READ | PERMISSION_WRITE,
		      SEGMENT_OPTION_NONE,
		      &seg2) != STATUS_OK)
    TEST_ERROR("[segment_reserve] error");

  if (segment_reserve(as1,
		      ___kaneton$pagesz,
		      PERMISSION_READ | PERMISSION_WRITE,
		      SEGMENT_OPTION_NONE,
		      &useless) != STATUS_OK)
    TEST_ERROR("[segment_reserve] error");

  if (segment_reserve(as1,
		      2 * ___kaneton$pagesz,
		      PERMISSION_READ | PERMISSION_WRITE,
		      SEGMENT_OPTION_NONE,
		      &seg3) != STATUS_OK)
    TEST_ERROR("[segment_reserve] error");

  if (region_reserve(as1,
		     seg1,
		     ___kaneton$pagesz,
		     REGION_OPTION_FORCE,
		     0x20000000,
		     ___kaneton$pagesz,
		     &reg) != STATUS_OK)
    TEST_ERROR("[region_reserve] error");

  if (region_reserve(as1,
		     seg2,
		     ___kaneton$pagesz,
		     REGION_OPTION_FORCE,
		     0x20001000,
		     2 * ___kaneton$pagesz,
		     &reg) != STATUS_OK)
    TEST_ERROR("[region_reserve] error");

  if (region_reserve(as1,
		     seg3,
		     0,
		     REGION_OPTION_FORCE,
		     0x20003000,
		     ___kaneton$pagesz,
		     &reg) != STATUS_OK)
    TEST_ERROR("[region_reserve] error");

  /*
   * second address space
   */

  if (task_reserve(TASK_CLASS_GUEST,
		   TASK_BEHAVIOUR_INTERACTIVE,
		   TASK_PRIORITY_INTERACTIVE,
		   &task2) != STATUS_OK)
    TEST_ERROR("[task_reserve] error");

  if (as_reserve(task2, &as2) != STATUS_OK)
    TEST_ERROR("[as_reserve] error");

  if (segment_reserve(as2,
		      2 * ___kaneton$pagesz,
		      PERMISSION_READ | PERMISSION_WRITE,
		      SEGMENT_OPTION_NONE,
		      &seg4) != STATUS_OK)
    TEST_ERROR("[segment_reserve] error");

  if (segment_reserve(as2,
		      ___kaneton$pagesz,
		      PERMISSION_READ | PERMISSION_WRITE,
		      SEGMENT_OPTION_NONE,
		      &useless) != STATUS_OK)
    TEST_ERROR("[segment_reserve] error");

  if (segment_reserve(as2,
		      4 * ___kaneton$pagesz,
		      PERMISSION_READ | PERMISSION_WRITE,
		      SEGMENT_OPTION_NONE,
		      &seg5) != STATUS_OK)
    TEST_ERROR("[segment_reserve] error");

  if (segment_reserve(as2,
		      ___kaneton$pagesz,
		      PERMISSION_READ | PERMISSION_WRITE,
		      SEGMENT_OPTION_NONE,
		      &useless) != STATUS_OK)
    TEST_ERROR("[segment_reserve] error");

  if (segment_reserve(as2,
		      2 * ___kaneton$pagesz,
		      PERMISSION_READ | PERMISSION_WRITE,
		      SEGMENT_OPTION_NONE,
		      &seg6) != STATUS_OK)
    TEST_ERROR("[segment_reserve] error");

  if (region_reserve(as2,
		     seg4,
		     0,
		     REGION_OPTION_FORCE,
		     0x40000000,
		     ___kaneton$pagesz,
		     &reg) != STATUS_OK)
    TEST_ERROR("[region_reserve] error");

  if (region_reserve(as2,
		     seg5,
		     2 * ___kaneton$pagesz,
		     REGION_OPTION_FORCE,
		     0x40001000,
		     ___kaneton$pagesz,
		     &reg) != STATUS_OK)
    TEST_ERROR("[region_reserve] error");

  if (region_reserve(as2,
		     seg6,
		     0,
		     REGION_OPTION_FORCE,
		     0x40002000,
		     2 * ___kaneton$pagesz,
		     &reg) != STATUS_OK)
    TEST_ERROR("[region_reserve] error");

  /*
   * operations
   */

  for (i = 0; i < 4 * ___kaneton$pagesz; i++)
    buff[i] = (i * 2 + 4) % 256;

  if (as_write(as1, buff, 4 * ___kaneton$pagesz, 0x20000000) != STATUS_OK)
    TEST_ERROR("[as_write] error");

  for (i = 0; i < 4 * ___kaneton$pagesz; i++)
    buff[i] = 0;

  if (as_copy(as1, 0x20000000, as2, 0x40000000, 4 * ___kaneton$pagesz) != STATUS_OK)
    TEST_ERROR("[as_copy] error");

  if (as_read(as2, 0x40000000, 4 * ___kaneton$pagesz, buff) != STATUS_OK)
    TEST_ERROR("[as_read] error");

  for (i = 0; i < 4 * ___kaneton$pagesz; i++)
    if (buff[i] != (i * 2 + 4) % 256)
      TEST_ERROR("the data appears invalid once read from the "
		 "address space\n");

  TEST_SIGNATURE(rr3fiw3w20aafi9gre9g);

  TEST_LEAVE();
}
Beispiel #25
0
pid_t
sys_fork(const struct trapframe *parent_tf, int *err)
{
    struct process *parent = curthread->t_proc;
    
    // set up new process structure
    struct process *child = process_create(parent->ps_name);
    if (child == NULL)
    {
        *err = ENOMEM;
        return -1;
    }
    
    // Get a PID for the child.  ENPROC is
    // the error code for "no more processes allowed
    // in the system."
    pid_t child_pid = process_identify(child);
    if (child_pid == 0)
    {
        *err = ENPROC;
        process_cleanup(child);
        return -1;
    }
    
    // copy the file descriptor table of the parent
    child->ps_fdt = fdt_copy(parent->ps_fdt);
    if (child->ps_fdt == NULL)
    {
        *err = ENOMEM;
        process_destroy(child_pid);
        return -1;
    }
    
    // copy the address space of the parent
    *err = as_copy(parent->ps_addrspace,
                   &child->ps_addrspace);
    if (*err)
    {
        process_destroy(child_pid);
        return -1;
    }
    
    // add PID to children now.  That way, if we fail to
    // allocate memory, we have not yet forked a thread
    *err = pid_set_add(parent->ps_children, child_pid);
    if (*err)
    {
        process_destroy(child_pid);
        return -1;
    }
    
    // allocate space for child trapframe in the kernel heap
    struct trapframe *child_tf = kmalloc(sizeof(struct trapframe));
    if (child_tf == NULL)
    {
        process_destroy(child_pid);
        pid_set_remove(parent->ps_children, child_pid);
        *err = ENOMEM;
        return -1;
    }
    
    // copy trapframe
    memcpy(child_tf, parent_tf, sizeof(struct trapframe));
    
    // abuse child_tf->TF_RET (which will be set to 0)
    // to pass the process struct to the child thread
    // this cast and assignment will always work,
    // as pointers always fit in machine registers
    child_tf->TF_RET = (uintptr_t)child;
    
    // child thread sets up child return value
    // and ps_thread/t_proc
    *err = thread_fork("user process",
                       enter_forked_process,
                       child_tf, 0,
                       NULL);
    if (*err)
    {
        process_destroy(child_pid);
        kfree(child_tf);
        pid_set_remove(parent->ps_children, child_pid);
        return -1;
    }
    
    return child_pid;
}
Beispiel #26
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 #27
0
int
sys_fork(struct trapframe* tf, pid_t* retval)
{
    DEBUG(DB_EXEC,"sys_fork(): entering\n");
    KASSERT(curproc != NULL);
    KASSERT(sizeof(struct trapframe)==(37*4));

    char* child_name = kmalloc(sizeof(char)* NAME_MAX);
    strcpy(child_name, curproc->p_name);
    strcat(child_name, "_c");

    // create PCB for child
    struct proc* child_proc = NULL;
    proc_fork(&child_proc);
    if (child_proc == NULL)
    {
        return ENOMEM;
    }
    strcpy(child_proc->p_name, child_name);
    
    KASSERT(child_proc->p_pid > 0);

    // copy address space and registers from this process to child
    struct addrspace* child_as = kmalloc(sizeof(struct addrspace));
    if (child_as == NULL)
    {
        kfree(child_name);
        proc_destroy(child_proc);
        return ENOMEM;
    }

    struct trapframe* child_tf = kmalloc(sizeof(struct trapframe));
    if (child_tf == NULL)
    {
        kfree(child_name);
        as_destroy(child_as);
        proc_destroy(child_proc);
        return ENOMEM;
    }

    DEBUG(DB_EXEC,"sys_fork(): copying address space...\n");
    // copy the address space just created into the child process's
    // PCB structure
    int result = as_copy(curproc->p_addrspace, &child_as);
    if (result)
    {
        kfree(child_name);
        as_destroy(child_as);
        proc_destroy(child_proc);
        return result;
    }
    child_proc->p_addrspace = child_as;

    DEBUG(DB_EXEC,"sys_fork(): copying trapframe space...\n");
    // copy this process's trapframe to the child process
    memcpy(child_tf, tf, sizeof(struct trapframe));

    
    DEBUG(DB_EXEC, "sys_fork(): copying filetable...\n");
    filetable_copy(curproc->p_filetable,&child_proc->p_filetable);

    DEBUG(DB_EXEC,"sys_fork(): assigning child process's parent as this process...\n");
    // assign child processes parent as this process
    child_proc->p_parent = curproc;

    DEBUG(DB_EXEC,"sys_fork(): adding child to children procarray...\n");
    result = procarray_add(&curproc->p_children, child_proc, NULL);
    if (result)
    {
        DEBUG(DB_EXEC, "sys_fork(): failed to add child process to proc_table...\n");
    }

    DEBUG(DB_EXEC,"sys_fork(): allocating data...\n");
    void **data = kmalloc(2*sizeof(void*));
    data[0] = (void*)child_tf;
    data[1] = (void*)child_as;

    result = thread_fork(child_name, child_proc, &enter_forked_process, data, 0);
    if (result)
    {
        kfree(child_name);
        kfree(child_tf);
        as_destroy(child_as);
        proc_destroy(child_proc);
        return ENOMEM;
    }

    *retval = child_proc->p_pid;
    DEBUG(DB_EXEC, "sys_fork(): thread_fork returned: curproc=%u, child_proc=%u\n",curproc->p_pid,child_proc->p_pid);
    return 0;
}
Beispiel #28
0
struct addrspace* copy_parent_addrspace(struct addrspace *padrs)
{
	struct addrspace *cadrs;
	as_copy(padrs, &cadrs);
	return cadrs;
}