Implement dbus_clear_connection(), etc.
authorSimon McVittie <smcv@collabora.com>
Fri, 21 Jul 2017 18:12:30 +0000 (19:12 +0100)
committerSimon McVittie <smcv@debian.org>
Sun, 30 Jul 2017 07:48:43 +0000 (08:48 +0100)
These are inspired by GLib's g_clear_pointer() and g_clear_object(),
which in turn is descended from CPython's Py_CLEAR_OBJECT. They should
make our code a lot less repetitive.

Signed-off-by: Simon McVittie <smcv@collabora.com>
Reviewed-by: Philip Withnall <withnall@endlessm.com>
Bug: https://bugs.freedesktop.org/show_bug.cgi?id=101895

dbus/dbus-address.h
dbus/dbus-connection.h
dbus/dbus-hash.h
dbus/dbus-macros.h
dbus/dbus-message-internal.h
dbus/dbus-message.h
dbus/dbus-pending-call.h
dbus/dbus-server.h

index 4d14fdf..fefb320 100644 (file)
@@ -59,6 +59,25 @@ DBUS_EXPORT
 char* dbus_address_unescape_value (const char *value,
                                    DBusError  *error);
 
+/**
+ * Clear a variable or struct member that contains an array of #DBusAddressEntry.
+ * If it does not contain #NULL, the entries that were previously
+ * there are freed with dbus_address_entries_free().
+ *
+ * This is similar to dbus_clear_connection(): see that function
+ * for more details.
+ *
+ * @param pointer_to_entries A pointer to a variable or struct member.
+ * pointer_to_entries must not be #NULL, but *pointer_to_entries
+ * may be #NULL.
+ */
+static inline void
+dbus_clear_address_entries (DBusAddressEntry ***pointer_to_entries)
+{
+  _dbus_clear_pointer_impl (DBusAddressEntry *, pointer_to_entries,
+                            dbus_address_entries_free);
+}
+
 /** @} */
 
 DBUS_END_DECLS
index fe4d04e..bed5424 100644 (file)
@@ -28,6 +28,7 @@
 #define DBUS_CONNECTION_H
 
 #include <dbus/dbus-errors.h>
+#include <dbus/dbus-macros.h>
 #include <dbus/dbus-memory.h>
 #include <dbus/dbus-message.h>
 #include <dbus/dbus-shared.h>
@@ -438,6 +439,35 @@ DBUS_EXPORT
 dbus_bool_t dbus_connection_get_socket             (DBusConnection              *connection,
                                                     int                         *fd);
 
+/**
+ * Clear a variable or struct member that contains a #DBusConnection.
+ * If it does not contain #NULL, the connection that was previously
+ * there is unreferenced with dbus_connection_unref().
+ *
+ * For example, this function and the similar functions for
+ * other reference-counted types can be used in code like this:
+ *
+ * @code
+ * DBusConnection *conn = NULL;
+ * struct { ...; DBusMessage *m; ... } *larger_structure = ...;
+ *
+ * ... code that might set conn or m to be non-NULL ...
+ *
+ * dbus_clear_connection (&conn);
+ * dbus_clear_message (&larger_structure->m);
+ * @endcode
+ *
+ * @param pointer_to_connection A pointer to a variable or struct member.
+ * pointer_to_connection must not be #NULL, but *pointer_to_connection
+ * may be #NULL.
+ */
+static inline void
+dbus_clear_connection (DBusConnection **pointer_to_connection)
+{
+  _dbus_clear_pointer_impl (DBusConnection, pointer_to_connection,
+                            dbus_connection_unref);
+}
+
 /** @} */
 
 
index 93f717a..fadab91 100644 (file)
@@ -210,6 +210,12 @@ _dbus_hash_table_insert_pollable (DBusHashTable *table,
 #endif
 }
 
+static inline void
+_dbus_clear_hash_table (DBusHashTable **table_p)
+{
+  _dbus_clear_pointer_impl (DBusHashTable, table_p, _dbus_hash_table_unref);
+}
+
 /** @} */
 
 DBUS_END_DECLS
index 0e784fe..2c8956e 100644 (file)
 #  define DBUS_PRIVATE_EXPORT /* no decoration */
 #endif
 
