From d416a446aa272de0c0f0d124fe752177218fd1f9 Mon Sep 17 00:00:00 2001 From: hasslesstech Date: Fri, 7 Mar 2025 18:49:49 +0200 Subject: [PATCH] add process removal support and sanity checks for obvious memory corruption issues --- config.h | 6 +- inc/kernel.h | 3 +- src/kernel.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/main.c | 36 ++++++++++-- src/process.c | 5 ++ 5 files changed, 190 insertions(+), 12 deletions(-) diff --git a/config.h b/config.h index fe26c6a..5821822 100644 --- a/config.h +++ b/config.h @@ -1,3 +1,5 @@ -#define PHYSICAL_PAGE_AMOUNT 64 +#define PHYSICAL_PAGE_AMOUNT 1536 #define PAGE_REPLACEMENT_ALGORITHM 2 -#define WSCLOCK_TIME_WINDOW 15 +#define WSCLOCK_TIME_WINDOW 200 + +#define VERBOSE_SANITY_CHECK 0 diff --git a/inc/kernel.h b/inc/kernel.h index 534d794..780ef7a 100644 --- a/inc/kernel.h +++ b/inc/kernel.h @@ -12,6 +12,7 @@ struct RunQ { struct RunQ *RunQ(size_t max_procs); void RUNQ_add_process(size_t max_page_accesses, size_t total_pages_owned); +void RUNQ_remove_current_process(void); @@ -27,7 +28,7 @@ struct PhysPage { void KERNEL_page_fault(struct PageTableEntry *pt, size_t page_no); - void KERNEL_update_job(size_t page_amount); +void KERNEL_sanity_check_memory_lists(void); #endif diff --git a/src/kernel.c b/src/kernel.c index 54ddfff..864e376 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -14,6 +14,10 @@ extern struct PhysPage *first_busy_page; extern size_t system_time; +// metrics +extern int free_pages_cnt; +extern int busy_pages_cnt; + struct RunQ * RunQ(size_t max_procs) @@ -52,6 +56,72 @@ RUNQ_add_process(size_t max_page_accesses, runq->next_proc_id++; } +void +RUNQ_remove_current_process(void) +{ + struct Process *tp = runq->current_proc; + + printf("[kernel:remove_current_process] Cleaning up process id %d\n", tp->id); + + if (runq->current_proc == runq->current_proc->next) { + runq->current_proc = NULL; + } else { + // detach this process from the list + tp->prev->next = tp->next; + tp->next->prev = tp->prev; + + runq->current_proc = tp->next; + } + + // free pages allocated by this process + struct PhysPage *starting_page = first_busy_page; + struct PhysPage *cp = first_busy_page; + + for (size_t i = 0; i < PHYSICAL_PAGE_AMOUNT; i++) { + if (cp->pt == tp->pt) { + printf("[kernel:remove_current_process] Found ppn #%d (pte %d#%d), freeing it\n", cp->ppn, tp->id, cp->pt_index); + // detach page from the busy list + if (cp == cp->next) { + first_busy_page = NULL; + } else { + cp->prev->next = cp->next; + cp->next->prev = cp->prev; + + first_busy_page = cp->next; + } + busy_pages_cnt--; + + // attach page to the free list + if (!first_free_page) { + first_free_page = cp; + cp->next = cp; + cp->prev = cp; + } else { + cp->next = first_free_page; + cp->prev = first_free_page->prev; + cp->prev->next = cp; + cp->next->prev = cp; + } + free_pages_cnt++; + + // reset busy flag + cp->busy_flag = 0; + + cp = first_busy_page; + } else { + cp = cp->next; + } + + KERNEL_sanity_check_memory_lists(); + + if ((cp == starting_page) || (!cp)) + break; + } + + free(tp); +} + + void KERNEL_page_fault(struct PageTableEntry *pt, size_t page_no) @@ -59,6 +129,7 @@ KERNEL_page_fault(struct PageTableEntry *pt, size_t page_no) printf("[kernel:page_fault] Handling %d started\n", page_no); if (first_free_page) { + free_pages_cnt--; printf("[kernel:page_fault] Found free page #%d, using it\n", first_free_page->ppn); pt[page_no].ppn = first_free_page->ppn; pt[page_no].p = 1; @@ -83,6 +154,8 @@ KERNEL_page_fault(struct PageTableEntry *pt, size_t page_no) if (!first_busy_page) { // initialize the busy list with this page first_busy_page = this_page; + first_busy_page->prev = first_busy_page; + first_busy_page->next = first_busy_page; } else { // insert this page at the end of the list this_page->next = first_busy_page; @@ -90,6 +163,8 @@ KERNEL_page_fault(struct PageTableEntry *pt, size_t page_no) this_page->prev->next = this_page; this_page->next->prev = this_page; } + + busy_pages_cnt++; } else { printf("[kernel:page_fault] No free pages available, trying to swap...\n"); @@ -123,8 +198,8 @@ KERNEL_page_fault(struct PageTableEntry *pt, size_t page_no) first_busy_page = first_busy_page->next; } else if ((system_time - first_busy_page->last_accessed) > WSCLOCK_TIME_WINDOW) { - printf("[kernel:page_fault:wsclock] ppn %d: r = 0, time_window = %d (> WSCLOCK_TIME_WINDOW), using it\n", - first_busy_page->ppn, system_time - first_busy_page->last_accessed); + printf("[kernel:page_fault:wsclock] ppn %d: r = 0, time_window = %d (> %d), using it\n", + first_busy_page->ppn, system_time - first_busy_page->last_accessed, WSCLOCK_TIME_WINDOW); first_busy_page->pt[first_busy_page->pt_index].p = 0; first_busy_page->pt = pt; first_busy_page->pt_index = page_no; @@ -135,8 +210,8 @@ KERNEL_page_fault(struct PageTableEntry *pt, size_t page_no) goto page_replacement_resolved; } else { - printf("[kernel:page_fault:wsclock] ppn %d: r = 0, time_window = %d (<= WSCLOCK_TIME_WINDOW), still active\n", - first_busy_page->ppn, system_time - first_busy_page->last_accessed); + printf("[kernel:page_fault:wsclock] ppn %d: r = 0, time_window = %d (<= %d), still active\n", + first_busy_page->ppn, system_time - first_busy_page->last_accessed, WSCLOCK_TIME_WINDOW); first_busy_page = first_busy_page->next; } @@ -164,6 +239,8 @@ KERNEL_page_fault(struct PageTableEntry *pt, size_t page_no) page_replacement_resolved: #endif } + + KERNEL_sanity_check_memory_lists(); } void KERNEL_update_job(size_t page_amount) @@ -192,3 +269,70 @@ void KERNEL_update_job(size_t page_amount) } } } + +void +KERNEL_sanity_check_memory_lists(void) +{ + size_t ppns_free[PHYSICAL_PAGE_AMOUNT] = {0}; + + struct PhysPage *p = first_free_page; + struct PhysPage *cp = first_free_page; + + if (!first_free_page) { +#if VERBOSE_SANITY_CHECK >= 1 + printf("[kernel:sanity_check_memory_lists] Free page list is empty, skipping it\n"); +#endif + } else { + do { + if (!cp) + printf("[kernel:sanity_check_memory_lists] Free page is NULL, circular list is corrupted\n"); + + if (cp->busy_flag) + printf("[kernel:sanity_check_memory_lists] Free page #%d with set busy flag\n", cp->ppn); + + ppns_free[cp->ppn] += 1; +#if VERBOSE_SANITY_CHECK >= 2 + printf("[kernel:sanity_check_memory_lists] Processed free page #%d\n", cp->ppn); +#endif + + if (ppns_free[cp->ppn] > 1) + printf("[kernel:sanity_check_memory_lists] Free page #%d listed more than once (%d times)\n", cp->ppn, ppns_free[cp->ppn]); + + cp = cp->next; + } while (cp != p); + } + + size_t ppns_busy[PHYSICAL_PAGE_AMOUNT] = {0}; + + p = first_busy_page; + cp = first_busy_page; + + if (!first_busy_page) { +#if VERBOSE_SANITY_CHECK >= 1 + printf("[kernel:sanity_check_memory_lists] Busy page list is empty, skipping it\n"); +#endif + } else { + do { + if (!cp) + printf("[kernel:sanity_check_memory_lists] Busy page is NULL, circular list is corrupted\n"); + + if (!cp->busy_flag) + printf("[kernel:sanity_check_memory_lists] Busy page #%d with clear busy flag\n", cp->ppn); + + ppns_busy[cp->ppn] += 1; +#if VERBOSE_SANITY_CHECK >= 2 + printf("[kernel:sanity_check_memory_lists] Processed busy page #%d\n", cp->ppn); +#endif + + if (ppns_busy[cp->ppn] > 1) + printf("[kernel:sanity_check_memory_lists] Busy page #%d listed more than once (%d times)\n", cp->ppn, ppns_busy[cp->ppn]); + + cp = cp->next; + } while (cp != p); + } + + for (size_t i = 0; i < PHYSICAL_PAGE_AMOUNT; i++) { + if (ppns_free[i] >= 1 && ppns_busy[i] >= 1) + printf("[kernel:sanity_check_memory_lists] Page #%d is listed in both lists (%d times in total)\n", i, ppns_busy[i] + ppns_free[i]); + } +} diff --git a/src/main.c b/src/main.c index d8cf5c5..bb92925 100644 --- a/src/main.c +++ b/src/main.c @@ -15,11 +15,19 @@ struct PhysPage *first_busy_page; size_t system_time; +// metrics +int free_pages_cnt; +int busy_pages_cnt; + + int main(void) { system_time = 0; + free_pages_cnt = 0; + busy_pages_cnt = 0; + first_busy_page = NULL; first_free_page = malloc(sizeof(struct PhysPage)); @@ -27,6 +35,7 @@ main(void) first_free_page->busy_flag = 0; first_free_page->prev = first_free_page; first_free_page->next = first_free_page; + free_pages_cnt++; for (int i = 1; i < PHYSICAL_PAGE_AMOUNT; i++) { struct PhysPage *pp = malloc(sizeof(struct PhysPage)); @@ -46,17 +55,34 @@ main(void) pp->next = first_free_page; pp->next->prev = pp; pp->prev->next = pp; + + free_pages_cnt++; } runq = RunQ(10); for (size_t i = 0; i < 10; i++) { - RUNQ_add_process(10000, 10 + randint(90)); + //RUNQ_add_process(1000 + randint(29000), 10 + randint(190)); + RUNQ_add_process(30000, 200); } - for (int i = 0; i < 100; i++) { - PROCESS_run_for(runq->current_proc, 50); - runq->current_proc = runq->current_proc->next; - KERNEL_update_job(8); + for (int i = 0; i < 100000; i++) { + //int removal_requested = PROCESS_run_for(runq->current_proc, 50); + int removal_requested = PROCESS_run_for(runq->current_proc, 150); + + if (removal_requested) + RUNQ_remove_current_process(); + else + runq->current_proc = runq->current_proc->next; + + printf("[main:metrics] Memory usage stats: busy %d, free %d, total %d\n", busy_pages_cnt, free_pages_cnt, free_pages_cnt+busy_pages_cnt); + + //KERNEL_update_job(8); + KERNEL_update_job(64); + + if (!runq->current_proc) { + printf("[main:scheduling] No processes left to execute!\n"); + break; + } } } diff --git a/src/process.c b/src/process.c index 775766c..cdf6c70 100644 --- a/src/process.c +++ b/src/process.c @@ -23,6 +23,11 @@ Process(size_t proc_id, size_t max_accesses, size_t total_pages_owned) size_t PROCESS_run_for(struct Process *p, size_t time_bits) { + if (!p) { + printf("[process ?] p == NULL, something is very wrong\n"); + return 0; + } + for (size_t i = 0; (i < time_bits) && (p->pages_accessed < p->max_accesses); i++, p->pages_accessed++)