diff options
author | Thomas Haller <thaller@redhat.com> | 2021-05-07 23:08:27 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2021-05-14 11:41:32 +0200 |
commit | 071ef784cfb05abbda6c811000ed4cd93026e6a9 (patch) | |
tree | 7fcab08e281a4a454144033ec157c4430238c94f | |
parent | 62027350f7e29447ee7976785ccf56f918a635cc (diff) | |
download | NetworkManager-071ef784cfb05abbda6c811000ed4cd93026e6a9.tar.gz |
glib-aux: add nm_g_subprocess_terminate_in_background() helper
-rw-r--r-- | src/libnm-glib-aux/nm-io-utils.c | 73 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-io-utils.h | 2 |
2 files changed, 75 insertions, 0 deletions
diff --git a/src/libnm-glib-aux/nm-io-utils.c b/src/libnm-glib-aux/nm-io-utils.c index 0176abf7f8..894c8726c0 100644 --- a/src/libnm-glib-aux/nm-io-utils.c +++ b/src/libnm-glib-aux/nm-io-utils.c @@ -491,3 +491,76 @@ nm_utils_fd_read(int fd, NMStrBuf *out_string) return n_read; } + +/*****************************************************************************/ + +typedef struct { + GSubprocess *subprocess; + GSource * timeout_source; +} SubprocessTerminateData; + +static void +_subprocess_terminate_wait_cb(GObject *source, GAsyncResult *result, gpointer user_data) +{ + SubprocessTerminateData *term_data = user_data; + + g_subprocess_wait_finish(G_SUBPROCESS(source), result, NULL); + + nm_clear_g_source_inst(&term_data->timeout_source); + g_object_unref(term_data->subprocess); + nm_g_slice_free(term_data); +} + +static gboolean +_subprocess_terminate_timeout_cb(gpointer user_data) +{ + SubprocessTerminateData *term_data = user_data; + + nm_clear_g_source_inst(&term_data->timeout_source); + g_subprocess_send_signal(term_data->subprocess, SIGKILL); + return G_SOURCE_REMOVE; +} + +void +nm_g_subprocess_terminate_in_background(GSubprocess *subprocess, int timeout_msec_before_kill) +{ + SubprocessTerminateData *term_data; + GMainContext * main_context; + + nm_assert(timeout_msec_before_kill > 0); + + /* The GSubprocess stays alive until the child is reaped (an internal reference is held). + * + * This function first sends SIGTERM to the process right away, and after a + * timeout "timeout_msec_before_kill" send a SIGKILL. + * + * Otherwise, it does nothing, it does not log, there is no notification when the process + * completes and there is no way to abort the thing. + * + * It honors the current g_main_context_get_thread_default(). */ + + if (!subprocess) + return; + + g_return_if_fail(G_IS_SUBPROCESS(subprocess)); + + main_context = g_main_context_get_thread_default(); + + term_data = g_slice_new(SubprocessTerminateData); + *term_data = (SubprocessTerminateData){ + .subprocess = g_object_ref(subprocess), + .timeout_source = NULL, + }; + + g_subprocess_send_signal(subprocess, SIGTERM); + + g_subprocess_wait_async(subprocess, NULL, _subprocess_terminate_wait_cb, term_data); + + term_data->timeout_source = + nm_g_source_attach(nm_g_timeout_source_new(timeout_msec_before_kill, + G_PRIORITY_DEFAULT, + _subprocess_terminate_timeout_cb, + term_data, + NULL), + main_context); +} diff --git a/src/libnm-glib-aux/nm-io-utils.h b/src/libnm-glib-aux/nm-io-utils.h index 2b132ff07d..98e63ac01e 100644 --- a/src/libnm-glib-aux/nm-io-utils.h +++ b/src/libnm-glib-aux/nm-io-utils.h @@ -56,4 +56,6 @@ struct stat; int nm_utils_file_stat(const char *filename, struct stat *out_st); +void nm_g_subprocess_terminate_in_background(GSubprocess *subprocess, int timeout_msec_before_kill); + #endif /* __NM_IO_UTILS_H__ */ |