Operating_Systems/Lab/Lab4/source/21281280-柯劲帆-第4次实验.md
2024-09-05 13:31:02 +08:00

24 KiB
Raw Blame History

北京交通大学实验报告

课程名称:操作系统
实验题目:动态可重定位分区内存管理模拟设计与实现
学号:21281280
姓名:柯劲帆
班级:物联网2101班
指导老师:何永忠
报告日期:2023年11月26日

目录

[TOC]


1. 开发运行环境和工具

操作系统 Linux内核版本 处理器 GCC版本
Deepin 20.9 5.18.17-amd64-desktop-hwe Intel(R) Core(TM) i3-2330M CPU @ 2.20GHz gcc (Uos 8.3.0.3-3+rebuild) 8.3.0
  • 其他工具
    • 编辑VSCode
    • 编译和运行Terminal

2. 实验过程、分析和结论

2.1. 初始化

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>

#define MAX_NUM_TASKS 128

struct Block {
    int start;
    int size;
    int pid;
    struct Block* next, * last;
};

struct Task {
    int start;
    int size;
    int pid;
    struct Block* block;
};

struct Request {
    int size;
    struct Request* next;
};


int preprocess_task_size(int);
int find_free_block_ff(int, struct Block**);
int find_free_block_bf(int, struct Block**);
void queue_push(int);
int queue_pop();
int get_command(FILE*);
int fork_process(int);
void kill_process(int);
int run(char*);
void init();
void clean_stdin();
void execute_wait_list();
void print();

int sys_size = 128 << 20, usr_size = 384 << 20;
struct Block* sys_space = NULL, * usr_space = NULL;
struct Task* tasks = NULL;
struct Request* waitlist_begin = NULL, * waitlist_end = NULL;
int waitlist_size = 0;
int last_pid = -1;
int match_method = -1;


int main() {
    init();
    while (get_command(stdin) >= 0);
    return 0;
}

void init() {
    sys_space = (struct Block*)malloc(sizeof(struct Block));
    sys_space->pid = -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->pid = -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");
    printf("choose> ");
    scanf("%d", &match_method);
    clean_stdin();
    if (match_method != 1 && match_method != 2) {
        printf("Bad input. Choose again.\n");
        goto ask_match_method;
    }

    waitlist_begin = (struct Request*)malloc(sizeof(struct Request));
    waitlist_end = waitlist_begin;
    waitlist_begin->next = NULL;
    waitlist_begin->size = -1;
}

2.2. 申请内存分配操作

int fork_process(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 && tasks[i].pid == pid) goto repeat;
    }
    for (int i = 0; i < MAX_NUM_TASKS; i++) {
        if (tasks[i].pid >= 0) continue;
        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;
        tasks[task_index].block->pid = pid;
        printf("Fork succeed. PID is %d . Block size is %d bits.\n", pid, size);
        return pid;
    }
    printf("Fork failed. Out of Memory. Trying to push into wait list.\n");
    queue_push(size);
    return -1;
}

int find_free_block_ff(int size, struct Block** block_p) {
    struct Block* now = usr_space;
    int cnt = 1;
    while (1) {
        if (now == NULL) return -1;
        if (now->pid < 0 && now->size >= size) break;
        now = now->next;
        cnt++;
    }
    printf("Use %d times to find free block.\n", cnt);
    *block_p = now;
    if (now->size == size) return now->start;
    struct Block* free_space = (struct Block*)malloc(sizeof(struct Block));
    free_space->pid = -1;
    free_space->last = now;
    free_space->next = now->next;
    free_space->size = now->size - size;
    free_space->start = now->start + size;

    now->pid = -2;
    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 = 0x7fffffff;
    int cnt = 1;
    while (1) {
        if (now == NULL) break;
        if (now->pid < 0 && now->size >= size && best_size >= now->size) {
            best_block = now;
            best_size = now->size;
        }
        now = now->next;
        cnt++;
    }
    if (best_size == 0x7fffffff) return -1;
    printf("Use %d times to find free block.\n", cnt);
    *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->pid = -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->pid = -2;
    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);
    return result;
}

