Merge branch 'steal-handle-id' into 'main'

utils: Add g_steal_handle_id() to complement g_clear_handle_id()

See merge request GNOME/glib!4308
This commit is contained in:
Philip Withnall 2024-10-01 14:25:58 +00:00
commit 766f3414eb
8 changed files with 186 additions and 83 deletions

View File

@ -184,6 +184,11 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
* Since: 2.80
*/
GLIB_AVAILABLE_STATIC_INLINE_IN_2_80
static inline gboolean g_unix_pipe_open (GUnixPipe *self,
int flags,
GError **error);
GLIB_AVAILABLE_STATIC_INLINE_IN_2_80
static inline gboolean
g_unix_pipe_open (GUnixPipe *self,
int flags,
@ -212,6 +217,10 @@ g_unix_pipe_open (GUnixPipe *self,
* Since: 2.80
*/
GLIB_AVAILABLE_STATIC_INLINE_IN_2_80
static inline int g_unix_pipe_get (GUnixPipe *self,
GUnixPipeEnd end);
GLIB_AVAILABLE_STATIC_INLINE_IN_2_80
static inline int
g_unix_pipe_get (GUnixPipe *self,
GUnixPipeEnd end)
@ -241,6 +250,10 @@ g_unix_pipe_get (GUnixPipe *self,
* Since: 2.80
*/
GLIB_AVAILABLE_STATIC_INLINE_IN_2_80
static inline int g_unix_pipe_steal (GUnixPipe *self,
GUnixPipeEnd end);
GLIB_AVAILABLE_STATIC_INLINE_IN_2_80
static inline int
g_unix_pipe_steal (GUnixPipe *self,
GUnixPipeEnd end)
@ -276,6 +289,11 @@ g_unix_pipe_steal (GUnixPipe *self,
* Since: 2.80
*/
GLIB_AVAILABLE_STATIC_INLINE_IN_2_80
static inline gboolean g_unix_pipe_close (GUnixPipe *self,
GUnixPipeEnd end,
GError **error);
GLIB_AVAILABLE_STATIC_INLINE_IN_2_80
static inline gboolean
g_unix_pipe_close (GUnixPipe *self,
GUnixPipeEnd end,
@ -304,6 +322,9 @@ g_unix_pipe_close (GUnixPipe *self,
*
* Since: 2.80
*/
GLIB_AVAILABLE_STATIC_INLINE_IN_2_80
static inline void g_unix_pipe_clear (GUnixPipe *self);
GLIB_AVAILABLE_STATIC_INLINE_IN_2_80
static inline void
g_unix_pipe_clear (GUnixPipe *self)

View File

@ -6571,24 +6571,3 @@ 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 [func@GLib.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.
*
* This function preserves the value of `errno`.
*
* Returns: the value that @fd_ptr previously had
* Since: 2.70
*/

View File

@ -634,6 +634,9 @@ typedef void GMainContextPusher GLIB_AVAILABLE_TYPE_IN_2_64;
* Since: 2.64
*/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
GLIB_AVAILABLE_STATIC_INLINE_IN_2_64
static inline GMainContextPusher *g_main_context_pusher_new (GMainContext *main_context);
GLIB_AVAILABLE_STATIC_INLINE_IN_2_64
static inline GMainContextPusher *
g_main_context_pusher_new (GMainContext *main_context)
@ -656,6 +659,9 @@ G_GNUC_END_IGNORE_DEPRECATIONS
* Since: 2.64
*/
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
GLIB_AVAILABLE_STATIC_INLINE_IN_2_64
static inline void g_main_context_pusher_free (GMainContextPusher *pusher);
GLIB_AVAILABLE_STATIC_INLINE_IN_2_64
static inline void
g_main_context_pusher_free (GMainContextPusher *pusher)
@ -866,6 +872,54 @@ void g_clear_handle_id (guint *tag_ptr,
} G_STMT_END \
GLIB_AVAILABLE_MACRO_IN_2_56
/**
* g_steal_handle_id:
* @handle_pointer: (inout) (not optional): a pointer to a handle ID
*
* Sets @handle_pointer to `0`, returning the value that was there before.
*
* Conceptually, this transfers the ownership of the handle ID from the
* referenced variable to the caller of the macro (ie: steals the
* handle ID).
*
* This can be very useful to make ownership transfer explicit, or to prevent
* a handle from being released multiple times. For example:
*
* ```c
* void
* maybe_unsubscribe_signal (ContextStruct *data)
* {
* if (some_complex_logic (data))
* {
* g_dbus_connection_signal_unsubscribe (data->connection,
* g_steal_handle_id (&data->subscription_id));
* // now data->subscription_id isnt a dangling handle
* }
* }
* ```
*
* While [func@GLib.clear_handle_id] can be used in many of the same situations
* as `g_steal_handle_id()`, this is one situation where it cannot be used, as
* there is no way to pass the `GDBusConnection` to a
* [type@GLib.ClearHandleFunc].
*
* Since: 2.84
*/
GLIB_AVAILABLE_STATIC_INLINE_IN_2_84
static inline unsigned int g_steal_handle_id (unsigned int *handle_pointer);
GLIB_AVAILABLE_STATIC_INLINE_IN_2_84
static inline unsigned int
g_steal_handle_id (unsigned int *handle_pointer)
{
unsigned int handle;
handle = *handle_pointer;
*handle_pointer = 0;
return handle;
}
/* Idles, child watchers and timeouts */
GLIB_AVAILABLE_IN_ALL
guint g_timeout_add_full (gint priority,
@ -930,6 +984,30 @@ void g_main_context_invoke (GMainContext *context,
GSourceFunc function,
gpointer data);
/**
* 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 [func@GLib.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.
*
* This function preserves the value of `errno`.
*
* Returns: the value that @fd_ptr previously had
* Since: 2.70
*/
GLIB_AVAILABLE_STATIC_INLINE_IN_2_70
static inline int g_steal_fd (int *fd_ptr);
GLIB_AVAILABLE_STATIC_INLINE_IN_2_70
static inline int
g_steal_fd (int *fd_ptr)

View File

@ -229,6 +229,9 @@ void g_aligned_free_sized (gpointer mem,
*
* Since: 2.44
*/
GLIB_AVAILABLE_STATIC_INLINE_IN_2_44
static inline gpointer g_steal_pointer (gpointer pp);
GLIB_AVAILABLE_STATIC_INLINE_IN_2_44
static inline gpointer
g_steal_pointer (gpointer pp)

View File

@ -1841,68 +1841,6 @@ g_close (gint fd,
return TRUE;
}
/**
* g_clear_fd: (skip)
* @fd_ptr: (not optional) (inout) (transfer full): a pointer to a file descriptor
* @error: Used to return an error on failure
*
* If @fd_ptr points to a file descriptor, close it and return
* whether closing it was successful, like g_close().
* If @fd_ptr points to a negative number, return %TRUE without closing
* anything.
* In both cases, set @fd_ptr to `-1` before returning.
*
* Like g_close(), if closing the file descriptor fails, the error is
* stored in both %errno and @error. If this function succeeds,
* %errno is undefined.
*
* On POSIX platforms, this function is async-signal safe
* if @error is %NULL and @fd_ptr points to either a negative number or a
* valid open file descriptor.
* This makes it safe to call from a signal handler or a #GSpawnChildSetupFunc
* under those conditions.
* See [`signal(7)`](man:signal(7)) and
* [`signal-safety(7)`](man:signal-safety(7)) for more details.
*
* It is a programming error for @fd_ptr to point to a non-negative
* number that is not a valid file descriptor.
*
* A typical use of this function is to clean up a file descriptor at
* the end of its scope, whether it has been set successfully or not:
*
* |[
* gboolean
* operate_on_fd (GError **error)
* {
* gboolean ret = FALSE;
* int fd = -1;
*
* fd = open_a_fd (error);
*
* if (fd < 0)
* goto out;
*
* if (!do_something (fd, error))
* goto out;
*
* if (!g_clear_fd (&fd, error))
* goto out;
*
* ret = TRUE;
*
* out:
* // OK to call even if fd was never opened or was already closed
* g_clear_fd (&fd, NULL);
* return ret;
* }
* ]|
*
* This function is also useful in conjunction with #g_autofd.
*
* Returns: %TRUE on success
* Since: 2.76
*/
/**
* g_autofd: (skip)
*

View File

@ -179,6 +179,71 @@ GLIB_AVAILABLE_IN_2_36
gboolean g_close (gint fd,
GError **error);
/**
* g_clear_fd: (skip)
* @fd_ptr: (not optional) (inout) (transfer full): a pointer to a file descriptor
* @error: Used to return an error on failure
*
* If @fd_ptr points to a file descriptor, close it and return
* whether closing it was successful, like g_close().
* If @fd_ptr points to a negative number, return %TRUE without closing
* anything.
* In both cases, set @fd_ptr to `-1` before returning.
*
* Like g_close(), if closing the file descriptor fails, the error is
* stored in both %errno and @error. If this function succeeds,
* %errno is undefined.
*
* On POSIX platforms, this function is async-signal safe
* if @error is %NULL and @fd_ptr points to either a negative number or a
* valid open file descriptor.
* This makes it safe to call from a signal handler or a #GSpawnChildSetupFunc
* under those conditions.
* See [`signal(7)`](man:signal(7)) and
* [`signal-safety(7)`](man:signal-safety(7)) for more details.
*
* It is a programming error for @fd_ptr to point to a non-negative
* number that is not a valid file descriptor.
*
* A typical use of this function is to clean up a file descriptor at
* the end of its scope, whether it has been set successfully or not:
*
* |[
* gboolean
* operate_on_fd (GError **error)
* {
* gboolean ret = FALSE;
* int fd = -1;
*
* fd = open_a_fd (error);
*
* if (fd < 0)
* goto out;
*
* if (!do_something (fd, error))
* goto out;
*
* if (!g_clear_fd (&fd, error))
* goto out;
*
* ret = TRUE;
*
* out:
* // OK to call even if fd was never opened or was already closed
* g_clear_fd (&fd, NULL);
* return ret;
* }
* ]|
*
* This function is also useful in conjunction with #g_autofd.
*
* Returns: %TRUE on success
* Since: 2.76
*/
GLIB_AVAILABLE_STATIC_INLINE_IN_2_76
static inline gboolean g_clear_fd (int *fd_ptr,
GError **error);
GLIB_AVAILABLE_STATIC_INLINE_IN_2_76
static inline gboolean
g_clear_fd (int *fd_ptr,

View File

@ -476,6 +476,10 @@ gboolean g_ascii_string_to_unsigned (const gchar *str,
* Since: 2.76
*/
GLIB_AVAILABLE_STATIC_INLINE_IN_2_76
static inline gboolean g_set_str (char **str_pointer,
const char *new_str);
GLIB_AVAILABLE_STATIC_INLINE_IN_2_76
static inline gboolean
g_set_str (char **str_pointer,
const char *new_str)

View File

@ -1322,6 +1322,20 @@ test_clear_slist (void)
g_assert_null (slist);
}
static void
test_steal_handle_id (void)
{
unsigned int handle_id = 0;
g_assert_cmpuint (g_steal_handle_id (&handle_id), ==, 0);
g_assert_cmpuint (handle_id, ==, 0);
handle_id = 5; /* pretend this is a meaningful handle */
g_assert_cmpuint (g_steal_handle_id (&handle_id), ==, 5);
g_assert_cmpuint (handle_id, ==, 0);
}
int
main (int argc,
char *argv[])
@ -1382,6 +1396,7 @@ main (int argc,
g_test_add_func ("/utils/int-limits", test_int_limits);
g_test_add_func ("/utils/clear-list", test_clear_list);
g_test_add_func ("/utils/clear-slist", test_clear_slist);
g_test_add_func ("/utils/steal-handle-id", test_steal_handle_id);
return g_test_run ();
}