diff --git a/src/exchange-lib/Makefile.am b/src/exchange-lib/Makefile.am index 6cf70052b..c8fc4471b 100644 --- a/src/exchange-lib/Makefile.am +++ b/src/exchange-lib/Makefile.am @@ -48,6 +48,7 @@ libtalertesting_la_SOURCES = \ testing_api_trait_coin_priv.c \ testing_api_trait_denom_pub.c \ testing_api_trait_denom_sig.c \ + testing_api_trait_process.c \ testing_api_trait_reserve_priv.c libtalertesting_la_LIBADD = \ diff --git a/src/exchange-lib/test_exchange_api_new.c b/src/exchange-lib/test_exchange_api_new.c index 573e900f5..4cf842341 100644 --- a/src/exchange-lib/test_exchange_api_new.c +++ b/src/exchange-lib/test_exchange_api_new.c @@ -51,12 +51,6 @@ */ // static struct TALER_EXCHANGE_Handle *exchange; - -/** - * Pipe used to communicate child death via signal. - */ -static struct GNUNET_DISK_PipeHandle *sigpipe; - /** * Handle to the exchange process. */ @@ -115,24 +109,6 @@ run (void *cls, } -/** - * Signal handler called for SIGCHLD. Triggers the - * respective handler by writing to the trigger pipe. - */ -static void -sighandler_child_death () -{ - static char c; - int old_errno = errno; /* back-up errno */ - - GNUNET_break (1 == - GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle - (sigpipe, GNUNET_DISK_PIPE_END_WRITE), - &c, sizeof (c))); - errno = old_errno; /* restore errno */ -} - - /** * Remove files from previous runs @@ -311,17 +287,8 @@ main (int argc, } while (0 != system ("wget -q -t 1 -T 1 http://127.0.0.1:8081/keys -o /dev/null -O /dev/null")); fprintf (stderr, "\n"); - sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, - GNUNET_NO, GNUNET_NO); - GNUNET_assert (NULL != sigpipe); - shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, - &sighandler_child_death); result = TALER_TESTING_setup (&run, NULL); - - GNUNET_SIGNAL_handler_uninstall (shc_chld); - shc_chld = NULL; - GNUNET_DISK_pipe_close (sigpipe); GNUNET_break (0 == GNUNET_OS_process_kill (exchanged, SIGTERM)); diff --git a/src/exchange-lib/testing_api_loop.c b/src/exchange-lib/testing_api_loop.c index d1e153af6..22d786703 100644 --- a/src/exchange-lib/testing_api_loop.c +++ b/src/exchange-lib/testing_api_loop.c @@ -44,6 +44,12 @@ struct TALER_TESTING_Interpreter */ struct GNUNET_SCHEDULER_Task *task; + /** + * ID of task called whenever we get a SIGCHILD. + * Used for #TALER_TESTING_wait_for_sigchld(). + */ + struct GNUNET_SCHEDULER_Task *child_death_task; + /** * Main execution context for the main loop. */ @@ -70,14 +76,17 @@ struct TALER_TESTING_Interpreter */ int result; - /** - * Pipe used to communicate child death via signal. - */ - struct GNUNET_DISK_PipeHandle *sigpipe; - }; +/** + * Pipe used to communicate child death via signal. + * Must be global, as used in signal handler! + */ +static struct GNUNET_DISK_PipeHandle *sigpipe; + + + /** * Lookup command by label. * @@ -263,6 +272,67 @@ do_timeout (void *cls) } +/** + * Task triggered whenever we receive a SIGCHLD (child + * process died). + * + * @param cls closure + */ +static void +maint_child_death (void *cls) +{ + struct TALER_TESTING_Interpreter *is = cls; + struct TALER_TESTING_Command *cmd = &is->commands[is->ip]; + const struct GNUNET_DISK_FileHandle *pr; + struct GNUNET_OS_Process **processp; + char c[16]; + + is->child_death_task = NULL; + pr = GNUNET_DISK_pipe_handle (sigpipe, + GNUNET_DISK_PIPE_END_READ); + GNUNET_break (0 < + GNUNET_DISK_file_read (pr, + &c, + sizeof (c))); + if (GNUNET_OK != + TALER_TESTING_get_trait_process (cmd, + NULL, + &processp)) + { + GNUNET_break (0); + TALER_TESTING_interpreter_fail (is); + return; + } + GNUNET_OS_process_wait (*processp); + GNUNET_OS_process_destroy (*processp); + *processp = NULL; + TALER_TESTING_interpreter_next (is); +} + + +/** + * Wait until we receive SIGCHLD signal. + * Then obtain the process trait of the current + * command, wait on the the zombie and continue + * with the next command. + */ +void +TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is) +{ + const struct GNUNET_DISK_FileHandle *pr; + + GNUNET_assert (NULL == is->child_death_task); + pr = GNUNET_DISK_pipe_handle (sigpipe, + GNUNET_DISK_PIPE_END_READ); + is->child_death_task + = GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL, + pr, + &maint_child_death, + is); + +} + + void TALER_TESTING_run (struct TALER_TESTING_Interpreter *is, struct TALER_TESTING_Command *commands) @@ -298,6 +368,25 @@ struct MainContext }; +/** + * Signal handler called for SIGCHLD. Triggers the + * respective handler by writing to the trigger pipe. + */ +static void +sighandler_child_death () +{ + static char c; + int old_errno = errno; /* back-up errno */ + + GNUNET_break (1 == + GNUNET_DISK_file_write (GNUNET_DISK_pipe_handle + (sigpipe, + GNUNET_DISK_PIPE_END_WRITE), + &c, sizeof (c))); + errno = old_errno; /* restore errno */ +} + + static void main_wrapper (void *cls) { @@ -326,12 +415,21 @@ TALER_TESTING_setup (TALER_TESTING_Main main_cb, .main_cb_cls = main_cb_cls, .is = &is }; + struct GNUNET_SIGNAL_Context *shc_chld; memset (&is, 0, sizeof (is)); + sigpipe = GNUNET_DISK_pipe (GNUNET_NO, GNUNET_NO, + GNUNET_NO, GNUNET_NO); + GNUNET_assert (NULL != sigpipe); + shc_chld = GNUNET_SIGNAL_handler_install (GNUNET_SIGCHLD, + &sighandler_child_death); GNUNET_SCHEDULER_run (&main_wrapper, &main_ctx); + GNUNET_SIGNAL_handler_uninstall (shc_chld); + GNUNET_DISK_pipe_close (sigpipe); + sigpipe = NULL; return is.result; } diff --git a/src/exchange-lib/testing_api_trait_process.c b/src/exchange-lib/testing_api_trait_process.c index 2e2e0e137..877eca973 100644 --- a/src/exchange-lib/testing_api_trait_process.c +++ b/src/exchange-lib/testing_api_trait_process.c @@ -44,8 +44,8 @@ TALER_TESTING_get_trait_process (const struct TALER_TESTING_Command *cmd, struct GNUNET_OS_Process ***processp) { return cmd->traits (cmd->cls, - (void **) coin_priv, - TALER_TESTING_TRAIT_COIN_PRIVATE_KEY, + (void **) processp, + TALER_TESTING_TRAIT_PROCESS, selector); } @@ -57,7 +57,7 @@ TALER_TESTING_make_trait_process (const char *selector, struct TALER_TESTING_Trait ret = { .selector = selector, .trait_name = TALER_TESTING_TRAIT_PROCESS, - .ptr = (const void *) process + .ptr = (const void *) processp }; return ret; diff --git a/src/include/taler_testing_lib.h b/src/include/taler_testing_lib.h index 949297713..8e1191685 100644 --- a/src/include/taler_testing_lib.h +++ b/src/include/taler_testing_lib.h @@ -162,6 +162,16 @@ struct TALER_TESTING_Command TALER_TESTING_cmd_end (void); +/** + * Wait until we receive SIGCHLD signal. + * Then obtain the process trait of the current + * command, wait on the the zombie and continue + * with the next command. + */ +void +TALER_TESTING_wait_for_sigchld (struct TALER_TESTING_Interpreter *is); + + void TALER_TESTING_run (struct TALER_TESTING_Interpreter *is, struct TALER_TESTING_Command *commands); @@ -272,6 +282,28 @@ TALER_TESTING_get_trait_reserve_priv (const struct TALER_TESTING_Command *cmd, struct TALER_ReservePrivateKeyP **reserve_priv); + +/** + * Obtain location where a command stores a pointer to a process + * + * @param cmd command to extract trait from + * @param selector which process to pick if @a cmd has multiple on offer + * @param coin_priv[out] set to address of the pointer to the process + * @return #GNUNET_OK on success + */ +int +TALER_TESTING_get_trait_process (const struct TALER_TESTING_Command *cmd, + const char *selector, + struct GNUNET_OS_Process ***processp); + + + + +struct TALER_TESTING_Trait +TALER_TESTING_make_trait_process (const char *selector, + struct GNUNET_OS_Process **processp); + + /** * @param selector */