From 078841353cab799fa1bbd87cb4ccc2ddade7822d Mon Sep 17 00:00:00 2001 From: JP Appel Date: Mon, 22 Jul 2024 21:38:35 -0400 Subject: FIX: correctly remove shared memory on early exit --- eztester.c | 151 +++++++++++++++++++++++++++++++++++-------------------------- 1 file changed, 86 insertions(+), 65 deletions(-) (limited to 'eztester.c') diff --git a/eztester.c b/eztester.c index 6cafbea..0370655 100644 --- a/eztester.c +++ b/eztester.c @@ -20,25 +20,72 @@ struct _ez_shared_mem { size_t index; }; +struct _ez_tests_results { + size_t current; + size_t passed; + size_t total; +}; + volatile sig_atomic_t _ez_child_premature_exit = 0; volatile sig_atomic_t _ez_child_premature_exit_signal; volatile sig_atomic_t _ez_child_premature_exit_status = 0; -void _ez_print_test_results(const size_t tests_run, const size_t tests_passed, - const size_t num_tests) { - printf("--------\nRan %zu of %zu tests\n", tests_run, num_tests); - if (tests_run == num_tests && tests_run == tests_passed) { +struct _ez_shared_mem *_ez_create_shared_memory() { + const size_t shm_size = sizeof(struct _ez_shared_mem); + char shr_mem_name[32]; + sprintf(shr_mem_name, "/eztester-%d", getpid()); + + int shm_fd = shm_open(shr_mem_name, O_RDWR | O_CREAT, 0666); + if (shm_fd == -1) { + perror("shm_open"); + exit(1); + } + + if (ftruncate(shm_fd, shm_size) == -1) { + perror("ftruncate"); + exit(1); + } + + void *shm_ptr = + mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); + if (shm_ptr == MAP_FAILED) { + perror("mmap"); + exit(1); + } + + return shm_ptr; +} + +void _ez_destroy_shared_memory(struct _ez_shared_mem *mem) { + char shr_mem_name[32]; + sprintf(shr_mem_name, "/eztester-%d", getpid()); + + // unmap memory + if (munmap(mem, sizeof(struct _ez_shared_mem)) == -1) { + perror("munmap"); + exit(1); + } + // unlink shared memory + if (shm_unlink(shr_mem_name) == -1) { + perror("shm_unlink"); + exit(1); + } +} + +void _ez_print_test_results(const struct _ez_tests_results results) { + printf("\n--------\nRan %zu of %zu tests\n", results.current, results.total); + if (results.current == results.total && results.current == results.passed) { printf("All tests passed :)\n"); - } else if (tests_run == num_tests && tests_passed == 0) { + } else if (results.current == results.total && results.passed == 0) { printf("No test passsed :(\n"); } else { - printf("%zu of %zu tests passed\n", tests_passed, tests_run); + printf("%zu of %zu tests passed\n", results.passed, results.current); } } void _ez_premature_exit(const char *message, const pid_t worker, - const size_t current_test, const size_t tests_passed, - const size_t num_tests) { + struct _ez_shared_mem *mem, + const struct _ez_tests_results results) { fprintf(stderr, "%s\n", message); if (_ez_child_premature_exit) { if (_ez_child_premature_exit_status != 0) { @@ -46,13 +93,15 @@ void _ez_premature_exit(const char *message, const pid_t worker, _ez_child_premature_exit_status); } if (_ez_child_premature_exit_signal > 0) { - fprintf(stderr, "Worker Process exited because of signal: %s", + fprintf(stderr, "Worker Process exited because of signal: %s\n", strsignal(_ez_child_premature_exit_signal)); } } kill(worker, SIGTERM); wait(NULL); - _ez_print_test_results(current_test, tests_passed, num_tests); + _ez_print_test_results(results); + + _ez_destroy_shared_memory(mem); exit(1); } @@ -92,26 +141,8 @@ void _ez_chld_handler(int signum) { } void eztester_run(eztester_list *test_list, eztester_behavior behavior) { - const size_t shm_size = sizeof(struct _ez_shared_mem); - int shm_fd = shm_open("/test_queue", O_RDWR | O_CREAT, 0666); - if (shm_fd == -1) { - perror("shm_open"); - exit(1); - } - if (ftruncate(shm_fd, shm_size) == -1) { - perror("ftruncate"); - exit(1); - } - - void *shm_ptr = - mmap(NULL, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); - if (shm_ptr == MAP_FAILED) { - perror("mmap"); - exit(1); - } - - struct _ez_shared_mem *mem = shm_ptr; + struct _ez_shared_mem *mem = _ez_create_shared_memory(); mem->index = 0; mem->work_in_queue = false; mem->behavior = behavior; @@ -127,8 +158,8 @@ void eztester_run(eztester_list *test_list, eztester_behavior behavior) { eztester_status status; eztester_test test; - const size_t length = test_list->length; - size_t pass_count = 0; + struct _ez_tests_results results = { + .current = 0, .passed = 0, .total = test_list->length}; // set child signal handler signal(SIGCHLD, _ez_chld_handler); @@ -136,67 +167,58 @@ void eztester_run(eztester_list *test_list, eztester_behavior behavior) { for (size_t i = 0; i < test_list->length; i++) { test = test_list->tests[i]; + results.current = i + 1; mem->index = i; mem->work_in_queue = true; - printf("[%03zu/%03zu] Testing: %s\n", i + 1, length, test.name); + printf("[%03zu/%03zu] Testing: %s\n", results.current, results.total, + test.name); fflush(stdout); if (_ez_child_premature_exit) { - _ez_premature_exit("Worker Process ended prematurely!", pid, i + 1, - pass_count, length); + _ez_premature_exit("Worker Process ended prematurely!", pid, mem, + results); } while (mem->work_in_queue) { usleep(1000 * 50); if (_ez_child_premature_exit) { - _ez_premature_exit("Worker Process ended prematurely!", pid, i + 1, - pass_count, length); + _ez_premature_exit("Worker Process ended prematurely!", pid, mem, + results); } } status = mem->status; switch (status) { case TEST_PASS: - printf("[%03zu/%03zu] %s Result: Pass\n", i + 1, length, test.name); - pass_count++; + printf("[%03zu/%03zu] %s Result: Pass\n", results.current, results.total, test.name); + results.passed++; break; case TEST_WARNING: - printf("[%03zu/%03zu] %s Result: Warning\n", i + 1, length, test.name); + printf("[%03zu/%03zu] %s Result: Warning\n", results.current, results.total, test.name); if (behavior == EXIT_ON_WARNING) { - _ez_premature_exit("Warning occured, Exitting", pid, i + 1, pass_count, - length); + _ez_premature_exit("Warning occured, Exitting", pid, mem, results); } - pass_count++; + results.passed++; break; case TEST_FAIL: - printf("[%03zu/%03zu] %s Result: Fail\n", i + 1, length, test.name); + printf("[%03zu/%03zu] %s Result: Fail\n", results.current, results.total, test.name); if (behavior != CONTINUE_ALL) { - _ez_premature_exit("Failure occured, Exitting", pid, i + 1, pass_count, - length); + _ez_premature_exit("Failure occured, Exitting", pid, mem, results); } break; case TEST_ERROR: - printf("[%03zu/%03zu] %s Result: Error\n", i + 1, length, test.name); - _ez_premature_exit("Fatal Error occured! Exiting", pid, i + 1, pass_count, - length); + printf("[%03zu/%03zu] %s Result: Error\n", results.current, results.total, test.name); + _ez_premature_exit("Fatal Error occured! Exiting", pid, mem, results); break; } } + signal(SIGCHLD, SIG_DFL); - _ez_print_test_results(length, pass_count, length); + _ez_print_test_results(results); - // unmap memory - if (munmap(shm_ptr, shm_size) == -1) { - perror("munmap"); - exit(1); - } - // unlink shared memory - if (shm_unlink("/test_queue") == -1) { - perror("shm_unlink"); - exit(1); - } + _ez_destroy_shared_memory(mem); } int eztester_shell(const char *command) { @@ -210,12 +232,11 @@ int eztester_shell(const char *command) { eztester_log("Executing %s", command); result = system(command); - if(result == -1){ - eztester_log("Error with child process"); - perror(command); - } - else { - eztester_log("Process exited with a status of %d", result); + if (result == -1) { + eztester_log("Error with child process"); + perror(command); + } else { + eztester_log("Process exited with a status of %d", result); } return result; -- cgit v1.2.3