265 lines
6.6 KiB
C++
265 lines
6.6 KiB
C++
#include <stdio.h>
|
|
#include <malloc.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
int preprocess_task_size(int);
|
|
int find_free_block_ff(int, struct Block**);
|
|
int find_free_block_bf(int, struct Block**);
|
|
int queue_push(int);
|
|
int queue_pop();
|
|
int get_command(FILE*);
|
|
int fork(int);
|
|
void kill(int);
|
|
int run(char*);
|
|
void init();
|
|
void clean_stdin();
|
|
|
|
#define MAX_NUM_TASKS 128
|
|
#define MAX_NUM_WAIT 512
|
|
|
|
struct Block {
|
|
int free;
|
|
int start;
|
|
int size;
|
|
struct Block* next, *last;
|
|
};
|
|
|
|
struct Task {
|
|
int start;
|
|
int size;
|
|
int pid;
|
|
struct Block* block;
|
|
};
|
|
|
|
int sys_size = 384 << 10, usr_size = 128 << 10;
|
|
struct Block* sys_space, *usr_space;
|
|
struct Task* tasks;
|
|
int last_pid = -1;
|
|
int match_method = -1;
|
|
int wait_queue[MAX_NUM_WAIT];
|
|
int wait_q_begin = 0, wait_q_end = 0;
|
|
|
|
|
|
int main() {
|
|
init();
|
|
while (get_command(stdin) >= 0);
|
|
return 0;
|
|
}
|
|
|
|
int get_command(FILE* stream) {
|
|
printf("user> ");
|
|
char input_str[128] = {0};
|
|
fgets(input_str, 127, stream);
|
|
if (stream != stdin) printf("%s", input_str);
|
|
|
|
int split_index = 0;
|
|
for (int i = 0; i < 127; i++) {
|
|
if (input_str[i] == '\0') break;
|
|
if (input_str[i] == ' ') {
|
|
input_str[i] = '\0';
|
|
split_index = i;
|
|
}
|
|
if (input_str[i] == '\n') {
|
|
input_str[i] = '\0';
|
|
break;
|
|
}
|
|
}
|
|
|
|
char* command = input_str, * arguments = input_str + split_index + 1;
|
|
|
|
if (!strcmp(command, "exit")) {
|
|
return -1;
|
|
}
|
|
else if (strcmp(command, "fork") == 0) {
|
|
int input_size = atoi(arguments);
|
|
if (input_size <= 0) {
|
|
printf("Bad input size. Input number must larger than ZERO.\n");
|
|
return 0;
|
|
}
|
|
int pid = fork(input_size);
|
|
return 1;
|
|
}
|
|
else if (!strcmp(command, "kill")) {
|
|
int input_pid = atoi(arguments);
|
|
if (input_pid < 0) {
|
|
printf("Bad input PID. Input number must not smaller than ZERO.\n");
|
|
return 0;
|
|
}
|
|
kill(input_pid);
|
|
return 1;
|
|
}
|
|
else if (!strcmp(input_str, "print")) {
|
|
printf("print.\n");
|
|
return 1;
|
|
}
|
|
else if (!strcmp(input_str, "run")) {
|
|
int result = run(arguments);
|
|
return result;
|
|
}
|
|
else if (!strcmp(input_str, ""));
|
|
else {
|
|
printf("Command not found.\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void kill(int pid) {
|
|
return;
|
|
}
|
|
|
|
void init() {
|
|
sys_space = (struct Block*)malloc(sizeof(struct Block));
|
|
sys_space->free = 1;
|
|
sys_space->start = 0;
|
|
sys_space->size = sys_size;
|
|
sys_space->next = NULL;
|
|
sys_space->last = NULL;
|
|
|
|
usr_space = (struct Block*)malloc(sizeof(struct Block));
|
|
usr_space->free = 1;
|
|
usr_space->start = sys_size;
|
|
usr_space->size = usr_size;
|
|
usr_space->next = NULL;
|
|
usr_space->last = NULL;
|
|
|
|
tasks = (struct Task*)malloc(MAX_NUM_TASKS * sizeof(struct Task));
|
|
for (int i = 0; i < MAX_NUM_TASKS; i++) tasks[i].pid = -1;
|
|
|
|
ask_match_method:
|
|
printf("Choose a matching method:\n 1. First Fit\n 2. Best Fit\n");
|
|
scanf("%d", &match_method);
|
|
clean_stdin();
|
|
if (match_method != 1 && match_method != 2) {
|
|
printf("Bad input. Choose again.\n");
|
|
goto ask_match_method;
|
|
}
|
|
}
|
|
|
|
int fork(int size) {
|
|
int pid;
|
|
int task_index = -1;
|
|
repeat:
|
|
last_pid++;
|
|
if (last_pid < 0) last_pid = 0;
|
|
pid = last_pid;
|
|
for (int i = 0; i < MAX_NUM_TASKS; i++) {
|
|
if (tasks[i].pid >= 0) continue;
|
|
if (tasks[i].pid == pid) goto repeat;
|
|
task_index = i;
|
|
break;
|
|
}
|
|
if (task_index == -1) return -1;
|
|
|
|
size = preprocess_task_size(size);
|
|
tasks[task_index].size = size;
|
|
int start_loc = -1;
|
|
if (match_method == 1) start_loc = find_free_block_ff(size, &tasks[task_index].block);
|
|
else start_loc = find_free_block_bf(size, &tasks[task_index].block);
|
|
if (start_loc >= 0) {
|
|
tasks[task_index].start = start_loc;
|
|
tasks[task_index].pid = pid;
|
|
tasks[task_index].size = size;
|
|
printf("Fork succeed. PID is %d . Block size is %d bit.\n", pid, size);
|
|
return pid;
|
|
}
|
|
printf("Fork failed. Out of Memory. Trying to push into wait list.\n");
|
|
int tmp = queue_push(size);
|
|
if (tmp < 0) printf("Error: Push into wait list failed.\n");
|
|
else printf("Push into wait list succeed.\n");
|
|
return -1;
|
|
}
|
|
|
|
int find_free_block_ff(int size, struct Block** block_p) {
|
|
struct Block* now = usr_space;
|
|
while (1) {
|
|
if (now == NULL) return -1;
|
|
if (now->free != 0 && now->size >= size) break;
|
|
now = now->next;
|
|
}
|
|
*block_p = now;
|
|
if (now->size == size) return now->start;
|
|
struct Block* free_space = (struct Block*)malloc(sizeof(struct Block));
|
|
free_space->free = 1;
|
|
free_space->last = now;
|
|
free_space->next = now->next;
|
|
free_space->size = now->size - size;
|
|
free_space->start = now->start + size;
|
|
|
|
now->free = 0;
|
|
now->next = free_space;
|
|
now->size = size;
|
|
return now->start;
|
|
}
|
|
|
|
int find_free_block_bf(int size, struct Block** block_p) {
|
|
struct Block* now = usr_space, *best_block;
|
|
int best_size = 0xffffff;
|
|
while (1) {
|
|
if (now == NULL) break;
|
|
if (now->free != 0 && now->size >= size && best_size >= now->size) {
|
|
best_block = now;
|
|
best_size = now->size;
|
|
}
|
|
now = now->next;
|
|
}
|
|
if (best_size == 0xffffff) return -1;
|
|
*block_p = best_block;
|
|
if (best_block->size == size) return best_block->start;
|
|
struct Block* free_space = (struct Block*)malloc(sizeof(struct Block));
|
|
free_space->free = 1;
|
|
free_space->last = best_block;
|
|
free_space->next = best_block->next;
|
|
free_space->size = best_block->size - size;
|
|
free_space->start = best_block->start + size;
|
|
|
|
best_block->free = 0;
|
|
best_block->next = free_space;
|
|
best_block->size = size;
|
|
return best_block->start;
|
|
}
|
|
|
|
int run(char* path) {
|
|
FILE* f = NULL;
|
|
f = fopen(path, "r+");
|
|
if (f == NULL) {
|
|
printf("Error: Invalid file path.\n");
|
|
return 0;
|
|
}
|
|
int result = 0;
|
|
while(!feof(f) && result != -1) result = get_command(f);
|
|
fclose(f);
|
|
printf("%d\n", result);
|
|
return result;
|
|
}
|
|
|
|
int preprocess_task_size(int size) {
|
|
size = size & 0x400;
|
|
size = size + 0x400;
|
|
return size;
|
|
}
|
|
|
|
int queue_push(int size) {
|
|
if ((wait_q_end + 1) % MAX_NUM_WAIT == wait_q_begin) {
|
|
printf("Wait list full.\n");
|
|
return -1;
|
|
}
|
|
wait_queue[wait_q_end++] = size;
|
|
wait_q_end %= MAX_NUM_WAIT;
|
|
return 1;
|
|
}
|
|
|
|
int queue_pop() {
|
|
if (wait_q_begin == wait_q_end) {
|
|
printf("Wait list empty.\n");
|
|
return -1;
|
|
}
|
|
return wait_queue[wait_q_begin++];
|
|
}
|
|
|
|
void clean_stdin() {
|
|
int c;
|
|
do {
|
|
c = getchar();
|
|
} while (c != '\n' && c != EOF);
|
|
} |