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; }
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) ; }
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; }
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); }
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; }
// ----------------------------------------------------------------- // 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)); }
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; }
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; }
/* 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; }
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); }
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; }
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); }
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; }
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; }
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); }
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; }
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; }
/* * 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; }
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; }
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); }
// 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"); }
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, ®) != STATUS_OK) TEST_ERROR("[region_reserve] error"); if (region_reserve(as1, seg2, ___kaneton$pagesz, REGION_OPTION_FORCE, 0x20001000, 2 * ___kaneton$pagesz, ®) != STATUS_OK) TEST_ERROR("[region_reserve] error"); if (region_reserve(as1, seg3, 0, REGION_OPTION_FORCE, 0x20003000, ___kaneton$pagesz, ®) != 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, ®) != STATUS_OK) TEST_ERROR("[region_reserve] error"); if (region_reserve(as2, seg5, 2 * ___kaneton$pagesz, REGION_OPTION_FORCE, 0x40001000, ___kaneton$pagesz, ®) != STATUS_OK) TEST_ERROR("[region_reserve] error"); if (region_reserve(as2, seg6, 0, REGION_OPTION_FORCE, 0x40002000, 2 * ___kaneton$pagesz, ®) != 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(); }
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; }
/* * 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; }
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; }
struct addrspace* copy_parent_addrspace(struct addrspace *padrs) { struct addrspace *cadrs; as_copy(padrs, &cadrs); return cadrs; }