void fault_handler(void) { INT32 device_id; INT32 status; INT32 Index = 0; static INT32 how_many_interrupt_entries = 0; // Get cause of interrupt read_from_memory(Z502InterruptDevice, &device_id); // Set this device as target of our query write_to_memory(Z502InterruptDevice, &device_id); // Now read the status of this device read_from_memory(Z502InterruptStatus, &status); if (ConfigArgument->show_other_output == Full) { printf("Fault_handler: Found vector type %d with value %d\n", device_id, status); } else if (ConfigArgument->show_other_output == Limited) { how_many_interrupt_entries++; if (how_many_interrupt_entries < 10) { printf("Fault_handler: Found vector type %d with value %d\n", device_id, status); } } if (status >= 1024) { printf("Invalid address: virtual page number out of range!\n"); shut_down(); } frame_scheduler(status); // Conditional output. if (ConfigArgument->show_memory_output == Full) { int idx; for (idx = 0; idx < NUM_OF_FRAMES; idx++) { if (shadow_pg_tbl[idx] != NULL) { MP_setup((INT32) ((*shadow_pg_tbl[idx]) & PTBL_FRAME_BITS), (INT32) process_holder[idx], (INT32) (shadow_pg_tbl[idx] - address_holder[process_holder[idx]]), (INT32) ((*shadow_pg_tbl[idx]) & PTBL_STATE_BITS) >> 13); } }
/************************************************************************ INTERRUPT_HANDLER When the Z502 gets a hardware interrupt, it transfers control to this routine in the OS. ************************************************************************/ void interrupt_handler(void) { INT32 status; INT32 device_id; INT32 Index = 0; static BOOL remove_this_in_your_code = TRUE; static INT32 how_many_interrupt_entries = 0; // Get cause of interrupt read_from_memory(Z502InterruptDevice, &device_id); // Set this device as target of our query write_to_memory(Z502InterruptDevice, &device_id); // Now read the status of this device read_from_memory(Z502InterruptStatus, &status); // Conditional output. if (ConfigArgument->show_other_output == Full) { printf("Interrupt_handler: Found device ID %d with status %d\n", device_id, status); } else if (ConfigArgument->show_other_output == Limited) { how_many_interrupt_entries++; /** TEMP **/ if (remove_this_in_your_code && (how_many_interrupt_entries < 10)) { printf("Interrupt_handler: Found device ID %d with status %d\n", device_id, status); } } if (device_id == 4) { os_make_ready_to_run(); } else if (device_id >= 5 || device_id <= 7) { read_write_scheduler(device_id); } Index = 0; write_to_memory(Z502InterruptClear, &Index); read_from_memory(Z502InterruptDevice, &device_id); // Clear out this device - we're done with it write_to_memory(Z502InterruptClear, &Index); } /* End of interrupt_handler */
/** * Read data from the specific position indicated by the disk id and sector id. * @param disk_id: Indicates which disk to read from. * @param sector: Indicates which sector to read from. * @param buffer: The buffer to hold the data. */ void os_disk_read(INT32 disk_id, INT32 sector, char *buffer) { INT32 status; int result; write_to_memory(Z502DiskSetID, &disk_id); read_from_memory(Z502DiskStatus, &status); // Disk hasn't been used - should be free if (status == DEVICE_FREE) { write_to_memory(Z502DiskSetSector, §or); write_to_memory(Z502DiskSetBuffer, (INT32 *) buffer); status = 0; // Specify a read write_to_memory(Z502DiskSetAction, &status); status = 0; // Must be set to 0 write_to_memory(Z502DiskStart, &status); CurrentPCB->disk_id = disk_id; CurrentPCB->operation = -1; get_data_lock(SUSPEND_QUEUE_LOCK); result = add_to_suspend_queue(CurrentPCB); release_data_lock(SUSPEND_QUEUE_LOCK); if (result) { CurrentPCB->suspend = TRUE; print_scheduling_info(ACTION_NAME_READ, CurrentPCB, NORMAL_INFO); } else { error_message("add_to_suspend_queue"); shut_down(); } os_dispatcher(); } else if (status == DEVICE_IN_USE) { CurrentPCB->disk_id = disk_id; CurrentPCB->operation = READ_ONE; CurrentPCB->disk = disk_id; CurrentPCB->sector = sector; CurrentPCB->disk_data = (DISK_DATA *) buffer; get_data_lock(SUSPEND_QUEUE_LOCK); result = add_to_suspend_queue(CurrentPCB); release_data_lock(SUSPEND_QUEUE_LOCK); if (result) { CurrentPCB->suspend = TRUE; print_scheduling_info(ACTION_NAME_READ, CurrentPCB, NORMAL_INFO); } else { error_message("add_to_suspend_queue"); shut_down(); } os_dispatcher(); } }
ViewReaction * Calculator::proceed_to_next_state(INPUT_TYPES input_type, OPERATION_MODE operation_mode, int number) { switch (input_type) { case INPUT_TYPES::OPERAND_CHARACTER: on_character_insertion(input_type); break; case INPUT_TYPES::OPERATOR: execute_operation(operation_mode, number, input_type); break; case INPUT_TYPES::MEMORY_SAVE: save_in_memory(number, input_type); break; case INPUT_TYPES::MEMORY_READ: read_from_memory(input_type); break; case INPUT_TYPES::CLEAR_HISTORY: clear_history(input_type); break; } }
int main (int argc, char* argv[]) { char** array; unsigned array_size; char command[32]; unsigned array_index; char command_letter; int size_or_position; int error = 0; #ifdef MTRACE mtrace (); #endif /* MTRACE */ if (argc != 2) { fprintf (stderr, "%s: array-size\n", argv[0]); return 1; } array_size = strtoul (argv[1], 0, 0); array = (char **) calloc (array_size, sizeof (char *)); assert (array != 0); /* Follow the user's commands. */ while (!error) { printf ("Please enter a command: "); command_letter = getchar (); assert (command_letter != EOF); switch (command_letter) { case 'a': fgets (command, sizeof (command), stdin); if (sscanf (command, "%u %i", &array_index, &size_or_position) == 2 && array_index < array_size) allocate (&(array[array_index]), size_or_position); else error = 1; break; case 'd': fgets (command, sizeof (command), stdin); if (sscanf (command, "%u", &array_index) == 1 && array_index < array_size) deallocate (&(array[array_index])); else error = 1; break; case 'r': fgets (command, sizeof (command), stdin); if (sscanf (command, "%u %i", &array_index, &size_or_position) == 2 && array_index < array_size) read_from_memory (array[array_index], size_or_position); else error = 1; break; case 'w': fgets (command, sizeof (command), stdin); if (sscanf (command, "%u %i", &array_index, &size_or_position) == 2 && array_index < array_size) write_to_memory (array[array_index], size_or_position); else error = 1; break; case 'q': free ((void *) array); return 0; default: error = 1; } } free ((void *) array); return 1; }
/** * Write data into the specific position indicated by the disk id and sector id. * @param disk_id: Indicates which disk to write to. * @param sector: Indicates which sector to write to. * @param buffer: The data needs to be written. */ void os_disk_write(INT32 disk_id, INT32 sector, char *buffer) { INT32 status; int result; /* Do the hardware call to put data on disk */ write_to_memory(Z502DiskSetID, &disk_id); read_from_memory(Z502DiskStatus, &status); // If the disk is free, indicates success in writing. if (status == DEVICE_FREE) { write_to_memory(Z502DiskSetSector, §or); write_to_memory(Z502DiskSetBuffer, (INT32 *) buffer); status = 1; // Specify a write write_to_memory(Z502DiskSetAction, &status); status = 0; // Must be set to 0 write_to_memory(Z502DiskStart, &status); CurrentPCB->disk_id = disk_id; CurrentPCB->operation = -1; get_data_lock(SUSPEND_QUEUE_LOCK); result = add_to_suspend_queue(CurrentPCB); release_data_lock(SUSPEND_QUEUE_LOCK); if (result) { CurrentPCB->suspend = TRUE; print_scheduling_info(ACTION_NAME_SUSPEND, CurrentPCB, NORMAL_INFO); } else { error_message("add_to_suspend_queue"); shut_down(); } os_dispatcher(); return; } // If the disk is busy, indicates failure in writing. else if (status == DEVICE_IN_USE) { DISK_DATA *disk_data; disk_data = (DISK_DATA *) calloc(1, sizeof ( DISK_DATA)); CurrentPCB->disk_id = disk_id; CurrentPCB->operation = WRITE_ONE; CurrentPCB->disk = disk_id; CurrentPCB->sector = sector; memcpy(disk_data, buffer, sizeof (DISK_DATA)); CurrentPCB->disk_data = disk_data; result = add_to_suspend_queue(CurrentPCB); if (result) { CurrentPCB->suspend = TRUE; print_scheduling_info(ACTION_NAME_WRITE, CurrentPCB, NORMAL_INFO); } else { error_message("add_to_suspend_queue"); shut_down(); } os_dispatcher(); return; } else { printf("some error not processed in os_disk_write!\n"); } }
/** * Used for interrupt handler. According to the action the process wants to take, * do the corresponding work and call dispatcher to schedule the processes. * @param device_id: The id of the device obtained from interrupt handler. */ void read_write_scheduler(INT32 device_id) { PCB *pcb; INT16 disk_id; switch (device_id) { case 5: disk_id = 1; break; case 6: disk_id = 2; break; case 7: disk_id = 3; break; default: error_message("Illegal device id."); break; } pcb = remove_from_suspend_queue_by_disk_id(disk_id); if (pcb != NULL) { // If the process needs to write, then write data to specific sector. if (pcb->operation == WRITE_ONE) { INT32 status; write_to_memory(Z502DiskSetID, & pcb->disk); read_from_memory(Z502DiskStatus, &status); if (status == DEVICE_FREE) { write_to_memory(Z502DiskSetSector, & pcb->sector); write_to_memory(Z502DiskSetBuffer, (INT32 *) pcb->disk_data); status = 1; // Specify a write. write_to_memory(Z502DiskSetAction, &status); status = 0; // Must be set to 0. write_to_memory(Z502DiskStart, &status); pcb->operation = WRITE_TWO; enqueue_suspend_queue_reversly(pcb); pcb->suspend = TRUE; print_scheduling_info(ACTION_NAME_WRITE, pcb, NORMAL_INFO); } else { enqueue_suspend_queue_reversly(pcb); pcb->suspend = TRUE; print_scheduling_info(ACTION_NAME_WRITE, pcb, NORMAL_INFO); } } // If the process needs to read, then read data from specific sector. else if (pcb->operation == READ_ONE) { INT32 status; write_to_memory(Z502DiskSetID, & pcb->disk); read_from_memory(Z502DiskStatus, &status); if (status == DEVICE_FREE) { write_to_memory(Z502DiskSetSector, & pcb->sector); write_to_memory(Z502DiskSetBuffer, (INT32 *) pcb->disk_data); status = 0; // Specify a read. write_to_memory(Z502DiskSetAction, &status); status = 0; // Must be set to 0. write_to_memory(Z502DiskStart, &status); pcb->operation = READ_TWO; enqueue_suspend_queue_reversly(pcb); pcb->suspend = TRUE; print_scheduling_info(ACTION_NAME_READ, pcb, NORMAL_INFO); } else { // If in use, add it reversely. enqueue_suspend_queue_reversly(pcb); pcb->suspend = TRUE; print_scheduling_info(ACTION_NAME_READ, pcb, NORMAL_INFO); } } else { add_to_ready_queue(pcb); pcb->suspend = FALSE; print_scheduling_info(ACTION_NAME_READY, pcb, NORMAL_INFO); } } }
// Evict Page returns the location of the lowest open slot in the provided memory level // If there are no open spots, it uses the paging algorithm to evict one page from the memlev // and move it to the next one. int evict_page(Memlev memlev) { // printf("Trying to evict a page.\n"); // Interate through the entire page table // If there is still room available in ram // find the lowest available location and return the data int i; int max_elements = 0; // This switch case determines the memory level the eviction is on // if the provided memlevel is "nul" or "hdd", not page can be // evicted and an error value of -2 is returned. switch(memlev){ case ram: // printf("Trying to evict page from ram\n"); max_elements = MAXRAM; break; case ssd: // printf("Trying to evict page from ssd\n"); max_elements = MAXSSD; break; case hdd: // printf("Trying to evict page from hdd\n"); max_elements = MAXHDD; break; default: printf("Trying to evict page from the 'nul' level\n"); return -2; break; break; } // This is the list of all the available pageframes in a memlev // 1 = taken, 0 = available int slots[max_elements]; // Iterate through the entire page table, marking all the taken pageframes for(int i = 0; i < max_elements; i++){ slots[i] = 0; } // Iterate through the entire page table, marking all the taken pageframes for(i = 0; i < MAXADDR; i++){ if(page_table[i].memlev == memlev && page_table[i].empty == 0){ slots[page_table[i].location] = 1; } } // Once all the take page frames are marked, see if any are still available for(i = 0; i < max_elements; i++){ // If there is a pageframe available // update the location with the ram information and return it. if(slots[i] == 0){ switch(memlev){ case ram: // printf("Trying to lock ram slot %i\n", i); if(pthread_mutex_trylock(&(lock_ram[i])) == 0){ // printf("Successfully locked ram slot %i\n", i); return i; } // printf("Failed to lock ram slot %i\n", i); break; case ssd: if(pthread_mutex_trylock(&(lock_ssd[i])) == 0){ return i; } break; case hdd: if(pthread_mutex_trylock(&(lock_hdd[i])) == 0){ return i; } break; break; } } } // If there are no spots in this memory level, // then we will have to move a page out // and into the higher memory level // Here we call evict on the next memory level // to find a place to move the evicted page // printf("'We need to go deeper'\n"); int new_slot = evict_page(memlev + 1); if(new_slot < 0){ printf("There is a serious problem\n"); } // We call our custom algorithm to find a page to evict vAddr temp_page = page_to_remove(memlev, type_r); // finally we move the content to the higher memory level switch(memlev) { case ram: write_to_memory(ssd, new_slot, read_from_memory(ram, page_table[temp_page].location)); break; case ssd: write_to_memory(hdd, new_slot, read_from_memory(ssd, page_table[temp_page].location)); break; break; } // update it's paging information to reflect the new position page_table[temp_page].memlev = memlev + 1; int result = page_table[temp_page].location; page_table[temp_page].location = new_slot; // Unlock the modified page pthread_mutex_unlock(&(page_table[temp_page].lock)); // And return the newly opened pageframe return result; }
// This method takes in a page address and content // and tries to put the content in the desired page // If the page is not in RAM, a page fault is generated and the page is moved into ram // Error = 0, success // Error = 1, desired page is outside page table range // Error = 2, Requested page is empty int store_value(vAddr address, content c) { if(printing == 2){ printf("Storing value %i in page %i\n", c, address); } if((address > MAXADDR) || (address < 0)){ if(printing == 2){ printf("Page Fault: Tried to access an page outside range: %d\n",address); } return 1; } // return the result if(page_table[address].empty) { if(printing == 2){ printf("Page Fault: Requested page is empty: %d\n",address); } return 2; } // Lock this page to prevent other threads from manipulating it pthread_mutex_lock(&(page_table[address].lock)); // check if the desired page is in RAM if(page_table[address].memlev != ram) { if(printing == 2){ printf("Page Fault: requested page not in RAM\n"); } int new_location = evict_page(ram); write_to_memory(ram, new_location, read_from_memory(page_table[address].memlev, page_table[address].location)); // Unlock the now free pageframe in the previous memory level switch(page_table[address].memlev){ case ssd: pthread_mutex_unlock(&(lock_ssd[page_table[address].location])); break; case hdd: pthread_mutex_unlock(&(lock_hdd[page_table[address].location])); break; break; } // update the information for the page page_table[address].memlev = ram; page_table[address].location = new_location; page_table[address].referenced++; if(printing == 2){ printf("Recovered from Page Fault: requested page not in RAM\n"); } } // write the information to the ram location write_to_memory(ram, page_table[address].location, c); if(printing == 2){ printf("\n"); } // Unlock the page pthread_mutex_unlock(&(page_table[address].lock)); return 0; }