From 6c5a227bcc7be280d3e59e6511bb4e67fe94dcb7 Mon Sep 17 00:00:00 2001 From: Simon McVittie Date: Mon, 22 Mar 2021 11:48:10 +0000 Subject: [PATCH] gmain: Add g_steal_fd() to API This is basically glnx_steal_fd() from libglnx. We already had two private implementations of it in GLib. Signed-off-by: Simon McVittie --- docs/reference/glib/glib-sections.txt | 3 +++ glib/gfileutils.c | 12 ++-------- glib/gmain.c | 20 +++++++++++++++++ glib/gmain.h | 9 ++++++++ glib/gspawn.c | 16 +++----------- glib/tests/mainloop.c | 32 +++++++++++++++++++++++++++ 6 files changed, 69 insertions(+), 23 deletions(-) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index 75994e889..c9697b45d 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -924,6 +924,9 @@ g_source_remove_by_user_data GClearHandleFunc g_clear_handle_id + +g_steal_fd + GLIB_HAVE_ALLOCA_H alloca diff --git a/glib/gfileutils.c b/glib/gfileutils.c index a4e90265e..e0a2a65d0 100644 --- a/glib/gfileutils.c +++ b/glib/gfileutils.c @@ -1208,14 +1208,6 @@ write_to_file (const gchar *contents, return TRUE; } -static inline int -steal_fd (int *fd_ptr) -{ - int fd = *fd_ptr; - *fd_ptr = -1; - return fd; -} - /** * g_file_set_contents: * @filename: (type filename): name of a file to write @contents to, in the GLib file name @@ -1369,7 +1361,7 @@ g_file_set_contents_full (const gchar *filename, } do_fsync = fd_should_be_fsynced (fd, filename, flags); - if (!write_to_file (contents, length, steal_fd (&fd), tmp_filename, do_fsync, error)) + if (!write_to_file (contents, length, g_steal_fd (&fd), tmp_filename, do_fsync, error)) { g_unlink (tmp_filename); retval = FALSE; @@ -1479,7 +1471,7 @@ consistent_out: } do_fsync = fd_should_be_fsynced (direct_fd, filename, flags); - if (!write_to_file (contents, length, steal_fd (&direct_fd), filename, + if (!write_to_file (contents, length, g_steal_fd (&direct_fd), filename, do_fsync, error)) return FALSE; } diff --git a/glib/gmain.c b/glib/gmain.c index 15581ee7a..2e1ab3a25 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -6122,3 +6122,23 @@ g_get_worker_context (void) return glib_worker_context; } + +/** + * g_steal_fd: + * @fd_ptr: (not optional) (inout): A pointer to a file descriptor + * + * Sets @fd_ptr to `-1`, returning the value that was there before. + * + * Conceptually, this transfers the ownership of the file descriptor + * from the referenced variable to the caller of the function (i.e. + * ‘steals’ the reference). This is very similar to g_steal_pointer(), + * but for file descriptors. + * + * On POSIX platforms, this function is async-signal safe + * (see [`signal(7)`](man:signal(7)) and + * [`signal-safety(7)`](man:signal-safety(7))), making it safe to call from a + * signal handler or a #GSpawnChildSetupFunc. + * + * Returns: the value that @fd_ptr previously had + * Since: 2.70 + */ diff --git a/glib/gmain.h b/glib/gmain.h index 5c0e524cc..22ea17876 100644 --- a/glib/gmain.h +++ b/glib/gmain.h @@ -781,6 +781,15 @@ void g_main_context_invoke (GMainContext *context, GSourceFunc function, gpointer data); +GLIB_AVAILABLE_STATIC_INLINE_IN_2_70 +static inline int +g_steal_fd (int *fd_ptr) +{ + int fd = *fd_ptr; + *fd_ptr = -1; + return fd; +} + /* Hook for GClosure / GSource integration. Don't touch */ GLIB_VAR GSourceFuncs g_timeout_funcs; GLIB_VAR GSourceFuncs g_child_watch_funcs; diff --git a/glib/gspawn.c b/glib/gspawn.c index 95f5b868e..1acf24058 100644 --- a/glib/gspawn.c +++ b/glib/gspawn.c @@ -249,16 +249,6 @@ g_spawn_async (const gchar *working_directory, error); } -/* This function is called between fork() and exec() and hence must be - * async-signal-safe (see signal-safety(7)). */ -static gint -steal_fd (gint *fd) -{ - gint fd_out = *fd; - *fd = -1; - return fd_out; -} - /* Avoids a danger in threaded situations (calling close() * on a file descriptor twice, and another thread has * re-opened it since the first close) @@ -2436,13 +2426,13 @@ success: close_and_invalidate (&stderr_pipe[1]); if (stdin_pipe_out != NULL) - *stdin_pipe_out = steal_fd (&stdin_pipe[1]); + *stdin_pipe_out = g_steal_fd (&stdin_pipe[1]); if (stdout_pipe_out != NULL) - *stdout_pipe_out = steal_fd (&stdout_pipe[0]); + *stdout_pipe_out = g_steal_fd (&stdout_pipe[0]); if (stderr_pipe_out != NULL) - *stderr_pipe_out = steal_fd (&stderr_pipe[0]); + *stderr_pipe_out = g_steal_fd (&stderr_pipe[0]); return TRUE; diff --git a/glib/tests/mainloop.c b/glib/tests/mainloop.c index d43b2cf08..e0ff04628 100644 --- a/glib/tests/mainloop.c +++ b/glib/tests/mainloop.c @@ -21,6 +21,7 @@ */ #include +#include #include "glib-private.h" #include #include @@ -2066,6 +2067,36 @@ test_maincontext_source_finalization_from_dispatch (gconstpointer user_data) g_main_context_unref (c); } +static void +test_steal_fd (void) +{ + GError *error = NULL; + gchar *tmpfile = NULL; + int fd = -42; + int borrowed; + int stolen; + + g_assert_cmpint (g_steal_fd (&fd), ==, -42); + g_assert_cmpint (fd, ==, -1); + g_assert_cmpint (g_steal_fd (&fd), ==, -1); + g_assert_cmpint (fd, ==, -1); + + fd = g_file_open_tmp (NULL, &tmpfile, &error); + g_assert_cmpint (fd, >=, 0); + g_assert_no_error (error); + borrowed = fd; + stolen = g_steal_fd (&fd); + g_assert_cmpint (fd, ==, -1); + g_assert_cmpint (borrowed, ==, stolen); + + g_close (g_steal_fd (&stolen), &error); + g_assert_no_error (error); + g_assert_cmpint (stolen, ==, -1); + + g_assert_no_errno (remove (tmpfile)); + g_free (tmpfile); +} + int main (int argc, char *argv[]) { @@ -2111,6 +2142,7 @@ main (int argc, char *argv[]) g_test_add_func ("/mainloop/unix-fd-priority", test_unix_fd_priority); #endif g_test_add_func ("/mainloop/nfds", test_nfds); + g_test_add_func ("/mainloop/steal-fd", test_steal_fd); return g_test_run (); }