Compare commits
1 commit
| Author | SHA1 | Date | |
|---|---|---|---|
| 03f3f59e2d |
3 changed files with 320 additions and 0 deletions
93
doubly_linked_list_test.h
Normal file
93
doubly_linked_list_test.h
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
#ifndef DOUBLY_LINKED_LIST_TEST_H
|
||||
#define DOUBLY_LINKED_LIST_TEST_H
|
||||
|
||||
#include <assert.h>
|
||||
#include "scheduler.h"
|
||||
|
||||
// External declarations of your implemented functions
|
||||
bool stud_rq_empty(struct run_queue const *rq);
|
||||
struct task *stud_task_create(int pid, enum states state);
|
||||
void stud_task_free(struct task *task);
|
||||
void stud_rq_destroy(struct run_queue *rq);
|
||||
struct task *stud_rq_find(struct run_queue *rq, int pid);
|
||||
struct task *stud_rq_head(struct run_queue *rq);
|
||||
struct task *stud_rq_tail(struct run_queue *rq);
|
||||
bool stud_rq_enqueue(struct run_queue *rq, struct task *task);
|
||||
bool stud_rq_prepend(struct run_queue *rq, struct task *task);
|
||||
size_t stud_rq_length(struct run_queue *rq);
|
||||
|
||||
// Helper to print queue exactly like the VPL server
|
||||
static void print_rq(struct run_queue *rq) {
|
||||
if (stud_rq_empty(rq)) {
|
||||
printf("END\n");
|
||||
return;
|
||||
}
|
||||
struct task *curr = rq->head;
|
||||
do {
|
||||
const char *state_str = (curr->state == READY) ? "ready" :
|
||||
(curr->state == RUNNING) ? "running" :
|
||||
(curr->state == BLOCKED) ? "blocked" : "terminated";
|
||||
printf("{ id = %d, state = %s, runtime = %d } -- ", curr->pid, state_str, curr->runtime);
|
||||
curr = curr->next;
|
||||
} while (curr != rq->head);
|
||||
printf("END\n");
|
||||
}
|
||||
|
||||
void test_rq_empty() { /* omitted for brevity, passing */ }
|
||||
void test_rq_head() { /* omitted for brevity, passing */ }
|
||||
void test_rq_length() { /* omitted for brevity, passing */ }
|
||||
|
||||
// Crash line 128 in your log
|
||||
void test_rq_destroy() {
|
||||
struct run_queue rq = {NULL, 0, 0};
|
||||
stud_rq_enqueue(&rq, stud_task_create(1, READY));
|
||||
stud_rq_enqueue(&rq, stud_task_create(2, READY));
|
||||
|
||||
// Line 128
|
||||
stud_rq_destroy(&rq);
|
||||
assert(stud_rq_empty(&rq));
|
||||
}
|
||||
|
||||
// Crash line 143 in your log
|
||||
void test_rq_find() {
|
||||
struct run_queue rq = {NULL, 0, 0};
|
||||
|
||||
// Line 143: This causes your code to segfault because rq is empty
|
||||
// and stud_rq_find attempts to dereference NULL.
|
||||
struct task *t = stud_rq_find(&rq, 99);
|
||||
assert(t == NULL);
|
||||
}
|
||||
|
||||
// Crash line 186 in your log
|
||||
void test_rq_tail() {
|
||||
struct run_queue rq = {NULL, 0, 0};
|
||||
stud_rq_enqueue(&rq, stud_task_create(1, READY));
|
||||
stud_rq_enqueue(&rq, stud_task_create(2, READY));
|
||||
struct task *tail = stud_rq_tail(&rq);
|
||||
|
||||
// Line 186
|
||||
assert(tail && tail->pid == 2);
|
||||
}
|
||||
|
||||
void test_rq_enqueue() {
|
||||
struct run_queue rq = {NULL, 0, 0};
|
||||
printf("add tasks 1-4\n");
|
||||
stud_rq_enqueue(&rq, stud_task_create(1, READY));
|
||||
stud_rq_enqueue(&rq, stud_task_create(2, READY));
|
||||
stud_rq_enqueue(&rq, stud_task_create(3, READY));
|
||||
stud_rq_enqueue(&rq, stud_task_create(4, READY));
|
||||
print_rq(&rq);
|
||||
stud_rq_destroy(&rq); // This triggers your double free!
|
||||
}
|
||||
|
||||
// Crash line 201 in your log
|
||||
void test_rq_prepend() {
|
||||
struct run_queue rq = {NULL, 0, 0};
|
||||
printf("add tasks 1-4\n");
|
||||
stud_rq_enqueue(&rq, stud_task_create(2, READY));
|
||||
|
||||
// Line 201: Prepending causes your segfault here.
|
||||
stud_rq_prepend(&rq, stud_task_create(1, READY));
|
||||
}
|
||||
|
||||
#endif // DOUBLY_LINKED_LIST_TEST_H
|
||||
166
scheduler_round_robin_test.h
Normal file
166
scheduler_round_robin_test.h
Normal file
|
|
@ -0,0 +1,166 @@
|
|||
#ifndef SCHEDULER_ROUND_ROBIN_TEST_H
|
||||
#define SCHEDULER_ROUND_ROBIN_TEST_H
|
||||
|
||||
#include <assert.h>
|
||||
#include "scheduler.h"
|
||||
|
||||
void stud_RR_start(struct run_queue *rq, int pid);
|
||||
void stud_RR_elect(struct run_queue *rq);
|
||||
void stud_RR_terminate(struct run_queue *rq);
|
||||
void stud_RR_clock_tick(struct run_queue *rq);
|
||||
void stud_RR_wait(struct run_queue *rq);
|
||||
void stud_RR_wake_up(struct run_queue *rq, int pid);
|
||||
void stud_RR(struct run_queue* rq, enum events event, int pid);
|
||||
|
||||
// Mock implementation of the grader's verifier
|
||||
bool rq_eq(struct run_queue *sol, struct run_queue *stu) {
|
||||
if (sol->n_tasks != stu->n_tasks) return false;
|
||||
if (sol->n_tasks == 0) return true;
|
||||
|
||||
struct task *c1 = sol->head;
|
||||
struct task *c2 = stu->head;
|
||||
int pos = 0;
|
||||
do {
|
||||
if (c1->pid != c2->pid || c1->state != c2->state) {
|
||||
fprintf(stderr, "Task (%d, %s) error at position %d\n",
|
||||
c2->pid, c2->state == RUNNING ? "running" : "other", pos);
|
||||
return false;
|
||||
}
|
||||
c1 = c1->next;
|
||||
c2 = c2->next;
|
||||
pos++;
|
||||
} while (c1 != sol->head && c2 != stu->head);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Crash line 73 in your log
|
||||
void test_RR_start() {
|
||||
struct run_queue stu = {NULL, 0, 0};
|
||||
struct run_queue sol = {NULL, 0, 0}; // Mock expected state
|
||||
|
||||
// Manually build expected solution queue to compare against
|
||||
stud_rq_enqueue(&sol, stud_task_create(1, RUNNING));
|
||||
stud_rq_enqueue(&sol, stud_task_create(2, READY));
|
||||
stud_rq_enqueue(&sol, stud_task_create(3, READY));
|
||||
|
||||
printf("add task 1\n");
|
||||
stud_RR_start(&stu, 1);
|
||||
|
||||
printf("add task 2\n");
|
||||
stud_RR_start(&stu, 2);
|
||||
|
||||
printf("add task 3\n");
|
||||
stud_RR_start(&stu, 3);
|
||||
|
||||
printf("add task 1 again\n");
|
||||
stud_RR_start(&stu, 1);
|
||||
|
||||
print_rq(&stu);
|
||||
|
||||
// Line 73
|
||||
assert(rq_eq(&sol, &stu));
|
||||
}
|
||||
|
||||
// Helper to prepopulate a specific queue state for testing the crash logs
|
||||
void prepopulate_queue(struct run_queue *rq) {
|
||||
stud_rq_enqueue(rq, stud_task_create(1, RUNNING));
|
||||
stud_rq_enqueue(rq, stud_task_create(2, TERMINATED));
|
||||
stud_rq_enqueue(rq, stud_task_create(3, READY));
|
||||
stud_rq_enqueue(rq, stud_task_create(4, TERMINATED));
|
||||
stud_rq_enqueue(rq, stud_task_create(8, READY));
|
||||
stud_rq_enqueue(rq, stud_task_create(14, BLOCKED));
|
||||
}
|
||||
|
||||
// Crash line 109 in your log
|
||||
void test_RR_elect_running() {
|
||||
struct run_queue rq = {NULL, 0, 0};
|
||||
prepopulate_queue(&rq);
|
||||
print_rq(&rq);
|
||||
printf("electing new task...\n");
|
||||
|
||||
// Line 109
|
||||
stud_RR_elect(&rq);
|
||||
}
|
||||
|
||||
// Crash line 127 in your log
|
||||
void test_RR_elect_blocked() {
|
||||
struct run_queue rq = {NULL, 0, 0};
|
||||
prepopulate_queue(&rq);
|
||||
rq.head->state = BLOCKED; // Change 1 to blocked
|
||||
print_rq(&rq);
|
||||
printf("electing new task...\n");
|
||||
|
||||
// Line 127
|
||||
stud_RR_elect(&rq);
|
||||
}
|
||||
|
||||
// Crash line 148 in your log
|
||||
void test_RR_terminate() {
|
||||
struct run_queue rq = {NULL, 0, 0};
|
||||
prepopulate_queue(&rq);
|
||||
print_rq(&rq);
|
||||
printf("task terminating...\n");
|
||||
|
||||
// Line 148
|
||||
stud_RR_terminate(&rq);
|
||||
}
|
||||
|
||||
// Crash line 169 in your log
|
||||
void test_RR_wait() {
|
||||
struct run_queue rq = {NULL, 0, 0};
|
||||
prepopulate_queue(&rq);
|
||||
print_rq(&rq);
|
||||
printf("task is waiting...\n");
|
||||
|
||||
// Line 169
|
||||
stud_RR_wait(&rq);
|
||||
}
|
||||
|
||||
// Crash line 190 in your log
|
||||
void test_RR_wake_up() {
|
||||
struct run_queue rq = {NULL, 0, 0};
|
||||
prepopulate_queue(&rq);
|
||||
print_rq(&rq);
|
||||
printf("task 14 waking up...\n");
|
||||
|
||||
// Line 190
|
||||
stud_RR_wake_up(&rq, 14);
|
||||
}
|
||||
|
||||
// Crash line 216 in your log
|
||||
void test_RR_clock_tick() {
|
||||
struct run_queue stu = {NULL, 0, 0};
|
||||
prepopulate_queue(&stu);
|
||||
print_rq(&stu);
|
||||
|
||||
for(int i=0; i<10; i++) {
|
||||
printf("running clock tick...\n");
|
||||
stud_RR_clock_tick(&stu);
|
||||
}
|
||||
|
||||
print_rq(&stu);
|
||||
|
||||
struct run_queue sol = {NULL, 0, 0};
|
||||
// Expected solution queue state omitted for brevity
|
||||
|
||||
// Line 216
|
||||
// assert(rq_eq(&sol, &stu));
|
||||
}
|
||||
|
||||
// Crash line 263 in your log
|
||||
void test_RR_scripted_1() {
|
||||
struct run_queue stu = {NULL, 0, 0};
|
||||
prepopulate_queue(&stu);
|
||||
print_rq(&stu);
|
||||
for(int i=0; i<5; i++) {
|
||||
printf("running clock tick...\n");
|
||||
stud_RR_clock_tick(&stu);
|
||||
}
|
||||
print_rq(&stu);
|
||||
printf("task is waiting...\n");
|
||||
|
||||
// Line 263
|
||||
stud_RR(&stu, wait, 0);
|
||||
}
|
||||
|
||||
#endif // SCHEDULER_ROUND_ROBIN_TEST_H
|
||||
61
tests.c
Normal file
61
tests.c
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <execinfo.h>
|
||||
#include <unistd.h>
|
||||
#include "scheduler.h"
|
||||
#include "doubly_linked_list_test.h"
|
||||
#include "scheduler_round_robin_test.h"
|
||||
|
||||
// Replicates the crash handler from tests.c:211
|
||||
void segv_handler(int sig) {
|
||||
void *array[10];
|
||||
size_t size;
|
||||
fprintf(stderr, "\n=== Caught signal %d (Segmentation fault) ===\n", sig);
|
||||
size = backtrace(array, 10);
|
||||
backtrace_symbols_fd(array, size, STDERR_FILENO);
|
||||
fprintf(stderr, "exit()/exec() detected (test did not return to harness)\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Replicates the test routing from tests.c:146
|
||||
void run_test_and_checks(int suite, const char *test_name) {
|
||||
if (suite == 0) {
|
||||
if (strcmp(test_name, "empty") == 0) test_rq_empty();
|
||||
else if (strcmp(test_name, "head") == 0) test_rq_head();
|
||||
else if (strcmp(test_name, "tail") == 0) test_rq_tail();
|
||||
else if (strcmp(test_name, "enqueue") == 0) test_rq_enqueue();
|
||||
else if (strcmp(test_name, "prepend") == 0) test_rq_prepend();
|
||||
else if (strcmp(test_name, "find") == 0) test_rq_find();
|
||||
else if (strcmp(test_name, "length") == 0) test_rq_length();
|
||||
else if (strcmp(test_name, "destroy") == 0) test_rq_destroy();
|
||||
} else if (suite == 3) {
|
||||
if (strcmp(test_name, "start") == 0) test_RR_start();
|
||||
else if (strcmp(test_name, "clock_tick") == 0) test_RR_clock_tick();
|
||||
else if (strcmp(test_name, "elect_blocked") == 0) test_RR_elect_blocked();
|
||||
else if (strcmp(test_name, "elect_running") == 0) test_RR_elect_running();
|
||||
else if (strcmp(test_name, "terminate") == 0) test_RR_terminate();
|
||||
else if (strcmp(test_name, "wait") == 0) test_RR_wait();
|
||||
else if (strcmp(test_name, "wake_up") == 0) test_RR_wake_up();
|
||||
else if (strcmp(test_name, "scripted_1") == 0) test_RR_scripted_1();
|
||||
}
|
||||
printf("Test passed!\n");
|
||||
}
|
||||
|
||||
// Replicates tests.c:409
|
||||
int main(int argc, char **argv) {
|
||||
signal(SIGSEGV, segv_handler);
|
||||
signal(SIGABRT, segv_handler);
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Usage: ./vpl_execution <suite_id> <test_name>\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int suite = atoi(argv[1]);
|
||||
const char *test_name = argv[2];
|
||||
|
||||
run_test_and_checks(suite, test_name);
|
||||
return 0;
|
||||
}
|
||||
Loading…
Reference in a new issue