diff options
Diffstat (limited to 'src/test/on_exit.cc')
-rw-r--r-- | src/test/on_exit.cc | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/src/test/on_exit.cc b/src/test/on_exit.cc new file mode 100644 index 00000000..aec1f78b --- /dev/null +++ b/src/test/on_exit.cc @@ -0,0 +1,115 @@ +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <stdlib.h> +#include <unistd.h> +#include "include/on_exit.h" +#include "include/ceph_assert.h" + +#ifndef MAP_ANONYMOUS +# ifdef MAP_ANON +# define MAP_ANONYMOUS MAP_ANON +# else +// cppcheck-suppress preprocessorErrorDirective +# error "Don't know how to create anonymous mmap" +# endif +#endif + +static int func_scope_val; + +static void add(void *incp) +{ + func_scope_val += *((int*)incp); +} + +static void func_scope(void) +{ + OnExitManager mgr; + + int *inc_1 = (int*)malloc(sizeof(*inc_1)); + *inc_1 = 5; + mgr.add_callback(add, inc_1); + + int *inc_2 = (int*)malloc(sizeof(*inc_2)); + *inc_2 = 3; + mgr.add_callback(add, inc_2); +} + +// shared between processes +static int *shared_val; + +#define MAIN_SCOPE_VAL 0x1111111 +static OnExitManager main_scope_mgr; +static void main_scope_cb(void *val) +{ + *shared_val = *((int*)val); +} + +#define EXIT_FUNC_VAL 0x22222222 +static OnExitManager exit_func_mgr; +static void exit_func_cb(void *val) +{ + *shared_val = *((int*)val); +} + +static void call_exit() +{ + exit(3); +} + +int main(int argc, char **argv) +{ + // test basic function scope behavior + ceph_assert(func_scope_val == 0); + func_scope(); + ceph_assert(func_scope_val == 8); + + // shared mem for exit tests + shared_val = (int*)mmap(NULL, sizeof(int), + PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0); + ceph_assert(shared_val != MAP_FAILED); + + // test normal exit returning from main + *shared_val = 0; + int pid = fork(); + ceph_assert(pid >= 0); + if (pid) { + int status; + int ret = waitpid(pid, &status, 0); + ceph_assert(ret == pid); // should be our child + ceph_assert(status == 0); + ceph_assert(*shared_val == MAIN_SCOPE_VAL); + } else { + // child adds a callback to the static scope callback manager and then + // exits by returning from main. The parent checks the value after the + // child exits via the memory map. + ceph_assert(*shared_val == 0); + int *new_val = (int*)malloc(sizeof(*new_val)); + *new_val = MAIN_SCOPE_VAL; + main_scope_mgr.add_callback(main_scope_cb, new_val); + return 0; + } + + // test exit via exit() + *shared_val = 0; + pid = fork(); + ceph_assert(pid >= 0); + if (pid) { + int status; + int ret = waitpid(pid, &status, 0); + ceph_assert(ret == pid); // should be our child + ceph_assert(WEXITSTATUS(status) == 3); + ceph_assert(*shared_val == EXIT_FUNC_VAL); + } else { + // child adds a callback to the static scope callback manager and then + // exits via exit(). + ceph_assert(*shared_val == 0); + int *new_val = (int*)malloc(sizeof(*new_val)); + *new_val = EXIT_FUNC_VAL; + exit_func_mgr.add_callback(exit_func_cb, new_val); + call_exit(); + ceph_abort(); + } + + return 0; +} |