int preprocess_task_size(int size) {
    int lower = size & 0x3ff;
    if (lower == 0) return size;
    int upper = size - lower;
    size = upper + 0x400;
    return size;
}

void queue_push(int size) {
    waitlist_begin->next = (struct Request*)malloc(sizeof(struct Request));
    waitlist_begin = waitlist_begin->next;
    waitlist_begin->next = NULL;
    waitlist_begin->size = size;
    waitlist_size++;
}

int queue_pop() {
    if (!waitlist_size) {
        printf("Wait list empty.\n");
        return -1;
    }
    struct Request* tmp = waitlist_end;
    waitlist_end = waitlist_end->next;
    free(tmp);
    waitlist_size--;
    return waitlist_end->size;
}

2.3. 回收

void kill_process(int pid) {
    struct Block* block = NULL;
    for (int i = 0; i < MAX_NUM_TASKS; i++) {
        if (tasks[i].pid != pid) continue;

        block = tasks[i].block;
        break;
    }
    if (block == NULL) {
        printf("Error: PID dosen't exist.\n");
        return;
    }
    if (block->last && block->last->pid < 0 && block->next && block->next->pid < 0) {
        struct Block* free_block = block->last;
        free_block->next = block->next->next;
        free_block->size += block->size + block->next->size;
        if (free_block->next) free_block->next->last = free_block;
        free(block->next);
        free(block);
    }
    else if (block->last && block->last->pid < 0) {
        struct Block* free_block = block->last;
        free_block->next = block->next;
        free_block->size += block->size;
        if (free_block->next) free_block->next->last = free_block;
        free(block);
    }
    else if (block->next && block->next->pid < 0) {
        struct Block* free_block = block;
        free_block->size += block->next->size;
        free_block->next = block->next->next;
        free_block->pid = -1;
        if (free_block->next) free_block->next->last = free_block;
        free(block->next);
    }
    else {
        block->pid = -1;
    }

    execute_wait_list();

    return;
}

void execute_wait_list() {
    int size = -1, loop_num = waitlist_size;
    for (int i = 0; i < loop_num; i++) {
        size = queue_pop();
        fork_process(size);
    }
}

2.4. 其他代码

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;
        }
        else if (input_size > usr_size) {
            printf("Bad input size. Input number must smaller than %d bits.\n", usr_size);
            return 0;
        }
        int pid = fork_process(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_process(input_pid);
        return 1;
    }
    else if (!strcmp(input_str, "print")) {
        print();
        return 1;
    }
    else if (!strcmp(input_str, "run")) {
        int result = run(arguments);
        return result;
    }
    else if (input_str[0] == '\0');
    else {
        printf("Command not found.\n");
        return 0;
    }
}

void print() {
    char str[2][13] = { {"        True"}, {"       False"} };
    char* s;
    struct Block* p = sys_space;
    printf("+----------------------------------------------------------------+\n");
    printf("|                          System Space                          |\n");
    printf("+------------+------------+------------+------------+------------+\n");
    printf("|    Free    |   Begin    |    Size    |    End     |     PID    |\n");
    printf("+------------+------------+------------+------------+------------+\n");
    while (p != NULL) {
        s = p->pid < 0 ? str[0] : str[1];
        printf("|%s|%12d|%12d|%12d|%12d|\n", s, p->start, p->size, p->start + p->size - 1, p->pid);
        printf("+------------+------------+------------+------------+------------+\n");
        p = p->next;
    }
    printf("+----------------------------------------------------------------+\n\n");

    p = usr_space;
    printf("+----------------------------------------------------------------+\n");
    printf("|                           User Space                           |\n");
    printf("+------------+------------+------------+------------+------------+\n");
    printf("|    Free    |   Begin    |    Size    |    End     |     PID    |\n");
    printf("+------------+------------+------------+------------+------------+\n");
    while (p != NULL) {
        s = p->pid < 0 ? str[0] : str[1];
        printf("|%s|%12d|%12d|%12d|%12d|\n", s, p->start, p->size, p->start + p->size - 1, p->pid);
        printf("+------------+------------+------------+------------+------------+\n");
        p = p->next;
    }
    printf("+----------------------------------------------------------------+\n");
}

