aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJP Appel <jeanpierre.appel01@gmail.com>2024-07-22 21:38:35 -0400
committerJP Appel <jeanpierre.appel01@gmail.com>2024-07-22 21:38:35 -0400
commit078841353cab799fa1bbd87cb4ccc2ddade7822d (patch)
tree3747f818e50e7ce39f9be342ddc4d46852b2985d
parent78f7532f00ac2b125659b4dac03d5072f25e1af0 (diff)
FIX: correctly remove shared memory on early exit
-rw-r--r--README.md2
-rw-r--r--eztester.c151
2 files changed, 87 insertions, 66 deletions
diff --git a/README.md b/README.md
index 3420f37..9e5f6f2 100644
--- a/README.md
+++ b/README.md
@@ -128,5 +128,5 @@ To use the header-only implementation replace the include in your programs entry
* [x] static library target
* [x] dynamic library target
* [x] header-only target
+* [x] shell command utility
* [ ] colorized output
-* [ ] `run_shell_script`
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;