├── output ├── m1 ├── m0 ├── sched_0 ├── os_0 ├── sched_1 └── os_1 ├── input ├── os_0 ├── sched_0 ├── sched_1 ├── proc │ ├── s1 │ ├── m0 │ ├── m1 │ ├── s2 │ ├── p1 │ ├── p0 │ ├── s0 │ └── s3 └── os_1 ├── .DS_Store ├── assignment_202.pdf ├── Operating_System_Assignment.pdf ├── include ├── loader.h ├── cpu.h ├── queue.h ├── sched.h ├── timer.h ├── mem.h └── common.h ├── src ├── paging.c ├── queue.c ├── sched.c ├── cpu.c ├── loader.c ├── timer.c ├── os.c └── mem.c ├── README.md └── Makefile /output/m1: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /input/os_0: -------------------------------------------------------------------------------- 1 | 6 2 4 2 | 0 p0 3 | 2 p1 4 | -------------------------------------------------------------------------------- /input/sched_0: -------------------------------------------------------------------------------- 1 | 2 1 2 2 | 0 s0 3 | 4 s1 4 | -------------------------------------------------------------------------------- /input/sched_1: -------------------------------------------------------------------------------- 1 | 2 1 4 2 | 0 s0 3 | 4 s1 4 | 6 s2 5 | 7 s3 6 | -------------------------------------------------------------------------------- /input/proc/s1: -------------------------------------------------------------------------------- 1 | 20 7 2 | calc 3 | calc 4 | calc 5 | calc 6 | calc 7 | calc 8 | calc 9 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phkhanhtrinh23/segmentation_with_paging/HEAD/.DS_Store -------------------------------------------------------------------------------- /input/os_1: -------------------------------------------------------------------------------- 1 | 2 4 8 2 | 1 p0 3 | 2 s3 4 | 4 m1 5 | 6 s2 6 | 7 m0 7 | 9 p1 8 | 11 s0 9 | 16 s1 10 | -------------------------------------------------------------------------------- /assignment_202.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phkhanhtrinh23/segmentation_with_paging/HEAD/assignment_202.pdf -------------------------------------------------------------------------------- /Operating_System_Assignment.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/phkhanhtrinh23/segmentation_with_paging/HEAD/Operating_System_Assignment.pdf -------------------------------------------------------------------------------- /input/proc/m0: -------------------------------------------------------------------------------- 1 | 1 7 2 | alloc 13535 0 3 | alloc 1568 1 4 | free 0 5 | alloc 1386 2 6 | alloc 4564 4 7 | write 102 1 20 8 | write 21 2 1000 9 | -------------------------------------------------------------------------------- /input/proc/m1: -------------------------------------------------------------------------------- 1 | 1 8 2 | alloc 13535 0 3 | alloc 1568 1 4 | free 0 5 | alloc 1386 2 6 | alloc 4564 4 7 | free 2 8 | free 4 9 | free 1 10 | -------------------------------------------------------------------------------- /input/proc/s2: -------------------------------------------------------------------------------- 1 | 20 12 2 | calc 3 | calc 4 | calc 5 | calc 6 | calc 7 | calc 8 | calc 9 | calc 10 | calc 11 | calc 12 | calc 13 | calc 14 | calc 15 | -------------------------------------------------------------------------------- /include/loader.h: -------------------------------------------------------------------------------- 1 | #ifndef LOADER_H 2 | #define LOADER_H 3 | 4 | #include "common.h" 5 | 6 | struct pcb_t * load(const char * path); 7 | 8 | #endif 9 | 10 | -------------------------------------------------------------------------------- /input/proc/p1: -------------------------------------------------------------------------------- 1 | 1 10 2 | calc 3 | alloc 4133 0 4 | alloc 37812 2 5 | free 2 6 | alloc 3125 1 7 | calc 8 | write 10 0 2535 9 | alloc 3215 2 10 | free 1 11 | calc 12 | -------------------------------------------------------------------------------- /input/proc/p0: -------------------------------------------------------------------------------- 1 | 1 10 2 | calc 3 | alloc 1232 0 4 | alloc 4214 4 5 | free 0 6 | alloc 102 1 7 | write 100 1 20 8 | read 1 20 2 9 | calc 10 | calc 11 | free 4 12 | calc 13 | -------------------------------------------------------------------------------- /input/proc/s0: -------------------------------------------------------------------------------- 1 | 12 15 2 | calc 3 | calc 4 | calc 5 | calc 6 | calc 7 | calc 8 | calc 9 | calc 10 | calc 11 | calc 12 | calc 13 | calc 14 | calc 15 | calc 16 | calc 17 | -------------------------------------------------------------------------------- /input/proc/s3: -------------------------------------------------------------------------------- 1 | 7 11 2 | calc 3 | calc 4 | calc 5 | calc 6 | calc 7 | calc 8 | calc 9 | calc 10 | calc 11 | calc 12 | calc 13 | calc 14 | calc 15 | calc 16 | calc 17 | calc 18 | calc 19 | -------------------------------------------------------------------------------- /include/cpu.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CPU_H 3 | #define CPU_H 4 | 5 | #include "common.h" 6 | 7 | /* Execute an instruction of a process. Return 0 8 | * if the instruction is executed successfully. 9 | * Otherwise, return 1. */ 10 | int run(struct pcb_t * proc); 11 | 12 | #endif 13 | 14 | -------------------------------------------------------------------------------- /include/queue.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef QUEUE_H 3 | #define QUEUE_H 4 | 5 | #include "common.h" 6 | 7 | #define MAX_QUEUE_SIZE 10 8 | 9 | struct queue_t { 10 | struct pcb_t * proc[MAX_QUEUE_SIZE]; 11 | int size; 12 | }; 13 | 14 | void enqueue(struct queue_t * q, struct pcb_t * proc); 15 | 16 | struct pcb_t * dequeue(struct queue_t * q); 17 | 18 | int empty(struct queue_t * q); 19 | 20 | #endif 21 | 22 | -------------------------------------------------------------------------------- /src/paging.c: -------------------------------------------------------------------------------- 1 | 2 | #include "mem.h" 3 | #include "cpu.h" 4 | #include "loader.h" 5 | #include 6 | #include 7 | 8 | int main(int argc, char ** argv) { 9 | if (argc < 2) { 10 | printf("Cannot find input process\n"); 11 | exit(1); 12 | } 13 | struct pcb_t * proc = load(argv[1]); 14 | unsigned int i; 15 | for (i = 0; i < proc->code->size; i++) { 16 | run(proc); 17 | } 18 | dump(); 19 | return 0; 20 | } 21 | 22 | -------------------------------------------------------------------------------- /include/sched.h: -------------------------------------------------------------------------------- 1 | #ifndef QUEUE_H 2 | #define QUEUE_H 3 | 4 | #include "common.h" 5 | 6 | int queue_empty(void); 7 | 8 | void init_scheduler(void); 9 | void finish_scheduler(void); 10 | 11 | /* Get the next process from ready queue */ 12 | struct pcb_t * get_proc(void); 13 | 14 | /* Put a process back to run queue */ 15 | void put_proc(struct pcb_t * proc); 16 | 17 | /* Add a new process to ready queue */ 18 | void add_proc(struct pcb_t * proc); 19 | 20 | #endif 21 | 22 | 23 | -------------------------------------------------------------------------------- /output/m0: -------------------------------------------------------------------------------- 1 | 000: 00000-003ff - PID: 01 (idx 000, nxt: 001) 2 | 003e8: 14 3 | 001: 00400-007ff - PID: 01 (idx 001, nxt: -01) 4 | 002: 00800-00bff - PID: 01 (idx 000, nxt: 003) 5 | 003: 00c00-00fff - PID: 01 (idx 001, nxt: 004) 6 | 004: 01000-013ff - PID: 01 (idx 002, nxt: 005) 7 | 005: 01400-017ff - PID: 01 (idx 003, nxt: 006) 8 | 006: 01800-01bff - PID: 01 (idx 004, nxt: -01) 9 | 014: 03800-03bff - PID: 01 (idx 000, nxt: 015) 10 | 03814: 64 11 | 015: 03c00-03fff - PID: 01 (idx 001, nxt: -01) 12 | -------------------------------------------------------------------------------- /include/timer.h: -------------------------------------------------------------------------------- 1 | #ifndef TIMER_H 2 | #define TIMER_H 3 | 4 | #include 5 | #include 6 | 7 | struct timer_id_t { 8 | int done; 9 | int fsh; 10 | pthread_cond_t event_cond; 11 | pthread_mutex_t event_lock; 12 | pthread_cond_t timer_cond; 13 | pthread_mutex_t timer_lock; 14 | }; 15 | 16 | void start_timer(); 17 | 18 | void stop_timer(); 19 | 20 | struct timer_id_t * attach_event(); 21 | 22 | void detach_event(struct timer_id_t * event); 23 | 24 | void next_slot(struct timer_id_t* timer_id); 25 | 26 | uint64_t current_time(); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /src/queue.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "queue.h" 4 | 5 | int empty(struct queue_t * q) { 6 | return (q->size == 0); 7 | } 8 | 9 | void enqueue(struct queue_t * q, struct pcb_t * proc) { 10 | /* TODO: put a new process to queue [q] */ 11 | if (q->size >= MAX_QUEUE_SIZE) return; 12 | size_t i; 13 | for (i=0; isize; i++){ 14 | if (proc->priority < q->proc[i]->priority) break; 15 | } 16 | for (size_t j=q->size; j>i; j--){ 17 | q->proc[j] = q->proc[j-1]; 18 | } 19 | q->proc[i] = proc; 20 | q->size++; 21 | } 22 | 23 | struct pcb_t * dequeue(struct queue_t * q) { 24 | /* TODO: return a pcb whose prioprity is the highest 25 | * in the queue [q] and remember to remove it from q 26 | * */ 27 | if (empty(q) == 1){ 28 | return NULL; 29 | } 30 | else{ 31 | q->size--; 32 | return q->proc[q->size]; 33 | } 34 | } 35 | 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Operating Systems CO2017 2 | ## About 3 | The objective of this assignment is the simulation of major components in a simple operating system, 4 | for example, scheduler, synchronization, related operations of physical memory and virtual memory. 5 | 6 | ## Description 7 | In detail, student will practice with three major modules: scheduler, synchronization, mechanism 8 | of memory allocation from virtual-to-physical memory. 9 | - scheduler 10 | - synchronization 11 | - the operations of mem-allocation from virtual-to-physical 12 | 13 | **Note**: 14 | - The instructions and information are included in ```assignment_202.pdf```. 15 | - Our report is in ```Operating_System_Assignment.pdf```. 16 | - All of the source codes are in ```src``` and their header file are in ```include```. Checking system is conducted by using ```input``` and ```ouput```. 17 | 18 | ## Result 19 | After this assignment, student can understand partly the principle of a simple OS. They can draw 20 | the role and meaning of key modules in the OS as well as how it works. 21 | -------------------------------------------------------------------------------- /include/mem.h: -------------------------------------------------------------------------------- 1 | #ifndef MEM_H 2 | #define MEM_H 3 | 4 | #include "common.h" 5 | 6 | #define RAM_SIZE (1 << ADDRESS_SIZE) 7 | 8 | /* Init related parameters, must be called before being used */ 9 | void init_mem(void); 10 | 11 | /* Allocate [size] bytes for process [proc] and return its virtual address. 12 | * If we cannot allocate new memory region for this process, return 0 */ 13 | addr_t alloc_mem(uint32_t size, struct pcb_t * proc); 14 | 15 | /* Free a memory block having the first byte at [address] used by 16 | * process [proc]. Return 0 if [address] is valid. Otherwise, return 1 */ 17 | int free_mem(addr_t address, struct pcb_t * proc); 18 | 19 | /* Read 1 byte memory pointed by [address] used by process [proc] and 20 | * save it to [data]. 21 | * If the given [address] is valid, return 0. Otherwise, return 1 */ 22 | int read_mem(addr_t address, struct pcb_t * proc, BYTE * data); 23 | 24 | /* Write [data] to 1 byte on the memory pointed by [address] of process 25 | * [proc]. If given [address] is valid, return 0. Otherwise, return 1 */ 26 | int write_mem(addr_t address, struct pcb_t * proc, BYTE data); 27 | 28 | void dump(void); 29 | 30 | #endif 31 | 32 | 33 | -------------------------------------------------------------------------------- /src/sched.c: -------------------------------------------------------------------------------- 1 | 2 | #include "queue.h" 3 | #include "sched.h" 4 | #include 5 | 6 | static struct queue_t ready_queue; 7 | static struct queue_t run_queue; 8 | static pthread_mutex_t queue_lock; 9 | 10 | int queue_empty(void) { 11 | return (empty(&ready_queue) && empty(&run_queue)); 12 | } 13 | 14 | void init_scheduler(void) { 15 | ready_queue.size = 0; 16 | run_queue.size = 0; 17 | pthread_mutex_init(&queue_lock, NULL); 18 | } 19 | 20 | struct pcb_t * get_proc(void) { 21 | struct pcb_t * proc = NULL; 22 | /* TODO: get a process from [ready_queue]. If ready queue 23 | * is empty, push all processes in [run_queue] back to 24 | * [ready_queue] and return the highest priority one. 25 | * Remember to use lock to protect the queue. 26 | * */ 27 | pthread_mutex_lock(&queue_lock); 28 | if(empty(&ready_queue) == 1){ 29 | while(empty(&run_queue) != 1){ 30 | struct pcb_t* temp = dequeue(&run_queue); 31 | enqueue(&ready_queue, temp); 32 | } 33 | } 34 | proc = dequeue(&ready_queue); 35 | pthread_mutex_unlock(&queue_lock); 36 | 37 | return proc; 38 | } 39 | 40 | void put_proc(struct pcb_t * proc) { 41 | pthread_mutex_lock(&queue_lock); 42 | enqueue(&run_queue, proc); 43 | pthread_mutex_unlock(&queue_lock); 44 | } 45 | 46 | void add_proc(struct pcb_t * proc) { 47 | pthread_mutex_lock(&queue_lock); 48 | enqueue(&ready_queue, proc); 49 | pthread_mutex_unlock(&queue_lock); 50 | } 51 | 52 | 53 | -------------------------------------------------------------------------------- /output/sched_0: -------------------------------------------------------------------------------- 1 | Time slot 0 2 | Loaded a process at input/proc/s0, PID: 1 3 | CPU 0: Dispatched process 1 4 | Time slot 1 5 | Time slot 2 6 | CPU 0: Put process 1 to run queue 7 | CPU 0: Dispatched process 1 8 | Time slot 3 9 | Time slot 4 10 | Loaded a process at input/proc/s1, PID: 2 11 | CPU 0: Put process 1 to run queue 12 | CPU 0: Dispatched process 2 13 | Time slot 5 14 | Time slot 6 15 | CPU 0: Put process 2 to run queue 16 | CPU 0: Dispatched process 2 17 | Time slot 7 18 | Time slot 8 19 | CPU 0: Put process 2 to run queue 20 | CPU 0: Dispatched process 1 21 | Time slot 9 22 | Time slot 10 23 | CPU 0: Put process 1 to run queue 24 | CPU 0: Dispatched process 2 25 | Time slot 11 26 | Time slot 12 27 | CPU 0: Put process 2 to run queue 28 | CPU 0: Dispatched process 1 29 | Time slot 13 30 | Time slot 14 31 | CPU 0: Put process 1 to run queue 32 | CPU 0: Dispatched process 2 33 | Time slot 15 34 | CPU 0: Processed 2 has finished 35 | CPU 0: Dispatched process 1 36 | Time slot 16 37 | Time slot 17 38 | CPU 0: Put process 1 to run queue 39 | CPU 0: Dispatched process 1 40 | Time slot 18 41 | Time slot 19 42 | CPU 0: Put process 1 to run queue 43 | CPU 0: Dispatched process 1 44 | Time slot 20 45 | Time slot 21 46 | CPU 0: Put process 1 to run queue 47 | CPU 0: Dispatched process 1 48 | Time slot 22 49 | CPU 0: Processed 1 has finished 50 | CPU 0 stopped 51 | 52 | MEMORY CONTENT: 53 | -------------------------------------------------------------------------------- /include/common.h: -------------------------------------------------------------------------------- 1 | #ifndef COMMON_H 2 | #define COMMON_H 3 | 4 | /* Define structs and routine could be used by every source files */ 5 | 6 | #include 7 | 8 | #define ADDRESS_SIZE 20 9 | #define OFFSET_LEN 10 10 | #define SEGMENT_LEN 5 11 | #define PAGE_LEN 5 12 | 13 | #define NUM_PAGES (1 << (ADDRESS_SIZE - OFFSET_LEN)) 14 | #define PAGE_SIZE (1 << OFFSET_LEN) 15 | 16 | typedef char BYTE; 17 | typedef uint32_t addr_t; 18 | 19 | enum ins_opcode_t { 20 | CALC, // Just perform calculation, only use CPU 21 | ALLOC, // Allocate memory 22 | FREE, // Deallocated a memory block 23 | READ, // Write data to a byte on memory 24 | WRITE // Read data from a byte on memory 25 | }; 26 | 27 | /* instructions executed by the CPU */ 28 | struct inst_t { 29 | enum ins_opcode_t opcode; 30 | uint32_t arg_0; // Argument lists for instructions 31 | uint32_t arg_1; 32 | uint32_t arg_2; 33 | }; 34 | 35 | struct code_seg_t { 36 | struct inst_t * text; 37 | uint32_t size; 38 | }; 39 | 40 | struct page_table_t { 41 | /* A row in the page table of the second layer */ 42 | struct { 43 | addr_t v_index; // The index of virtual address 44 | addr_t p_index; // The index of physical address 45 | } table[1 << SEGMENT_LEN]; 46 | int size; 47 | }; 48 | 49 | /* Mapping virtual addresses and physical ones */ 50 | struct seg_table_t { 51 | /* Translation table for the first layer */ 52 | struct { 53 | addr_t v_index; // Virtual index 54 | struct page_table_t * pages; 55 | } table[1 << PAGE_LEN]; 56 | int size; // Number of row in the first layer 57 | }; 58 | 59 | /* PCB, describe information about a process */ 60 | struct pcb_t { 61 | uint32_t pid; // PID 62 | uint32_t priority; 63 | struct code_seg_t * code; // Code segment 64 | addr_t regs[10]; // Registers, store address of allocated regions 65 | uint32_t pc; // Program pointer, point to the next instruction 66 | struct seg_table_t * seg_table; // Page table 67 | uint32_t bp; // Break pointer 68 | }; 69 | 70 | #endif 71 | 72 | -------------------------------------------------------------------------------- /src/cpu.c: -------------------------------------------------------------------------------- 1 | 2 | #include "cpu.h" 3 | #include "mem.h" 4 | 5 | static int calc(struct pcb_t * proc) { 6 | return ((unsigned long)proc & 0UL); 7 | } 8 | 9 | static int alloc(struct pcb_t * proc, uint32_t size, uint32_t reg_index) { 10 | addr_t addr = alloc_mem(size, proc); 11 | if (addr == 0) { 12 | return 1; 13 | }else{ 14 | proc->regs[reg_index] = addr; 15 | return 0; 16 | } 17 | } 18 | 19 | static int free_data(struct pcb_t * proc, uint32_t reg_index) { 20 | return free_mem(proc->regs[reg_index], proc); 21 | } 22 | 23 | static int read( 24 | struct pcb_t * proc, // Process executing the instruction 25 | uint32_t source, // Index of source register 26 | uint32_t offset, // Source address = [source] + [offset] 27 | uint32_t destination) { // Index of destination register 28 | 29 | BYTE data; 30 | if (read_mem(proc->regs[source] + offset, proc, &data)) { 31 | proc->regs[destination] = data; 32 | return 0; 33 | }else{ 34 | return 1; 35 | } 36 | } 37 | 38 | static int write( 39 | struct pcb_t * proc, // Process executing the instruction 40 | BYTE data, // Data to be wrttien into memory 41 | uint32_t destination, // Index of destination register 42 | uint32_t offset) { // Destination address = 43 | // [destination] + [offset] 44 | return write_mem(proc->regs[destination] + offset, proc, data); 45 | } 46 | 47 | int run(struct pcb_t * proc) { 48 | /* Check if Program Counter point to the proper instruction */ 49 | if (proc->pc >= proc->code->size) { 50 | return 1; 51 | } 52 | 53 | struct inst_t ins = proc->code->text[proc->pc]; 54 | proc->pc++; 55 | int stat = 1; 56 | switch (ins.opcode) { 57 | case CALC: 58 | stat = calc(proc); 59 | break; 60 | case ALLOC: 61 | stat = alloc(proc, ins.arg_0, ins.arg_1); 62 | break; 63 | case FREE: 64 | stat = free_data(proc, ins.arg_0); 65 | break; 66 | case READ: 67 | stat = read(proc, ins.arg_0, ins.arg_1, ins.arg_2); 68 | break; 69 | case WRITE: 70 | stat = write(proc, ins.arg_0, ins.arg_1, ins.arg_2); 71 | break; 72 | default: 73 | stat = 1; 74 | } 75 | return stat; 76 | 77 | } 78 | 79 | 80 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | INC = -Iinclude 3 | LIB = -lpthread 4 | 5 | SRC = src 6 | OBJ = obj 7 | INCLUDE = include 8 | 9 | CC = gcc 10 | DEBUG = -g 11 | CFLAGS = -Wall -c $(DEBUG) 12 | LFLAGS = -Wall $(DEBUG) 13 | 14 | vpath %.c $(SRC) 15 | vpath %.h $(INCLUDE) 16 | 17 | MAKE = $(CC) $(INC) 18 | 19 | # Object files needed by modules 20 | MEM_OBJ = $(addprefix $(OBJ)/, paging.o mem.o cpu.o loader.o) 21 | OS_OBJ = $(addprefix $(OBJ)/, mem.o cpu.o loader.o queue.o os.o sched.o timer.o) 22 | SCHED_OBJ = $(addprefix $(OBJ)/, cpu.o loader.o mem.o queue.o os.o sched.o timer.o) 23 | HEADER = $(wildcard $(INCLUDE)/*.h) 24 | 25 | all: mem sched os test_all 26 | 27 | # Just compile memory management modules 28 | mem: $(MEM_OBJ) 29 | $(MAKE) $(LFLAGS) $(MEM_OBJ) -o mem $(LIB) 30 | 31 | # Just compile scheduler 32 | sched: $(SCHED_OBJ) 33 | $(MAKE) $(LFLAGS) $(SCHED_OBJ) -o os $(LIB) 34 | 35 | # Compile the whole OS simulation 36 | os: $(OS_OBJ) 37 | $(MAKE) $(LFLAGS) $(OS_OBJ) -o os $(LIB) 38 | 39 | test_all: test_mem test_sched test_os 40 | 41 | test_mem: 42 | @echo ------ MEMORY MANAGEMENT TEST 0 ------------------------------------ 43 | ./mem input/proc/m0 44 | @echo NOTE: Read file output/m0 to verify your result 45 | @echo ------ MEMORY MANAGEMENT TEST 1 ------------------------------------ 46 | ./mem input/proc/m1 47 | @echo 'NOTE: Read file output/m1 to verify your result (your implementation should print nothing)' 48 | 49 | test_sched: 50 | @echo ------ SCHEDULING TEST 0 ------------------------------------------- 51 | ./os sched_0 52 | @echo NOTE: Read file output/sched_0 to verify your result 53 | @echo ------ SCHEDULING TEST 1 ------------------------------------------- 54 | ./os sched_1 55 | @echo NOTE: Read file output/sched_1 to verify your result 56 | 57 | test_os: 58 | @echo ----- OS TEST 0 ---------------------------------------------------- 59 | ./os os_0 60 | @echo NOTE: Read file output/os_0 to verify your result 61 | @echo ----- OS TEST 1 ---------------------------------------------------- 62 | ./os os_1 63 | @echo NOTE: Read file output/os_1 to verify your result 64 | 65 | $(OBJ)/%.o: %.c ${HEADER} 66 | $(MAKE) $(CFLAGS) $< -o $@ 67 | 68 | clean: 69 | rm -f obj/*.o os sched mem 70 | 71 | 72 | 73 | -------------------------------------------------------------------------------- /src/loader.c: -------------------------------------------------------------------------------- 1 | 2 | #include "loader.h" 3 | #include 4 | #include 5 | #include 6 | 7 | static uint32_t avail_pid = 1; 8 | 9 | #define OPT_CALC "calc" 10 | #define OPT_ALLOC "alloc" 11 | #define OPT_FREE "free" 12 | #define OPT_READ "read" 13 | #define OPT_WRITE "write" 14 | 15 | static enum ins_opcode_t get_opcode(char * opt) { 16 | if (!strcmp(opt, OPT_CALC)) { 17 | return CALC; 18 | }else if (!strcmp(opt, OPT_ALLOC)) { 19 | return ALLOC; 20 | }else if (!strcmp(opt, OPT_FREE)) { 21 | return FREE; 22 | }else if (!strcmp(opt, OPT_READ)) { 23 | return READ; 24 | }else if (!strcmp(opt, OPT_WRITE)) { 25 | return WRITE; 26 | }else{ 27 | printf("Opcode: %s\n", opt); 28 | exit(1); 29 | } 30 | } 31 | 32 | struct pcb_t * load(const char * path) { 33 | /* Create new PCB for the new process */ 34 | struct pcb_t * proc = (struct pcb_t * )malloc(sizeof(struct pcb_t)); 35 | proc->pid = avail_pid; 36 | avail_pid++; 37 | proc->seg_table = 38 | (struct seg_table_t*)malloc(sizeof(struct seg_table_t)); 39 | proc->bp = PAGE_SIZE; 40 | proc->pc = 0; 41 | 42 | /* Read process code from file */ 43 | FILE * file; 44 | if ((file = fopen(path, "r")) == NULL) { 45 | printf("Cannot find process description at '%s'\n", path); 46 | exit(1); 47 | } 48 | char opcode[10]; 49 | proc->code = (struct code_seg_t*)malloc(sizeof(struct code_seg_t)); 50 | fscanf(file, "%u %u", &proc->priority, &proc->code->size); 51 | proc->code->text = (struct inst_t*)malloc( 52 | sizeof(struct inst_t) * proc->code->size 53 | ); 54 | uint32_t i = 0; 55 | for (i = 0; i < proc->code->size; i++) { 56 | fscanf(file, "%s", opcode); 57 | proc->code->text[i].opcode = get_opcode(opcode); 58 | switch(proc->code->text[i].opcode) { 59 | case CALC: 60 | break; 61 | case ALLOC: 62 | fscanf( 63 | file, 64 | "%u %u\n", 65 | &proc->code->text[i].arg_0, 66 | &proc->code->text[i].arg_1 67 | ); 68 | break; 69 | case FREE: 70 | fscanf(file, "%u\n", &proc->code->text[i].arg_0); 71 | break; 72 | case READ: 73 | case WRITE: 74 | fscanf( 75 | file, 76 | "%u %u %u\n", 77 | &proc->code->text[i].arg_0, 78 | &proc->code->text[i].arg_1, 79 | &proc->code->text[i].arg_2 80 | ); 81 | break; 82 | default: 83 | printf("Opcode: %s\n", opcode); 84 | exit(1); 85 | } 86 | } 87 | return proc; 88 | } 89 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /output/os_0: -------------------------------------------------------------------------------- 1 | Time slot 0 2 | Loaded a process at input/proc/p0, PID: 1 3 | Time slot 1 4 | CPU 0: Dispatched process 1 5 | Loaded a process at input/proc/p1, PID: 2 6 | Time slot 2 7 | Time slot 3 8 | CPU 1: Dispatched process 2 9 | Loaded a process at input/proc/p1, PID: 3 10 | Time slot 4 11 | Loaded a process at input/proc/p1, PID: 4 12 | Time slot 5 13 | Time slot 6 14 | Time slot 7 15 | CPU 0: Put process 1 to run queue 16 | CPU 0: Dispatched process 4 17 | Time slot 8 18 | Time slot 9 19 | CPU 1: Put process 2 to run queue 20 | CPU 1: Dispatched process 3 21 | Time slot 10 22 | Time slot 11 23 | Time slot 12 24 | Time slot 13 25 | CPU 0: Put process 4 to run queue 26 | CPU 0: Dispatched process 1 27 | Time slot 14 28 | Time slot 15 29 | CPU 1: Put process 3 to run queue 30 | CPU 1: Dispatched process 2 31 | Time slot 16 32 | Time slot 17 33 | CPU 0: Processed 1 has finished 34 | CPU 0: Dispatched process 4 35 | Time slot 18 36 | Time slot 19 37 | CPU 1: Processed 2 has finished 38 | CPU 1: Dispatched process 3 39 | Time slot 20 40 | Time slot 21 41 | CPU 0: Processed 4 has finished 42 | CPU 0 stopped 43 | Time slot 22 44 | Time slot 23 45 | CPU 1: Processed 3 has finished 46 | CPU 1 stopped 47 | 48 | MEMORY CONTENT: 49 | 000: 00000-003ff - PID: 04 (idx 000, nxt: 001) 50 | 001: 00400-007ff - PID: 04 (idx 001, nxt: 002) 51 | 002: 00800-00bff - PID: 04 (idx 002, nxt: 003) 52 | 003: 00c00-00fff - PID: 04 (idx 003, nxt: -01) 53 | 004: 01000-013ff - PID: 03 (idx 000, nxt: 005) 54 | 005: 01400-017ff - PID: 03 (idx 001, nxt: 006) 55 | 006: 01800-01bff - PID: 03 (idx 002, nxt: 012) 56 | 007: 01c00-01fff - PID: 02 (idx 000, nxt: 008) 57 | 008: 02000-023ff - PID: 02 (idx 001, nxt: 009) 58 | 009: 02400-027ff - PID: 02 (idx 002, nxt: 010) 59 | 025e7: 0a 60 | 010: 02800-02bff - PID: 02 (idx 003, nxt: 011) 61 | 011: 02c00-02fff - PID: 02 (idx 004, nxt: -01) 62 | 012: 03000-033ff - PID: 03 (idx 003, nxt: -01) 63 | 014: 03800-03bff - PID: 04 (idx 000, nxt: 015) 64 | 015: 03c00-03fff - PID: 04 (idx 001, nxt: 016) 65 | 016: 04000-043ff - PID: 04 (idx 002, nxt: 017) 66 | 041e7: 0a 67 | 017: 04400-047ff - PID: 04 (idx 003, nxt: 018) 68 | 018: 04800-04bff - PID: 04 (idx 004, nxt: -01) 69 | 023: 05c00-05fff - PID: 02 (idx 000, nxt: 024) 70 | 024: 06000-063ff - PID: 02 (idx 001, nxt: 025) 71 | 025: 06400-067ff - PID: 02 (idx 002, nxt: 026) 72 | 026: 06800-06bff - PID: 02 (idx 003, nxt: -01) 73 | 047: 0bc00-0bfff - PID: 01 (idx 000, nxt: -01) 74 | 0bc14: 64 75 | 057: 0e400-0e7ff - PID: 03 (idx 000, nxt: 058) 76 | 058: 0e800-0ebff - PID: 03 (idx 001, nxt: 059) 77 | 059: 0ec00-0efff - PID: 03 (idx 002, nxt: 060) 78 | 0ede7: 0a 79 | 060: 0f000-0f3ff - PID: 03 (idx 003, nxt: 061) 80 | 061: 0f400-0f7ff - PID: 03 (idx 004, nxt: -01) 81 | -------------------------------------------------------------------------------- /output/sched_1: -------------------------------------------------------------------------------- 1 | Time slot 0 2 | Loaded a process at input/proc/s0, PID: 1 3 | Time slot 1 4 | CPU 0: Dispatched process 1 5 | Time slot 2 6 | Time slot 3 7 | CPU 0: Put process 1 to run queue 8 | CPU 0: Dispatched process 1 9 | Time slot 4 10 | Loaded a process at input/proc/s1, PID: 2 11 | Time slot 5 12 | CPU 0: Put process 1 to run queue 13 | CPU 0: Dispatched process 2 14 | Time slot 6 15 | Loaded a process at input/proc/s2, PID: 3 16 | Time slot 7 17 | CPU 0: Put process 2 to run queue 18 | CPU 0: Dispatched process 3 19 | Loaded a process at input/proc/s3, PID: 4 20 | Time slot 8 21 | Time slot 9 22 | CPU 0: Put process 3 to run queue 23 | CPU 0: Dispatched process 4 24 | Time slot 10 25 | Time slot 11 26 | CPU 0: Put process 4 to run queue 27 | CPU 0: Dispatched process 2 28 | Time slot 12 29 | Time slot 13 30 | CPU 0: Put process 2 to run queue 31 | CPU 0: Dispatched process 3 32 | Time slot 14 33 | Time slot 15 34 | CPU 0: Put process 3 to run queue 35 | CPU 0: Dispatched process 1 36 | Time slot 16 37 | Time slot 17 38 | CPU 0: Put process 1 to run queue 39 | CPU 0: Dispatched process 4 40 | Time slot 18 41 | Time slot 19 42 | CPU 0: Put process 4 to run queue 43 | CPU 0: Dispatched process 2 44 | Time slot 20 45 | Time slot 21 46 | CPU 0: Put process 2 to run queue 47 | CPU 0: Dispatched process 3 48 | Time slot 22 49 | Time slot 23 50 | CPU 0: Put process 3 to run queue 51 | CPU 0: Dispatched process 1 52 | Time slot 24 53 | Time slot 25 54 | CPU 0: Put process 1 to run queue 55 | CPU 0: Dispatched process 4 56 | Time slot 26 57 | Time slot 27 58 | CPU 0: Put process 4 to run queue 59 | CPU 0: Dispatched process 2 60 | Time slot 28 61 | CPU 0: Processed 2 has finished 62 | CPU 0: Dispatched process 3 63 | Time slot 29 64 | Time slot 30 65 | CPU 0: Put process 3 to run queue 66 | CPU 0: Dispatched process 1 67 | Time slot 31 68 | Time slot 32 69 | CPU 0: Put process 1 to run queue 70 | CPU 0: Dispatched process 4 71 | Time slot 33 72 | Time slot 34 73 | CPU 0: Put process 4 to run queue 74 | CPU 0: Dispatched process 3 75 | Time slot 35 76 | Time slot 36 77 | CPU 0: Put process 3 to run queue 78 | CPU 0: Dispatched process 1 79 | Time slot 37 80 | Time slot 38 81 | CPU 0: Put process 1 to run queue 82 | CPU 0: Dispatched process 4 83 | Time slot 39 84 | Time slot 40 85 | CPU 0: Put process 4 to run queue 86 | CPU 0: Dispatched process 3 87 | Time slot 41 88 | Time slot 42 89 | CPU 0: Processed 3 has finished 90 | CPU 0: Dispatched process 1 91 | Time slot 43 92 | Time slot 44 93 | CPU 0: Put process 1 to run queue 94 | CPU 0: Dispatched process 4 95 | Time slot 45 96 | CPU 0: Processed 4 has finished 97 | CPU 0: Dispatched process 1 98 | Time slot 46 99 | CPU 0: Processed 1 has finished 100 | CPU 0 stopped 101 | 102 | MEMORY CONTENT: 103 | -------------------------------------------------------------------------------- /src/timer.c: -------------------------------------------------------------------------------- 1 | 2 | #include "timer.h" 3 | #include 4 | #include 5 | 6 | static pthread_t _timer; 7 | 8 | struct timer_id_container_t { 9 | struct timer_id_t id; 10 | struct timer_id_container_t * next; 11 | }; 12 | 13 | static struct timer_id_container_t * dev_list = NULL; 14 | 15 | static uint64_t _time; 16 | 17 | static int timer_started = 0; 18 | static int timer_stop = 0; 19 | 20 | 21 | static void * timer_routine(void * args) { 22 | while (!timer_stop) { 23 | printf("Time slot %3lu\n", current_time()); 24 | int fsh = 0; 25 | int event = 0; 26 | /* Wait for all devices have done the job in current 27 | * time slot */ 28 | struct timer_id_container_t * temp; 29 | for (temp = dev_list; temp != NULL; temp = temp->next) { 30 | pthread_mutex_lock(&temp->id.event_lock); 31 | while (!temp->id.done && !temp->id.fsh) { 32 | pthread_cond_wait( 33 | &temp->id.event_cond, 34 | &temp->id.event_lock 35 | ); 36 | } 37 | if (temp->id.fsh) { 38 | fsh++; 39 | } 40 | event++; 41 | pthread_mutex_unlock(&temp->id.event_lock); 42 | } 43 | 44 | /* Increase the time slot */ 45 | _time++; 46 | 47 | /* Let devices continue their job */ 48 | for (temp = dev_list; temp != NULL; temp = temp->next) { 49 | pthread_mutex_lock(&temp->id.timer_lock); 50 | temp->id.done = 0; 51 | pthread_cond_signal(&temp->id.timer_cond); 52 | pthread_mutex_unlock(&temp->id.timer_lock); 53 | } 54 | if (fsh == event) { 55 | break; 56 | } 57 | } 58 | pthread_exit(args); 59 | } 60 | 61 | void next_slot(struct timer_id_t * timer_id) { 62 | /* Tell to timer that we have done our job in current slot */ 63 | pthread_mutex_lock(&timer_id->event_lock); 64 | timer_id->done = 1; 65 | pthread_cond_signal(&timer_id->event_cond); 66 | pthread_mutex_unlock(&timer_id->event_lock); 67 | 68 | /* Wait for going to next slot */ 69 | pthread_mutex_lock(&timer_id->timer_lock); 70 | while (timer_id->done) { 71 | pthread_cond_wait( 72 | &timer_id->timer_cond, 73 | &timer_id->timer_lock 74 | ); 75 | } 76 | pthread_mutex_unlock(&timer_id->timer_lock); 77 | } 78 | 79 | uint64_t current_time() { 80 | return _time; 81 | } 82 | 83 | void start_timer() { 84 | timer_started = 1; 85 | pthread_create(&_timer, NULL, timer_routine, NULL); 86 | } 87 | 88 | void detach_event(struct timer_id_t * event) { 89 | pthread_mutex_lock(&event->event_lock); 90 | event->fsh = 1; 91 | pthread_cond_signal(&event->event_cond); 92 | pthread_mutex_unlock(&event->event_lock); 93 | } 94 | 95 | struct timer_id_t * attach_event() { 96 | if (timer_started) { 97 | return NULL; 98 | }else{ 99 | struct timer_id_container_t * container = 100 | (struct timer_id_container_t*)malloc( 101 | sizeof(struct timer_id_container_t) 102 | ); 103 | container->id.done = 0; 104 | container->id.fsh = 0; 105 | pthread_cond_init(&container->id.event_cond, NULL); 106 | pthread_mutex_init(&container->id.event_lock, NULL); 107 | pthread_cond_init(&container->id.timer_cond, NULL); 108 | pthread_mutex_init(&container->id.timer_lock, NULL); 109 | if (dev_list == NULL) { 110 | dev_list = container; 111 | dev_list->next = NULL; 112 | }else{ 113 | container->next = dev_list; 114 | dev_list = container; 115 | } 116 | return &(container->id); 117 | } 118 | } 119 | 120 | void stop_timer() { 121 | timer_stop = 1; 122 | pthread_join(_timer, NULL); 123 | while (dev_list != NULL) { 124 | struct timer_id_container_t * temp = dev_list; 125 | dev_list = dev_list->next; 126 | pthread_cond_destroy(&temp->id.event_cond); 127 | pthread_mutex_destroy(&temp->id.event_lock); 128 | pthread_cond_destroy(&temp->id.timer_cond); 129 | pthread_mutex_destroy(&temp->id.timer_lock); 130 | free(temp); 131 | } 132 | } 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /src/os.c: -------------------------------------------------------------------------------- 1 | 2 | #include "cpu.h" 3 | #include "timer.h" 4 | #include "sched.h" 5 | #include "loader.h" 6 | #include "mem.h" 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | static int time_slot; 14 | static int num_cpus; 15 | static int done = 0; 16 | 17 | static struct ld_args{ 18 | char ** path; 19 | unsigned long * start_time; 20 | } ld_processes; 21 | int num_processes; 22 | 23 | struct cpu_args { 24 | struct timer_id_t * timer_id; 25 | int id; 26 | }; 27 | 28 | static void * cpu_routine(void * args) { 29 | struct timer_id_t * timer_id = ((struct cpu_args*)args)->timer_id; 30 | int id = ((struct cpu_args*)args)->id; 31 | /* Check for new process in ready queue */ 32 | int time_left = 0; 33 | struct pcb_t * proc = NULL; 34 | while (1) { 35 | /* Check the status of current process */ 36 | if (proc == NULL) { 37 | /* No process is running, the we load new process from 38 | * ready queue */ 39 | proc = get_proc(); 40 | }else if (proc->pc == proc->code->size) { 41 | /* The porcess has finish it job */ 42 | printf("\tCPU %d: Processed %2d has finished\n", 43 | id ,proc->pid); 44 | free(proc); 45 | proc = get_proc(); 46 | time_left = 0; 47 | }else if (time_left == 0) { 48 | /* The process has done its job in current time slot */ 49 | printf("\tCPU %d: Put process %2d to run queue\n", 50 | id, proc->pid); 51 | put_proc(proc); 52 | proc = get_proc(); 53 | } 54 | 55 | /* Recheck process status after loading new process */ 56 | if (proc == NULL && done) { 57 | /* No process to run, exit */ 58 | printf("\tCPU %d stopped\n", id); 59 | break; 60 | }else if (proc == NULL) { 61 | /* There may be new processes to run in 62 | * next time slots, just skip current slot */ 63 | next_slot(timer_id); 64 | continue; 65 | }else if (time_left == 0) { 66 | printf("\tCPU %d: Dispatched process %2d\n", 67 | id, proc->pid); 68 | time_left = time_slot; 69 | } 70 | 71 | /* Run current process */ 72 | run(proc); 73 | time_left--; 74 | next_slot(timer_id); 75 | } 76 | detach_event(timer_id); 77 | pthread_exit(NULL); 78 | } 79 | 80 | static void * ld_routine(void * args) { 81 | struct timer_id_t * timer_id = (struct timer_id_t*)args; 82 | int i = 0; 83 | while (i < num_processes) { 84 | struct pcb_t * proc = load(ld_processes.path[i]); 85 | while (current_time() < ld_processes.start_time[i]) { 86 | next_slot(timer_id); 87 | } 88 | printf("\tLoaded a process at %s, PID: %d\n", 89 | ld_processes.path[i], proc->pid); 90 | add_proc(proc); 91 | free(ld_processes.path[i]); 92 | i++; 93 | next_slot(timer_id); 94 | } 95 | free(ld_processes.path); 96 | free(ld_processes.start_time); 97 | done = 1; 98 | detach_event(timer_id); 99 | pthread_exit(NULL); 100 | } 101 | 102 | static void read_config(const char * path) { 103 | FILE * file; 104 | if ((file = fopen(path, "r")) == NULL) { 105 | printf("Cannot find configure file at %s\n", path); 106 | exit(1); 107 | } 108 | fscanf(file, "%d %d %d\n", &time_slot, &num_cpus, &num_processes); 109 | ld_processes.path = (char**)malloc(sizeof(char*) * num_processes); 110 | ld_processes.start_time = (unsigned long*) 111 | malloc(sizeof(unsigned long) * num_processes); 112 | int i; 113 | for (i = 0; i < num_processes; i++) { 114 | ld_processes.path[i] = (char*)malloc(sizeof(char) * 100); 115 | ld_processes.path[i][0] = '\0'; 116 | strcat(ld_processes.path[i], "input/proc/"); 117 | char proc[100]; 118 | fscanf(file, "%lu %s\n", &ld_processes.start_time[i], proc); 119 | strcat(ld_processes.path[i], proc); 120 | } 121 | } 122 | 123 | int main(int argc, char * argv[]) { 124 | /* Read config */ 125 | if (argc != 2) { 126 | printf("Usage: os [path to configure file]\n"); 127 | return 1; 128 | } 129 | char path[100]; 130 | path[0] = '\0'; 131 | strcat(path, "input/"); 132 | strcat(path, argv[1]); 133 | read_config(path); 134 | 135 | pthread_t * cpu = (pthread_t*)malloc(num_cpus * sizeof(pthread_t)); 136 | struct cpu_args * args = 137 | (struct cpu_args*)malloc(sizeof(struct cpu_args) * num_cpus); 138 | pthread_t ld; 139 | 140 | /* Init timer */ 141 | int i; 142 | for (i = 0; i < num_cpus; i++) { 143 | args[i].timer_id = attach_event(); 144 | args[i].id = i; 145 | } 146 | struct timer_id_t * ld_event = attach_event(); 147 | start_timer(); 148 | 149 | /* Init scheduler */ 150 | init_scheduler(); 151 | 152 | /* Run CPU and loader */ 153 | pthread_create(&ld, NULL, ld_routine, (void*)ld_event); 154 | for (i = 0; i < num_cpus; i++) { 155 | pthread_create(&cpu[i], NULL, 156 | cpu_routine, (void*)&args[i]); 157 | } 158 | 159 | /* Wait for CPU and loader finishing */ 160 | for (i = 0; i < num_cpus; i++) { 161 | pthread_join(cpu[i], NULL); 162 | } 163 | pthread_join(ld, NULL); 164 | 165 | /* Stop timer */ 166 | stop_timer(); 167 | 168 | printf("\nMEMORY CONTENT: \n"); 169 | dump(); 170 | 171 | return 0; 172 | 173 | } 174 | 175 | 176 | 177 | -------------------------------------------------------------------------------- /output/os_1: -------------------------------------------------------------------------------- 1 | Time slot 0 2 | Loaded a process at input/proc/p0, PID: 1 3 | Time slot 1 4 | CPU 2: Dispatched process 1 5 | Time slot 2 6 | Loaded a process at input/proc/s3, PID: 2 7 | CPU 2: Put process 1 to run queue 8 | Time slot 3 9 | CPU 2: Dispatched process 2 10 | CPU 1: Dispatched process 1 11 | Loaded a process at input/proc/m1, PID: 3 12 | Time slot 4 13 | CPU 3: Dispatched process 3 14 | CPU 2: Put process 2 to run queue 15 | CPU 2: Dispatched process 2 16 | CPU 1: Put process 1 to run queue 17 | CPU 1: Dispatched process 1 18 | Time slot 5 19 | Loaded a process at input/proc/s2, PID: 4 20 | CPU 3: Put process 3 to run queue 21 | CPU 3: Dispatched process 4 22 | Time slot 6 23 | CPU 0: Dispatched process 3 24 | Time slot 7 25 | CPU 1: Put process 1 to run queue 26 | CPU 1: Dispatched process 1 27 | CPU 2: Put process 2 to run queue 28 | CPU 2: Dispatched process 2 29 | Loaded a process at input/proc/m0, PID: 5 30 | CPU 3: Put process 4 to run queue 31 | CPU 3: Dispatched process 5 32 | Time slot 8 33 | CPU 0: Put process 3 to run queue 34 | CPU 0: Dispatched process 4 35 | Loaded a process at input/proc/p1, PID: 6 36 | Time slot 9 37 | CPU 1: Put process 1 to run queue 38 | CPU 1: Dispatched process 6 39 | CPU 2: Put process 2 to run queue 40 | CPU 2: Dispatched process 3 41 | CPU 3: Put process 5 to run queue 42 | Time slot 10 43 | CPU 3: Dispatched process 2 44 | CPU 0: Put process 4 to run queue 45 | CPU 0: Dispatched process 5 46 | Loaded a process at input/proc/s0, PID: 7 47 | Time slot 11 48 | CPU 1: Put process 6 to run queue 49 | CPU 1: Dispatched process 7 50 | CPU 2: Put process 3 to run queue 51 | CPU 2: Dispatched process 1 52 | CPU 3: Put process 2 to run queue 53 | Time slot 12 54 | CPU 3: Dispatched process 4 55 | CPU 0: Put process 5 to run queue 56 | CPU 0: Dispatched process 2 57 | Time slot 13 58 | CPU 1: Put process 7 to run queue 59 | CPU 1: Dispatched process 6 60 | CPU 2: Processed 1 has finished 61 | CPU 2: Dispatched process 3 62 | CPU 3: Put process 4 to run queue 63 | Time slot 14 64 | CPU 3: Dispatched process 4 65 | CPU 0: Put process 2 to run queue 66 | CPU 0: Dispatched process 7 67 | Time slot 15 68 | CPU 2: Processed 3 has finished 69 | CPU 2: Dispatched process 5 70 | CPU 1: Put process 6 to run queue 71 | CPU 1: Dispatched process 2 72 | Loaded a process at input/proc/s1, PID: 8 73 | Time slot 16 74 | CPU 1: Processed 2 has finished 75 | CPU 0: Put process 7 to run queue 76 | CPU 1: Dispatched process 8 77 | CPU 0: Dispatched process 6 78 | CPU 3: Put process 4 to run queue 79 | CPU 3: Dispatched process 4 80 | CPU 2: Put process 5 to run queue 81 | CPU 2: Dispatched process 7 82 | Time slot 17 83 | CPU 3: Put process 4 to run queue 84 | Time slot 18 85 | CPU 0: Put process 6 to run queue 86 | CPU 1: Put process 8 to run queue 87 | CPU 1: Dispatched process 5 88 | CPU 3: Dispatched process 4 89 | CPU 0: Dispatched process 8 90 | CPU 2: Put process 7 to run queue 91 | CPU 2: Dispatched process 6 92 | Time slot 19 93 | CPU 1: Processed 5 has finished 94 | CPU 1: Dispatched process 7 95 | CPU 3: Processed 4 has finished 96 | CPU 3 stopped 97 | Time slot 20 98 | CPU 0: Put process 8 to run queue 99 | CPU 0: Dispatched process 8 100 | Time slot 21 101 | CPU 1: Put process 7 to run queue 102 | CPU 1: Dispatched process 7 103 | CPU 2: Put process 6 to run queue 104 | CPU 2: Dispatched process 6 105 | Time slot 22 106 | CPU 0: Put process 8 to run queue 107 | CPU 0: Dispatched process 8 108 | Time slot 23 109 | CPU 2: Processed 6 has finished 110 | CPU 2 stopped 111 | CPU 1: Put process 7 to run queue 112 | CPU 1: Dispatched process 7 113 | CPU 0: Processed 8 has finished 114 | CPU 0 stopped 115 | Time slot 24 116 | Time slot 25 117 | CPU 1: Put process 7 to run queue 118 | CPU 1: Dispatched process 7 119 | Time slot 26 120 | Time slot 27 121 | CPU 1: Put process 7 to run queue 122 | CPU 1: Dispatched process 7 123 | Time slot 28 124 | CPU 1: Processed 7 has finished 125 | CPU 1 stopped 126 | 127 | MEMORY CONTENT: 128 | 000: 00000-003ff - PID: 05 (idx 000, nxt: 001) 129 | 003e8: 15 130 | 001: 00400-007ff - PID: 05 (idx 001, nxt: -01) 131 | 002: 00800-00bff - PID: 05 (idx 000, nxt: 003) 132 | 003: 00c00-00fff - PID: 05 (idx 001, nxt: 004) 133 | 004: 01000-013ff - PID: 05 (idx 002, nxt: 005) 134 | 005: 01400-017ff - PID: 05 (idx 003, nxt: 006) 135 | 006: 01800-01bff - PID: 05 (idx 004, nxt: -01) 136 | 011: 02c00-02fff - PID: 06 (idx 000, nxt: 012) 137 | 012: 03000-033ff - PID: 06 (idx 001, nxt: 013) 138 | 013: 03400-037ff - PID: 06 (idx 002, nxt: 014) 139 | 014: 03800-03bff - PID: 06 (idx 003, nxt: -01) 140 | 021: 05400-057ff - PID: 01 (idx 000, nxt: -01) 141 | 05414: 64 142 | 024: 06000-063ff - PID: 05 (idx 000, nxt: 025) 143 | 06014: 66 144 | 025: 06400-067ff - PID: 05 (idx 001, nxt: -01) 145 | 031: 07c00-07fff - PID: 06 (idx 000, nxt: 032) 146 | 032: 08000-083ff - PID: 06 (idx 001, nxt: 033) 147 | 033: 08400-087ff - PID: 06 (idx 002, nxt: 034) 148 | 085e7: 0a 149 | 034: 08800-08bff - PID: 06 (idx 003, nxt: 035) 150 | 035: 08c00-08fff - PID: 06 (idx 004, nxt: -01) 151 | -------------------------------------------------------------------------------- /src/mem.c: -------------------------------------------------------------------------------- 1 | #include "mem.h" 2 | #include "stdlib.h" 3 | #include "string.h" 4 | #include 5 | #include 6 | 7 | static BYTE _ram[RAM_SIZE]; 8 | 9 | static struct { 10 | uint32_t proc; // ID of process currently uses this page 11 | int index; // Index of the page in the list of pages allocated 12 | // to the process. 13 | int next; // The next page in the list. -1 if it is the last 14 | // page. 15 | } _mem_stat [NUM_PAGES]; 16 | 17 | static pthread_mutex_t mem_lock; 18 | 19 | void init_mem(void) { 20 | memset(_mem_stat, 0, sizeof(*_mem_stat) * NUM_PAGES); 21 | memset(_ram, 0, sizeof(BYTE) * RAM_SIZE); 22 | pthread_mutex_init(&mem_lock, NULL); 23 | } 24 | 25 | /* get offset of the virtual address */ 26 | static addr_t get_offset(addr_t addr) { 27 | return addr & ~((~0U) << OFFSET_LEN); 28 | } 29 | 30 | /* get the first layer index */ 31 | static addr_t get_first_lv(addr_t addr) { 32 | return addr >> (OFFSET_LEN + PAGE_LEN); 33 | } 34 | 35 | /* get the second layer index */ 36 | static addr_t get_second_lv(addr_t addr) { 37 | return (addr >> OFFSET_LEN) - (get_first_lv(addr) << PAGE_LEN); 38 | } 39 | 40 | /* Search for page table table from the a segment table */ 41 | static struct page_table_t * get_page_table( 42 | addr_t index, // Segment level index 43 | struct seg_table_t * seg_table) { // first level table 44 | 45 | /* 46 | * TODO: Given the Segment index [index], you must go through each 47 | * row of the segment table [seg_table] and check if the v_index 48 | * field of the row is equal to the index 49 | * 50 | * */ 51 | // pthread_mutex_lock(&mem_lock); 52 | int i; 53 | for (i = 0; i < seg_table->size; i++) { 54 | // Enter your code here 55 | if (seg_table->table[i].v_index == index) 56 | return seg_table->table[i].pages; 57 | } 58 | // printf("Page table got\n"); 59 | // pthread_mutex_unlock(&mem_lock); 60 | return NULL; 61 | 62 | } 63 | 64 | /* Translate virtual address to physical address. If [virtual_addr] is valid, 65 | * return 1 and write its physical counterpart to [physical_addr]. 66 | * Otherwise, return 0 */ 67 | static int translate( 68 | addr_t virtual_addr, // Given virtual address 69 | addr_t * physical_addr, // Physical address to be returned 70 | struct pcb_t * proc) { // Process uses given virtual address 71 | 72 | /* Offset of the virtual address */ 73 | addr_t offset = get_offset(virtual_addr); 74 | /* The first layer index */ 75 | addr_t first_lv = get_first_lv(virtual_addr); 76 | /* The second layer index */ 77 | addr_t second_lv = get_second_lv(virtual_addr); 78 | 79 | /* Search in the first level */ 80 | struct page_table_t * page_table = NULL; 81 | page_table = get_page_table(first_lv, proc->seg_table); 82 | if (page_table == NULL) { 83 | return 0; 84 | } 85 | 86 | int i; 87 | for (i = 0; i < page_table->size; i++) { 88 | if (page_table->table[i].v_index == second_lv) { 89 | /* TODO: Concatenate the offset of the virtual addess 90 | * to [p_index] field of page_table->table[i] to 91 | * produce the correct physical address and save it to 92 | * [*physical_addr] */ 93 | *physical_addr = (page_table->table[i].p_index << OFFSET_LEN) | offset; 94 | // printf("%05x | %05x = %05x\n", page_table->table[i].p_index << OFFSET_LEN, offset, *physical_addr); 95 | return 1; 96 | } 97 | } 98 | return 0; 99 | } 100 | 101 | addr_t alloc_mem(uint32_t size, struct pcb_t * proc) { 102 | pthread_mutex_lock(&mem_lock); 103 | addr_t ret_mem = 0; 104 | /* TODO: Allocate [size] byte in the memory for the 105 | * process [proc] and save the address of the first 106 | * byte in the allocated memory region to [ret_mem]. 107 | * */ 108 | // Number of pages we will use 109 | uint32_t num_pages = (size % PAGE_SIZE) ? size / PAGE_SIZE + 1: 110 | size / PAGE_SIZE; 111 | 112 | int mem_avail = 0; // We could allocate new memory region or not? 113 | 114 | /* TODO: First we must check if the amount of free memory in 115 | * Virtual Memory Space (Virtual Memory Engine) and Physical Memory Space 116 | * is large enough to represent the amount of required 117 | * memory. If so, set 1 to [mem_avail]. 118 | * Hint: check [proc] bit in each page of _mem_stat 119 | * to know whether this page has been used by a process. 120 | * For virtual memory space, check bp (break pointer). 121 | * */ 122 | 123 | int available_page = 0; 124 | int i; 125 | for (i = 0; i= num_pages) { 130 | if ((1 << ADDRESS_SIZE) - size >= proc->bp){ 131 | mem_avail = 1; 132 | } 133 | break; 134 | } 135 | } 136 | 137 | if (mem_avail) { 138 | /* We could allocate new memory region to the process */ 139 | ret_mem = proc->bp; 140 | proc->bp += num_pages * PAGE_SIZE; 141 | /* TODO: Update status of physical pages which will be allocated 142 | * to [proc] in _mem_stat. Tasks to do: 143 | * - Update [proc], [index], and [next] field 144 | * - Add entries to segment table page tables of [proc] 145 | * to ensure accesses to allocated memory slot is 146 | * valid. */ 147 | 148 | // TODO: Update [proc], [index], and [next] field 149 | 150 | int number_of_page_left = num_pages; 151 | int prev_mem_stat = -1; 152 | int i; 153 | 154 | // Array of physical index of _mem_stat 155 | int list_p_index[num_pages]; 156 | 157 | for (i=0; ipid; 165 | _mem_stat[i].index = num_pages - number_of_page_left; 166 | prev_mem_stat = i; 167 | 168 | // Update physical index 169 | list_p_index[num_pages - number_of_page_left] = i; 170 | 171 | number_of_page_left--; 172 | 173 | // TODO: Assign -1 to the [next] of tha last _mem_stat 174 | if (number_of_page_left == 0){ 175 | _mem_stat[i].next = -1; 176 | break; 177 | } 178 | } 179 | } 180 | 181 | // TODO: Add entries to segment table page tables of [proc] 182 | // to ensure accesses to allocated memory slot is 183 | // valid. 184 | 185 | addr_t current_virtual_addr = ret_mem; 186 | 187 | for (size_t i=0; iseg_table->size; j++){ 194 | if (proc->seg_table->table[j].v_index == first_lv_addr){ 195 | found = 1; 196 | break; 197 | } 198 | } 199 | 200 | if (found == 0){ 201 | proc->seg_table->table[j].v_index = first_lv_addr; 202 | proc->seg_table->table[j].pages = (struct page_table_t *) malloc (sizeof(struct page_table_t)); 203 | proc->seg_table->table[j].pages->size = 0; 204 | proc->seg_table->size++; 205 | } 206 | 207 | proc->seg_table->table[j].pages->table[proc->seg_table->table[j].pages->size].v_index = second_lv_addr; 208 | proc->seg_table->table[j].pages->table[proc->seg_table->table[j].pages->size].p_index = list_p_index[i]; 209 | proc->seg_table->table[j].pages->size++; 210 | current_virtual_addr += PAGE_SIZE; 211 | } 212 | 213 | } 214 | pthread_mutex_unlock(&mem_lock); 215 | return ret_mem; 216 | } 217 | 218 | int free_mem(addr_t address, struct pcb_t * proc) { 219 | /*TODO: Release memory region allocated by [proc]. The first byte of 220 | * this region is indicated by [address]. Task to do: 221 | * - Set flag [proc] of physical page use by the memory block 222 | * back to zero to indicate that it is free. 223 | * - Remove unused entries in segment table and page tables of 224 | * the process [proc]. 225 | * - Remember to use lock to protect the memory from other 226 | * processes. */ 227 | 228 | int found = 0; 229 | int number_of_pages = 0; 230 | 231 | for (size_t i=0; iseg_table->size; i++){ 232 | if (proc->seg_table->table[i].v_index == get_first_lv(address)){ 233 | found = 1; 234 | } 235 | } 236 | 237 | if (found == 1){ 238 | addr_t physical_addr; 239 | translate(address, &physical_addr, proc); 240 | addr_t _p_index = physical_addr >> OFFSET_LEN; 241 | while(1){ 242 | pthread_mutex_lock(&mem_lock); 243 | _mem_stat[_p_index].proc = 0; 244 | number_of_pages++; 245 | _p_index = _mem_stat[_p_index].next; 246 | pthread_mutex_unlock(&mem_lock); 247 | if (_p_index == -1){ 248 | break; 249 | } 250 | } 251 | addr_t current_virtual_address = address; 252 | for (size_t j=0; jseg_table->size; seg_table_ind++){ 258 | if (proc->seg_table->table[seg_table_ind].v_index == first_lv_addr){ 259 | break; 260 | } 261 | } 262 | 263 | size_t page_table_ind; 264 | for (page_table_ind=0; 265 | page_table_indseg_table->table[seg_table_ind].pages->size; 266 | page_table_ind++){ 267 | if(proc->seg_table->table[seg_table_ind].pages->table[page_table_ind].v_index 268 | == second_lv_addr){ 269 | break; 270 | } 271 | } 272 | 273 | 274 | for (size_t j=page_table_ind; 275 | jseg_table->table[seg_table_ind].pages->size-1; 276 | j++){ 277 | proc->seg_table->table[seg_table_ind].pages->table[j] = 278 | proc->seg_table->table[seg_table_ind].pages->table[j+1]; 279 | } 280 | 281 | proc->seg_table->table[seg_table_ind].pages->size--; 282 | 283 | // TODO: If the page_table is empty, free it 284 | if (proc->seg_table->table[seg_table_ind].pages->size == 0){ 285 | free(proc->seg_table->table[seg_table_ind].pages); 286 | for (size_t k=seg_table_ind; kseg_table->size-1; k++){ 287 | proc->seg_table->table[k] = proc->seg_table->table[k+1]; 288 | } 289 | proc->seg_table->size--; 290 | } 291 | current_virtual_address += PAGE_SIZE; 292 | } 293 | } 294 | 295 | return 0; 296 | } 297 | 298 | int read_mem(addr_t address, struct pcb_t * proc, BYTE * data) { 299 | addr_t physical_addr; 300 | if (translate(address, &physical_addr, proc)) { 301 | pthread_mutex_lock(&mem_lock); 302 | *data = _ram[physical_addr]; 303 | pthread_mutex_unlock(&mem_lock); 304 | return 0; 305 | }else{ 306 | return 1; 307 | } 308 | } 309 | 310 | int write_mem(addr_t address, struct pcb_t * proc, BYTE data) { 311 | addr_t physical_addr; 312 | if (translate(address, &physical_addr, proc)) { 313 | pthread_mutex_lock(&mem_lock); 314 | _ram[physical_addr] = data; 315 | // printf("_ram[%05x] = %02x\n", physical_addr, data); 316 | pthread_mutex_unlock(&mem_lock); 317 | // printf("--------------------------------------------------\n"); 318 | // printf("Proc %d write %02x into address %05x\n", proc->pid, data, physical_addr); 319 | // printf("--------------------------------------------------\n"); 320 | return 0; 321 | }else{ 322 | return 1; 323 | } 324 | } 325 | 326 | void dump(void) { 327 | pthread_mutex_lock(&mem_lock); 328 | int i; 329 | for (i = 0; i < NUM_PAGES; i++) { 330 | if (_mem_stat[i].proc != 0) { 331 | printf("%03d: ", i); 332 | printf("%05x-%05x - PID: %02d (idx %03d, nxt: %03d)\n", 333 | i << OFFSET_LEN, 334 | ((i + 1) << OFFSET_LEN) - 1, 335 | _mem_stat[i].proc, 336 | _mem_stat[i].index, 337 | _mem_stat[i].next 338 | ); 339 | int j; 340 | for ( j = i << OFFSET_LEN; 341 | j < ((i+1) << OFFSET_LEN) - 1; 342 | j++) { 343 | 344 | if (_ram[j] != 0) { 345 | printf("\t%05x: %02x\n", j, _ram[j]); 346 | } 347 | 348 | } 349 | } 350 | } 351 | pthread_mutex_unlock(&mem_lock); 352 | } --------------------------------------------------------------------------------