integrate sigpipe with ain loop

This commit is contained in:
Christian Grothoff 2018-01-21 18:46:18 +01:00
parent 41cb8b4c51
commit d09beecc8f
No known key found for this signature in database
GPG Key ID: 939E6BE1E29FC3CC
5 changed files with 139 additions and 41 deletions

View File

@ -48,6 +48,7 @@ libtalertesting_la_SOURCES = \
testing_api_trait_coin_priv.c \ testing_api_trait_coin_priv.c \
testing_api_trait_denom_pub.c \ testing_api_trait_denom_pub.c \
testing_api_trait_denom_sig.c \ testing_api_trait_denom_sig.c \
testing_api_trait_process.c \
testing_api_trait_reserve_priv.c testing_api_trait_reserve_priv.c
libtalertesting_la_LIBADD = \ libtalertesting_la_LIBADD = \

View File

@ -51,12 +51,6 @@
*/ */
// static struct TALER_EXCHANGE_Handle *exchange; // 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. * 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 * 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")); 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"); 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); result = TALER_TESTING_setup (&run, NULL);
GNUNET_SIGNAL_handler_uninstall (shc_chld);
shc_chld = NULL;
GNUNET_DISK_pipe_close (sigpipe);
GNUNET_break (0 == GNUNET_break (0 ==
GNUNET_OS_process_kill (exchanged, GNUNET_OS_process_kill (exchanged,
SIGTERM)); SIGTERM));

View File

@ -44,6 +44,12 @@ struct TALER_TESTING_Interpreter
*/ */
struct GNUNET_SCHEDULER_Task *task; 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. * Main execution context for the main loop.
*/ */
@ -70,14 +76,17 @@ struct TALER_TESTING_Interpreter
*/ */
int result; 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. * 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 void
TALER_TESTING_run (struct TALER_TESTING_Interpreter *is, TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
struct TALER_TESTING_Command *commands) 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 static void
main_wrapper (void *cls) main_wrapper (void *cls)
{ {
@ -326,12 +415,21 @@ TALER_TESTING_setup (TALER_TESTING_Main main_cb,
.main_cb_cls = main_cb_cls, .main_cb_cls = main_cb_cls,
.is = &is .is = &is
}; };
struct GNUNET_SIGNAL_Context *shc_chld;
memset (&is, memset (&is,
0, 0,
sizeof (is)); 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, GNUNET_SCHEDULER_run (&main_wrapper,
&main_ctx); &main_ctx);
GNUNET_SIGNAL_handler_uninstall (shc_chld);
GNUNET_DISK_pipe_close (sigpipe);
sigpipe = NULL;
return is.result; return is.result;
} }

View File

@ -44,8 +44,8 @@ TALER_TESTING_get_trait_process (const struct TALER_TESTING_Command *cmd,
struct GNUNET_OS_Process ***processp) struct GNUNET_OS_Process ***processp)
{ {
return cmd->traits (cmd->cls, return cmd->traits (cmd->cls,
(void **) coin_priv, (void **) processp,
TALER_TESTING_TRAIT_COIN_PRIVATE_KEY, TALER_TESTING_TRAIT_PROCESS,
selector); selector);
} }
@ -57,7 +57,7 @@ TALER_TESTING_make_trait_process (const char *selector,
struct TALER_TESTING_Trait ret = { struct TALER_TESTING_Trait ret = {
.selector = selector, .selector = selector,
.trait_name = TALER_TESTING_TRAIT_PROCESS, .trait_name = TALER_TESTING_TRAIT_PROCESS,
.ptr = (const void *) process .ptr = (const void *) processp
}; };
return ret; return ret;

View File

@ -162,6 +162,16 @@ struct TALER_TESTING_Command
TALER_TESTING_cmd_end (void); 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 void
TALER_TESTING_run (struct TALER_TESTING_Interpreter *is, TALER_TESTING_run (struct TALER_TESTING_Interpreter *is,
struct TALER_TESTING_Command *commands); 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); 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 * @param selector
*/ */