From 2378353eab064ed06166e025a1df9d4a23efe6c4 Mon Sep 17 00:00:00 2001 From: Christian Grothoff Date: Mon, 10 Oct 2016 14:52:47 +0000 Subject: [PATCH] extending process API to allow obtaining status code in blocking fashion --- src/include/gnunet_os_lib.h | 25 ++++++++-- src/include/gnunet_testbed_service.h | 1 + src/util/os_priority.c | 66 +++++++++++++++++++++++++-- src/util/service_new.c | 68 ++++++++++++++++++++-------- 4 files changed, 132 insertions(+), 28 deletions(-) diff --git a/src/include/gnunet_os_lib.h b/src/include/gnunet_os_lib.h index 39c70c8bd..ce3e05f13 100644 --- a/src/include/gnunet_os_lib.h +++ b/src/include/gnunet_os_lib.h @@ -524,7 +524,8 @@ struct GNUNET_OS_CommandHandle; * @param cls closure * @param line line of output from a command, NULL for the end */ -typedef void (*GNUNET_OS_LineProcessor) (void *cls, const char *line); +typedef void +(*GNUNET_OS_LineProcessor) (void *cls, const char *line); /** @@ -548,8 +549,10 @@ GNUNET_OS_command_stop (struct GNUNET_OS_CommandHandle *cmd); * @return NULL on error */ struct GNUNET_OS_CommandHandle * -GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, void *proc_cls, - struct GNUNET_TIME_Relative timeout, const char *binary, +GNUNET_OS_command_run (GNUNET_OS_LineProcessor proc, + void *proc_cls, + struct GNUNET_TIME_Relative timeout, + const char *binary, ...); @@ -582,6 +585,22 @@ int GNUNET_OS_process_wait (struct GNUNET_OS_Process *proc); + +/** + * Retrieve the status of a process, waiting on him if dead. + * Blocking version. + * + * @param proc pointer to process structure + * @param type status type + * @param code return code/signal number + * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise + */ +int +GNUNET_OS_process_wait_status (struct GNUNET_OS_Process *proc, + enum GNUNET_OS_ProcessStatusType *type, + unsigned long *code); + + /** * Connects this process to its parent via pipe; * essentially, the parent control handler will read signal numbers diff --git a/src/include/gnunet_testbed_service.h b/src/include/gnunet_testbed_service.h index 7d9abbe49..f8a8ef38d 100644 --- a/src/include/gnunet_testbed_service.h +++ b/src/include/gnunet_testbed_service.h @@ -1493,6 +1493,7 @@ GNUNET_TESTBED_test_run (const char *testname, struct GNUNET_TESTBED_Controller * GNUNET_TESTBED_run_get_controller_handle (struct GNUNET_TESTBED_RunHandle *h); + /** * Opaque handle for barrier */ diff --git a/src/util/os_priority.c b/src/util/os_priority.c index 9b1ec0963..4b1dbd491 100644 --- a/src/util/os_priority.c +++ b/src/util/os_priority.c @@ -1592,19 +1592,21 @@ GNUNET_OS_start_process_s (int pipe_control, * @param proc process ID * @param type status type * @param code return code/signal number + * @param options WNOHANG if non-blocking is desired * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise */ -int -GNUNET_OS_process_status (struct GNUNET_OS_Process *proc, - enum GNUNET_OS_ProcessStatusType *type, - unsigned long *code) +static int +process_status (struct GNUNET_OS_Process *proc, + enum GNUNET_OS_ProcessStatusType *type, + unsigned long *code, + int options) { #ifndef MINGW int status; int ret; GNUNET_assert (0 != proc); - ret = waitpid (proc->pid, &status, WNOHANG); + ret = waitpid (proc->pid, &status, options); if (ret < 0) { LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, @@ -1650,6 +1652,10 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc, *code = 0; } #else +#ifndef WNOHANG +#define WNOHANG 42 /* just a flag for W32, purely internal at this point */ +#endif + HANDLE h; DWORD c, error_code, ret; @@ -1665,6 +1671,14 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc, if (h == NULL) h = GetCurrentProcess (); + if (WNOHANG != options) + { + if (WAIT_OBJECT_0 != WaitForSingleObject (h, INFINITE)) + { + SetErrnoFromWinError (GetLastError ()); + return GNUNET_SYSERR; + } + } SetLastError (0); ret = GetExitCodeProcess (h, &c); error_code = GetLastError (); @@ -1688,6 +1702,48 @@ GNUNET_OS_process_status (struct GNUNET_OS_Process *proc, } +/** + * Retrieve the status of a process, waiting on him if dead. + * Nonblocking version. + * + * @param proc process ID + * @param type status type + * @param code return code/signal number + * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise + */ +int +GNUNET_OS_process_status (struct GNUNET_OS_Process *proc, + enum GNUNET_OS_ProcessStatusType *type, + unsigned long *code) +{ + return process_status (proc, + type, + code, + WNOHANG); +} + + +/** + * Retrieve the status of a process, waiting on him if dead. + * Blocking version. + * + * @param proc pointer to process structure + * @param type status type + * @param code return code/signal number + * @return #GNUNET_OK on success, #GNUNET_NO if the process is still running, #GNUNET_SYSERR otherwise + */ +int +GNUNET_OS_process_wait_status (struct GNUNET_OS_Process *proc, + enum GNUNET_OS_ProcessStatusType *type, + unsigned long *code) +{ + return process_status (proc, + type, + code, + 0); +} + + /** * Wait for a process to terminate. The return code is discarded. * You must not use #GNUNET_OS_process_status() on the same process diff --git a/src/util/service_new.c b/src/util/service_new.c index cf871eb89..9929341f4 100644 --- a/src/util/service_new.c +++ b/src/util/service_new.c @@ -1535,6 +1535,35 @@ detach_terminal (struct GNUNET_SERVICE_Handle *sh) } +/** + * Tear down the service, closing the listen sockets and + * freeing the ACLs. + * + * @param sh handle to the service to tear down. + */ +static void +teardown_service (struct GNUNET_SERVICE_Handle *sh) +{ + struct ServiceListenContext *slc; + + GNUNET_free_non_null (sh->v4_denied); + GNUNET_free_non_null (sh->v6_denied); + GNUNET_free_non_null (sh->v4_allowed); + GNUNET_free_non_null (sh->v6_allowed); + while (NULL != (slc = sh->slc_head)) + { + GNUNET_CONTAINER_DLL_remove (sh->slc_head, + sh->slc_tail, + slc); + if (NULL != slc->listen_task) + GNUNET_SCHEDULER_cancel (slc->listen_task); + GNUNET_break (GNUNET_OK == + GNUNET_NETWORK_socket_close (slc->listen_socket)); + GNUNET_free (slc); + } +} + + /** * Low-level function to start a service if the scheduler * is already running. Should only be used directly in @@ -1579,8 +1608,21 @@ GNUNET_SERVICE_starT (const char *service_name, void *cls, const struct GNUNET_MQ_MessageHandler *handlers) { - GNUNET_break (0); // FIXME: not implemented - return NULL; + struct GNUNET_SERVICE_Handle *sh; + + sh = GNUNET_new (struct GNUNET_SERVICE_Handle); + sh->service_name = service_name; + sh->cfg = cfg; + sh->connect_cb = connect_cb; + sh->disconnect_cb = disconnect_cb; + sh->cb_cls = cls; + sh->handlers = handlers; + if (GNUNET_OK != setup_service (sh)) + { + GNUNET_free (sh); + return NULL; + } + return sh; } @@ -1592,7 +1634,8 @@ GNUNET_SERVICE_starT (const char *service_name, void GNUNET_SERVICE_stoP (struct GNUNET_SERVICE_Handle *srv) { - GNUNET_assert (0); // FIXME: not implemented + teardown_service (srv); + GNUNET_free (srv); } @@ -1823,29 +1866,14 @@ shutdown: } } #endif + teardown_service (&sh); + GNUNET_SPEEDUP_stop_ (); GNUNET_CONFIGURATION_destroy (cfg); - - while (NULL != sh.slc_head) - { - struct ServiceListenContext *slc = sh.slc_head; - - sh.slc_head = slc->next; - if (NULL != slc->listen_task) - GNUNET_SCHEDULER_cancel (slc->listen_task); - GNUNET_break (GNUNET_OK == - GNUNET_NETWORK_socket_close (slc->listen_socket)); - GNUNET_free (slc); - } - GNUNET_free_non_null (logfile); GNUNET_free_non_null (loglev); GNUNET_free (cfg_filename); GNUNET_free_non_null (opt_cfg_filename); - GNUNET_free_non_null (sh.v4_denied); - GNUNET_free_non_null (sh.v6_denied); - GNUNET_free_non_null (sh.v4_allowed); - GNUNET_free_non_null (sh.v6_allowed); return err ? GNUNET_SYSERR : sh.ret; } -- 2.25.1