void initialize_user_process(char **kos_argv) { // zero out the memory bzero(main_memory, MemorySize); PCB *pcb = (PCB *) malloc(sizeof(PCB)); pcb_init(pcb); printf("filename: %s\n", kos_argv[0]); if (load_user_program(kos_argv[0]) < 0) { fprintf(stderr,"Can't load program.\n"); exit(1); } // set up the program counters and the stack register pcb->registers[PCReg] = 0; pcb->registers[NextPCReg] = 4; /* need to back off from top of memory */ /* 12 for argc, argv, envp */ /* 12 for stack frame */ pcb->registers[StackReg] = MemorySize - 24; dll_append(readyq, new_jval_v((void *) pcb)); printf("Running user code.\n"); kt_exit(); }
int syscall_return(PCB *pcb, int returnVal) { // printf("Goes in syscall\n"); // printf("This is the user_base and user_limit of the curProc in syscall: %i %i\n",curProc->user_base, curProc->user_limit); //Set PCReg in the saved registers to NextPCReg. This pcb is not the global one in KOS() pcb->registers[PCReg] = pcb->registers[NextPCReg]; pcb->registers[2] = returnVal; //Put the PCB onto the ready queue. Jval value = new_jval_v((void *)pcb); //value.v = pcb; //places it at the end of the dllist dll_append(readyq,value); kt_exit(); }
//Console buffer. Code buffers input from the console until a program requests it with a call to read(). CREATE. //a thread whose sole job is to read characters from the console and put them into a buffer. void *console_buffer(void *arg) { //printf("Goes into the console_buffer\n"); // int cbTail = 0; //int cbHead =0; //char *filename = (char *)arg; //these are used to convert the char to int and place into buf int i; char c; //int stop =1; PIPE *pipe= (PIPE *)arg; //printf("Enters console_buffer\n"); //while(stop) while(pipe->ref_count!=0) //bc it it is then you have to deallocate { P_kt_sem(consoleWait); //printf("P_kt_sem(consoleWait): %i\n",kt_getval(consoleWait)); //have to check if the buffer is full or not //printf("Enters while loop in console\n"); //if not full yet //if (cbTail !=cbSize) if (pipe->pbuf_tail!=256) { //printf("We are reading from the console into the buffer\n"); //currently a char c = console_read(); // printf("Reading from console: %c\n", c); //conversion to a int bc buffer holds ints only i = c -'0'; // printf("Coverted c into i: %i\n",i); //enqueue - insert it into the buffer cb, enter through the back! and 256 size of the buffer //cbTail = (cbTail+1)%256; //this is a shortcut pipe->pbuf_tail = (pipe->pbuf_tail+1)%256; pipe->read_buf[pipe->pbuf_tail] = i; //printf("Placed into cb[%i]: %i\n", cbTail, cb[cbTail]); // printf("This is in index %i: %c %i\n", cbTail, c, cb[cbTail]); //Step 17: V_kt_sem(nelem); //printf("V_kt_sem(nelem): %i\n",kt_getval(nelem)); } } // printf("Exits while loop in console buffer\n"); kt_exit(); }
void *console_buf_read(void *arg) { char c; int i; while (sysStopRead != 1) { P_kt_sem(consoleWait); if (!full(consoleBufferTail, consoleSize)) { c = console_read(); i = c - '0'; add_to_queue(consoleBuffer, &consoleBufferTail, i); V_kt_sem(nelem); } } kt_exit(); }
int syscall_exec(PCB *pcb, int returnVal) { // printf("Goes into syscall_return exec\n"); //Set PCReg in the saved registers to NextPCReg. This pcb is not the global one in KOS() pcb->registers[PCReg] = 0; pcb->registers[NextPCReg] = 4; // pcb->registers[NextPCReg]+=4; //Put the return value into register 2. pcb->registers[2] = returnVal; pcb->registers[2] = returnVal; //Put the PCB onto the ready queue. Jval value = new_jval_v((void *)pcb); //value.v = pcb; //printf("This is in the syscall_return pcb that gets placed in the value to be placed in readyq: %s\n", value.v); //places it at the end of the dllist dll_append(readyq,value); //Call kt_exit kt_exit(); }
void *initialize_user_process(void *arg) { // printf("Enters initalize_user_process\n"); int i; char **filename = (char **)arg; int argc = 0; while (filename[argc]!=NULL) { printf("This is filename[%i]: %s\n", argc, filename[argc]); argc++; } // printf("This is argc in init: %i\n", argc); //Step 19: putting in argc //k = WordToMachine(argc); //memcpy(main_memory+MemorySize-40+12, &k, 4); //L3 Step 18: start first process, is this init? init=(PCB *)malloc(sizeof(PCB)); init->registers = (int *)malloc(NumTotalRegs*sizeof(int)); for (i=0; i < NumTotalRegs; i++) { init->registers[i] = 0; } init->pid = (int *)0; // printf("This is init's pid: %i\n", (int)init->pid); //L3 Step 19: init->waiter_sem = make_kt_sem(0); init->waiters = new_dllist(); init->children = make_jrb(); //Allocate a new PCB PCB *temp=(PCB *)malloc(sizeof(PCB)); temp->registers = (int *)malloc(NumTotalRegs*sizeof(int)); temp->user_base = 0; //printf("Initial user_base: %i\n", temp->user_base); //Changed Step 12: temp->user_limit = MemorySize-2048; temp->user_limit = MemorySize/8; //printf("Initial user_limt: %i\n", temp->user_limit); //L3 Step 18: temp->parent = init; //L3 Step 19: temp->waiter_sem = make_kt_sem(0); temp->waiters = new_dllist(); //L3 Step 21: make rb tree for children temp->children = make_jrb(); //Changed at Step 12: User_Base = temp->user_base; User_Base = memory8(); User_Limit = temp->user_limit; //printf("This is User_Base in initialize: %i\n", User_Base); //printf("This is User_Limit in initialize: %i\n", User_Limit); //set the regs of the //printf("Setting all the registers to 0 in initalize_user_process\n"); for (i=0; i < NumTotalRegs; i++) temp->registers[i] = 0; //printf("Setting pid in init\n"); temp->pid = (int *)get_new_pid(); printf("First Pid: %i and its parent's should be 0 init: %i\n", temp->pid, temp->parent->pid ); /* set up the program counters and the stack register */ temp->registers[PCReg] = 0; temp->registers[NextPCReg] = 4; //insert the first process as init's child; WOW you can use this function! Jval tempN = new_jval_v((void*)temp); //can only insert Jvals jrb_insert_int(init->children, (int)temp->pid, tempN); //JRB tree, int ikey, Jval val //JRB ptr; // jrb_traverse(ptr, init->children) //{ //printf("This is child pid %i of init %i\n", ptr->key, (int)init->pid); //} //perform_execve(job, fn, argv) // where job is the new PCB, fn is the name of your initial executable (at this point, mine is a.out), //and argv is the argv of this initial job. //returns-> 0 success, errno if error //PrintStack(temp->registers[StackReg], temp->user_base); int errno = perform_execve(temp, filename[0],filename); // printf("This is perform_execve: %i\n", errno); //returns to initialize_user_process(), it either exits because there was an error, or it puts the new job onto the ready queue and calls kt_exit() PrintStack(temp->registers[StackReg], temp->user_base); if (errno!=0) { printf("Perform_execve returned unsucessful\n"); kt_exit(); } //printf("Placing jval into queue\n"); Jval value = new_jval_v((void *)temp); //value.v = temp; //printf("This is the value being placed into the readyq in the initalize_user_process: %s\n",value.v ); dll_append(readyq, value); // printf("Program %s loaded\n", kos_argv[0]); kt_exit(); }
void *initialize_user_process(void *arg) { PCB *start = (PCB *) malloc(sizeof(PCB)); start->registers = (int *) malloc(NumTotalRegs * sizeof(int)); int i; for (i = 0; i < NumTotalRegs; i++) { start->registers[i] = 0; } int argc = 0; while (kos_argv[argc] != NULL) { argc++; } int tempCount = argc; int fIndex = 0; int ptr[argc]; int topOfStack = MemorySize - 20; while (tempCount != 0) { tempCount--; topOfStack -= strlen(kos_argv[fIndex]) + 1; ptr[tempCount] = topOfStack; strcpy(main_memory + topOfStack, kos_argv[fIndex]); fIndex++; } while (topOfStack % 4) { topOfStack--; } topOfStack -= 4; int machineAddress = WordToMachine(0); memcpy(main_memory + topOfStack, &machineAddress, 4); fIndex = 0; while (fIndex < argc) { topOfStack -= 4; machineAddress = WordToMachine(ptr[fIndex]); memcpy(main_memory + topOfStack, &machineAddress, 4); fIndex++; } int argv = topOfStack; // envp topOfStack -= 4; machineAddress = WordToMachine(0); memcpy(main_memory + topOfStack, &machineAddress, 4); // argv topOfStack -= 4; machineAddress = WordToMachine(argv); memcpy(main_memory + topOfStack, &machineAddress, 4); // argc topOfStack -= 4; machineAddress = WordToMachine(argc); memcpy(main_memory + topOfStack, &machineAddress, 4); if (load_user_program(kos_argv[0]) < 0) { fprintf(stderr, "Error: Unable to load user program.\n"); exit(1); } start->registers[StackReg] = topOfStack - 12; start->registers[PCReg] = 0; start->registers[NextPCReg] = 4; Jval j = new_jval_v((void *)start); dll_append(queue, j); kt_exit(); }
void KtSched() { K_t kt; JRB jb; unsigned int sp; unsigned int now; JRB tmp; Dllist dtmp; /* * start by recording the current stack contents in case * I'm descheduled * * this is where I return to when I'm rescheduled */ if(setjmp(ktRunning->jmpbuf) != 0) { FreeFinishedThreads(); /* * if we are being killed by another thread, jump through * the exitbuf */ if(ktRunning->die_now) { /* Jim: This used to longjmp to the exitbuf, but I changed it for two reasons: 1. It wasn't being removed from ktActive 2. Hell will be paid if it is ktOriginal. I believe kt_exit() is cleaner. I have not tested it. I should. */ kt_exit(); /* not reached */ } return; } start: if (!jrb_empty(ktSleeping)) { now = time(0); while(!jrb_empty(ktSleeping)) { kt = (K_t) jval_v(jrb_val(jrb_first(ktSleeping))); if(kt->wake_time > now) { break; } WakeKThread(kt); } } /* * if there is nothing left to run, exit. However, if there * are sleepers or a joinall, deal with them appropriately */ if(dll_empty(ktRunnable)) { /* * first, check for sleepers and deal with them */ if(!jrb_empty(ktSleeping)) { kt = jval_v(jrb_val(jrb_first(ktSleeping))); sleep(kt->wake_time - now); goto start; } /* * next, see if there is a joinall thread waiting */ jb = jrb_find_int(ktBlocked,0); if(jb != NULL) { WakeKThread((K_t)jval_v(jrb_val(jb))); goto start; } if(!jrb_empty(ktBlocked)) { if(Debug & KT_DEBUG) { fprintf(stderr, "All processes blocked, exiting\n"); fflush(stderr); } exit(1); } else { if(Debug & KT_DEBUG) { fprintf(stderr, "No runnable threads, exiting\n"); fflush(stderr); } exit(0); } fprintf(stderr, "We shouldn't get here\n"); exit(1); } /* Grab the first job of the ready queue */ dtmp = dll_first(ktRunnable); kt = (K_t) dtmp->val.v; dll_delete_node(dtmp); /* If it is runnable, run it */ if(kt->state == RUNNABLE) { ktRunning = kt; ktRunning->state = RUNNING; longjmp(ktRunning->jmpbuf,1); /* This doesn't return */ } /* * if we have never run before, set up initial stack and go */ if(kt->state == STARTING) { if(setjmp(kt->jmpbuf) == 0) { /* * get double word aligned SP -- stacks grow from high * to low */ sp = (unsigned int)&((kt->stack[kt->stack_size-1])); while((sp % 8) != 0) sp--; #ifdef LINUX /* * keep double word aligned but put in enough * space to handle local variables for KtSched */ kt->jmpbuf->__jmpbuf[JB_BP] = (int)sp; kt->jmpbuf->__jmpbuf[JB_SP] = (int)sp-1024; PTR_MANGLE(kt->jmpbuf->__jmpbuf[JB_SP]); #endif #ifdef SOLARIS /* * keep double word aligned but put in enough * space to handle local variables for KtSched */ kt->jmpbuf[JB_FP] = (int)sp; kt->jmpbuf[JB_SP] = (int)sp-1024; #endif /* * set ktRunning while we still have local variables */ kt->state = RUNNING; ktRunning = kt; /* * now jump onto the new stack */ longjmp(kt->jmpbuf,1); } else { /* * here we are on a new, clean stack -- touch nothing, * set the state, and call * * ktRunning is global so there is no local variable * problem * * borrow this stack to try and free the last thread * if there was one */ FreeFinishedThreads(); if(setjmp(ktRunning->exitbuf) == 0) { /* * if we were killed before we ran, skip the * function call */ if(ktRunning->die_now == 0) { ktRunning->func(ktRunning->arg); } } /* * we are back and this thread is done * * make it inactive */ jb = jrb_find_int(ktActive,ktRunning->tid); if(jb == NULL) { if(Debug & KT_DEBUG) { fprintf(stderr, "KtSched: panic -- inactive return\n"); fflush(stderr); } exit(1); } jrb_delete_node(jb); /* * look to see if there is a thread waiting for this * one to exit -- careful with locals */ jb = jrb_find_int(ktBlocked,ktRunning->tid); if(jb != NULL) { WakeKThread((K_t)jval_v(jrb_val(jb))); } /* * all we can do now is to commit suicide * * don't touch the locals; * * and don't free the stack we are running on */ FreeFinishedThreads(); ktRunning->state = DEAD; dll_append(ktFree_me,new_jval_v(ktRunning)); ktRunning = NULL; goto start; } } /* The only way we get here is if there was a thread on the runnable queue whose state was not RUNNABLE or STARTING. Flag that as an error */ fprintf(stderr, "Error: non-STARTING or RUNNABLE thread on the ready queue\n"); exit(1); }
void *initialize_user_process(void *arg){ PCB *user_process; Jval jval_pcb; Jval user_process_child_node; char **filename; int base; int arg_count; int errno; int i; arg_count = 0; errno = 0; i = 0; /* Unmarshalling */ filename = (char **) arg; /* Create the global init process */ init = (PCB *)malloc(sizeof(PCB)); init->registers = (int *)malloc(sizeof(int) * NumTotalRegs); // Initialize init's registers */ for (i = 0; i < NumTotalRegs; i++) { init->registers[i] = 0; } // Initialize init's other variables init->pid = (int *)0; init->waiter = make_kt_sem(0); init->waiters = new_dllist(); init->children = make_jrb(); /* Allocate new PCB and initialize registers */ user_process = (PCB *)malloc(sizeof(PCB)); user_process->registers = (int *)malloc(NumTotalRegs * sizeof(int)); for (i = 0; i < NumTotalRegs; i++) { user_process->registers[i] = 0; } // Obtain pid and partiton memory for new process user_process->pid = (int *)get_new_pid(); base = partition_memory(user_process->pid); // Initialize first process' other variables user_process->waiter = make_kt_sem(0); user_process->waiters = new_dllist(); user_process->children = make_jrb(); // Set base and limit for new process user_process->base = 0; user_process->limit = MemorySize/8; // Set User global vars User_Base = base; User_Limit = user_process->limit; // Set process' PCRegs user_process->registers[PCReg] = 0; user_process->registers[NextPCReg] = 4; // Set first process' parent as init and add to init's children user_process->parent = (struct PCB *)init; user_process_child_node.v = user_process; jrb_insert_int(init->children, (int)user_process->pid, user_process_child_node); // Get number of args and turn off exec flag. while (filename[arg_count] != NULL) { arg_count++; } totalArgs = arg_count; is_exec = 0; /* Call perform_execve */ errno = perform_execve(user_process, filename[0], filename); // If errors, returns proper errno if (errno != 1) { syscall_return(user_process, errno); } else { // Puts new job onto readyQ and calls kt_exit() jval_pcb.v = user_process; dll_append(readyQ, jval_pcb); kt_exit(); } }