/* * 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; }
/* Does most of the work for open(). */ int vfs_open(char *path, int openflags, struct vnode **ret) { int how; int result; int canwrite; struct vnode *vn = NULL; how = openflags & O_ACCMODE; switch (how) { case O_RDONLY: canwrite=0; break; case O_WRONLY: case O_RDWR: canwrite=1; break; default: return EINVAL; } if (openflags & O_CREAT) { char name[NAME_MAX+1]; struct vnode *dir; int excl = (openflags & O_EXCL)!=0; result = vfs_lookparent(path, &dir, name, sizeof(name)); if (result) { return result; } result = VOP_CREAT(dir, name, excl, &vn); VOP_DECREF(dir); } else { result = vfs_lookup(path, &vn); } if (result) { return result; } assert(vn != NULL); result = VOP_OPEN(vn, openflags); if (result) { VOP_DECREF(vn); return result; } VOP_INCOPEN(vn); if (openflags & O_TRUNC) { if (canwrite==0) { result = EINVAL; } else { result = VOP_TRUNCATE(vn, 0); } if (result) { VOP_DECOPEN(vn); VOP_DECREF(vn); return result; } } *ret = vn; return 0; }