void clean_stdin() {
    int c;
    do {
        c = getchar();
    } while (c != '\n' && c != EOF);
}

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);
    return result;
}

附录

#include <stdio.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>

#define MAX_NUM_TASKS 128

struct Block {
    int start;
    int size;
    int pid;
    struct Block* next, * last;
};

struct Task {
    int start;
    int size;
    int pid;
    struct Block* block;
};

struct Request {
    int size;
    struct Request* next;
};


int preprocess_task_size(int);
int find_free_block_ff(int, struct Block**);
int find_free_block_bf(int, struct Block**);
void queue_push(int);
int queue_pop();
int get_command(FILE*);
int fork_process(int);
void kill_process(int);
int run(char*);
void init();
void clean_stdin();
void execute_wait_list();
void print();

int sys_size = 128 << 20, usr_size = 384 << 20;
struct Block* sys_space = NULL, * usr_space = NULL;
struct Task* tasks = NULL;
struct Request* waitlist_begin = NULL, * waitlist_end = NULL;
int waitlist_size = 0;
int last_pid = -1;
int match_method = -1;


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;
        }
        else if (input_size > usr_size) {
            printf("Bad input size. Input number must smaller than %d bits.\n", usr_size);
            return 0;
        }
        int pid = fork_process(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_process(input_pid);
        return 1;
    }
    else if (!strcmp(input_str, "print")) {
        print();
        return 1;
    }
    else if (!strcmp(input_str, "run")) {
        int result = run(arguments);
        return result;
    }
    else if (input_str[0] == '\0');
    else {
        printf("Command not found.\n");
        return 0;
    }
}

void kill_process(int pid) {
    struct Block* block = NULL;
    for (int i = 0; i < MAX_NUM_TASKS; i++) {
        if (tasks[i].pid != pid) continue;

        block = tasks[i].block;
        break;
    }
    if (block == NULL) {
        printf("Error: PID dosen't exist.\n");
        return;
    }
    if (block->last && block->last->pid < 0 && block->next && block->next->pid < 0) {
        struct Block* free_block = block->last;
        free_block->next = block->next->next;
        free_block->size += block->size + block->next->size;
        if (free_block->next) free_block->next->last = free_block;
        free(block->next);
        free(block);
    }
    else if (block->last && block->last->pid < 0) {
        struct Block* free_block = block->last;
        free_block->next = block->next;
        free_block->size += block->size;
        if (free_block->next) free_block->next->last = free_block;
        free(block);
    }
    else if (block->next && block->next->pid < 0) {
        struct Block* free_block = block;
        free_block->size += block->next->size;
        free_block->next = block->next->next;
        free_block->pid = -1;
        if (free_block->next) free_block->next->last = free_block;
        free(block->next);
    }
    else {
        block->pid = -1;
    }

    execute_wait_list();

    return;
}

void init() {
    sys_space = (struct Block*)malloc(sizeof(struct Block));
    sys_space->pid = -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->pid = -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");
    printf("choose> ");
    scanf("%d", &match_method);
    clean_stdin();
    if (match_method != 1 && match_method != 2) {
        printf("Bad input. Choose again.\n");
        goto ask_match_method;
    }

    waitlist_begin = (struct Request*)malloc(sizeof(struct Request));
    waitlist_end = waitlist_begin;
    waitlist_begin->next = NULL;
    waitlist_begin->size = -1;
}