+/* Implementation for dbus_clear_message() etc. This is not API,
+ * do not use it directly.
+ *
+ * We're using a specific type (T ** and T *) instead of void ** and
+ * void * partly for type-safety, partly to be strict-aliasing-compliant,
+ * and partly to keep C++ compilers happy. This code is inlined into
+ * users of libdbus, so we can't rely on it having dbus' own compiler
+ * settings. */
+#define _dbus_clear_pointer_impl(T, pointer_to_pointer, destroy) \
+  do { \
+    T **_pp = (pointer_to_pointer); \
+    T *_value = *_pp; \
+    \
+    *_pp = NULL; \
+    \
+    if (_value != NULL) \
+      destroy (_value); \
+  } while (0)
+/* Not (destroy) (_value) in case destroy() is a function-like macro */
+
 /** @} */
 
 #endif /* DBUS_MACROS_H */
index f8fe383..38c7923 100644 (file)
@@ -135,6 +135,12 @@ const DBusString  *_dbus_variant_peek                            (DBusVariant *s
 DBUS_PRIVATE_EXPORT
 const char        *_dbus_variant_get_signature                   (DBusVariant *self);
 
+static inline void
+_dbus_clear_variant (DBusVariant **variant_p)
+{
+  _dbus_clear_pointer_impl (DBusVariant, variant_p, _dbus_variant_free);
+}
+
 typedef struct DBusInitialFDs DBusInitialFDs;
 DBusInitialFDs *_dbus_check_fdleaks_enter (void);
 void            _dbus_check_fdleaks_leave (DBusInitialFDs *fds);
index 9e7ae7f..8a9d57a 100644 (file)
@@ -351,6 +351,25 @@ DBUS_EXPORT
 dbus_bool_t dbus_message_get_allow_interactive_authorization (
     DBusMessage *message);
 
+/**
+ * Clear a variable or struct member that contains a #DBusMessage.
+ * If it does not contain #NULL, the message that was previously
+ * there is unreferenced with dbus_message_unref().
+ *
+ * This is very similar to dbus_clear_connection(): see that function
+ * for more details.
+ *
+ * @param pointer_to_message A pointer to a variable or struct member.
+ * pointer_to_message must not be #NULL, but *pointer_to_message
+ * may be #NULL.
+ */
+static inline void
+dbus_clear_message (DBusMessage **pointer_to_message)
+{
+  _dbus_clear_pointer_impl (DBusMessage, pointer_to_message,
+                            dbus_message_unref);
+}
+
 /** @} */
 
 DBUS_END_DECLS
index 8a37ec0..5593397 100644 (file)
@@ -72,6 +72,25 @@ DBUS_EXPORT
 void*       dbus_pending_call_get_data           (DBusPendingCall  *pending,
                                                   dbus_int32_t      slot);
 
+/**
+ * Clear a variable or struct member that contains a #DBusPendingCall.
+ * If it does not contain #NULL, the pending call that was previously
+ * there is unreferenced with dbus_pending_call_unref().
+ *
+ * This is very similar to dbus_clear_connection(): see that function
+ * for more details.
+ *
+ * @param pointer_to_pending_call A pointer to a variable or struct member.
+ * pointer_to_pending_call must not be #NULL, but *pointer_to_pending_call
+ * may be #NULL.
+ */
+static inline void
+dbus_clear_pending_call (DBusPendingCall **pointer_to_pending_call)
+{
+  _dbus_clear_pointer_impl (DBusPendingCall, pointer_to_pending_call,
+                            dbus_pending_call_unref);
+}
+
 /** @} */
 
 DBUS_END_DECLS
index bdbefa0..7d8f04e 100644 (file)
@@ -28,6 +28,7 @@
 #define DBUS_SERVER_H
 
 #include <dbus/dbus-errors.h>
+#include <dbus/dbus-macros.h>
 #include <dbus/dbus-message.h>
 #include <dbus/dbus-connection.h>
 #include <dbus/dbus-protocol.h>
@@ -99,6 +100,24 @@ DBUS_EXPORT
 void*       dbus_server_get_data           (DBusServer       *server,
                                             int               slot);
 
+/**
+ * Clear a variable or struct member that contains a #DBusServer.
+ * If it does not contain #NULL, the server that was previously
+ * there is unreferenced with dbus_server_unref().
+ *
+ * This is very similar to dbus_clear_connection(): see that function
+ * for more details.
+ *
+ * @param pointer_to_server A pointer to a variable or struct member.
+ * pointer_to_server must not be #NULL, but *pointer_to_server
+ * may be #NULL.
+ */
+static inline void
+dbus_clear_server (DBusServer **pointer_to_server)
+{
+  _dbus_clear_pointer_impl (DBusServer, pointer_to_server, dbus_server_unref);
+}
+
 /** @} */
 
 DBUS_END_DECLS