/* * 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; }
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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }
/* * 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; }