int fork_process(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 && tasks[i].pid == pid) goto repeat;
    }
    for (int i = 0; i < MAX_NUM_TASKS; i++) {
        if (tasks[i].pid >= 0) continue;
        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;
        tasks[task_index].block->pid = pid;
        printf("Fork succeed. PID is %d . Block size is %d bits.\n", pid, size);
        return pid;
    }
    printf("Fork failed. Out of Memory. Trying to push into wait list.\n");
    queue_push(size);
    return -1;
}

int find_free_block_ff(int size, struct Block** block_p) {
    struct Block* now = usr_space;
    int cnt = 1;
    while (1) {
        if (now == NULL) return -1;
        if (now->pid < 0 && now->size >= size) break;
        now = now->next;
        cnt++;
    }
    printf("Use %d times to find free block.\n", cnt);
    *block_p = now;
    if (now->size == size) return now->start;
    struct Block* free_space = (struct Block*)malloc(sizeof(struct Block));
    free_space->pid = -1;
    free_space->last = now;
    free_space->next = now->next;
    free_space->size = now->size - size;
    free_space->start = now->start + size;

    now->pid = -2;
    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 = 0x7fffffff;
    int cnt = 1;
    while (1) {
        if (now == NULL) break;
        if (now->pid < 0 && now->size >= size && best_size >= now->size) {
            best_block = now;
            best_size = now->size;
        }
        now = now->next;
        cnt++;
    }
    if (best_size == 0x7fffffff) return -1;
    printf("Use %d times to find free block.\n", cnt);
    *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->pid = -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->pid = -2;
    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);
    return result;
}

int preprocess_task_size(int size) {
    int lower = size & 0x3ff;
    if (lower == 0) return size;
    int upper = size - lower;
    size = upper + 0x400;
    return size;
}

void queue_push(int size) {
    waitlist_begin->next = (struct Request*)malloc(sizeof(struct Request));
    waitlist_begin = waitlist_begin->next;
    waitlist_begin->next = NULL;
    waitlist_begin->size = size;
    waitlist_size++;
}

int queue_pop() {
    if (!waitlist_size) {
        printf("Wait list empty.\n");
        return -1;
    }
    struct Request* tmp = waitlist_end;
    waitlist_end = waitlist_end->next;
    free(tmp);
    waitlist_size--;
    return waitlist_end->size;
}

void clean_stdin() {
    int c;
    do {
        c = getchar();
    } while (c != '\n' && c != EOF);
}

void execute_wait_list() {
    int size = -1, loop_num = waitlist_size;
    for (int i = 0; i < loop_num; i++) {
        size = queue_pop();
        fork_process(size);
    }
}

void print() {
    char str[2][13] = { {"        True"}, {"       False"} };
    char* s;
    struct Block* p = sys_space;
    printf("+----------------------------------------------------------------+\n");
    printf("|                          System Space                          |\n");
    printf("+------------+------------+------------+------------+------------+\n");
    printf("|    Free    |   Begin    |    Size    |    End     |     PID    |\n");
    printf("+------------+------------+------------+------------+------------+\n");
    while (p != NULL) {
        s = p->pid < 0 ? str[0] : str[1];
        printf("|%s|%12d|%12d|%12d|%12d|\n", s, p->start, p->size, p->start + p->size - 1, p->pid);
        printf("+------------+------------+------------+------------+------------+\n");
        p = p->next;
    }
    printf("+----------------------------------------------------------------+\n\n");

    p = usr_space;
    printf("+----------------------------------------------------------------+\n");
    printf("|                           User Space                           |\n");
    printf("+------------+------------+------------+------------+------------+\n");
    printf("|    Free    |   Begin    |    Size    |    End     |     PID    |\n");
    printf("+------------+------------+------------+------------+------------+\n");
    while (p != NULL) {
        s = p->pid < 0 ? str[0] : str[1];
        printf("|%s|%12d|%12d|%12d|%12d|\n", s, p->start, p->size, p->start + p->size - 1, p->pid);
        printf("+------------+------------+------------+------------+------------+\n");
        p = p->next;
    }
    printf("+----------------------------------------------------------------+\n");
}