bus: optionally call a callbacks for cleanup

This adds a function sd_bus_slot_set_destroy_callback() to set a function
which can free userdata or perform other cleanups.

sd_bus_slot_get_destory_callback() queries the callback, and is included
for completeness.

Without something like this, for floating asynchronous callbacks, which might
be called or not, depending on the sequence of events, it's hard to perform
resource cleanup. The alternative would be to always perform the cleanup from
the caller too, but that requires more coordination and keeping of some shared
state. It's nicer to keep the cleanup contained between the callback and the
function that requests the callback.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2018-06-06 11:07:02 +02:00
parent e3736e0223
commit fa17b4e8d9
7 changed files with 136 additions and 0 deletions

View File

@ -231,6 +231,10 @@ manpages = [
['sd_bus_set_connected_signal', '3', ['sd_bus_get_connected_signal'], ''],
['sd_bus_set_sender', '3', ['sd_bus_get_sender'], ''],
['sd_bus_set_watch_bind', '3', ['sd_bus_get_watch_bind'], ''],
['sd_bus_slot_set_destroy_callback',
'3',
['sd_bus_slot_get_destroy_callback'],
''],
['sd_bus_slot_set_floating', '3', ['sd_bus_slot_get_floating'], ''],
['sd_bus_track_add_name',
'3',

View File

@ -0,0 +1,105 @@
<?xml version='1.0'?> <!--*- Mode: nxml; nxml-child-indent: 2; indent-tabs-mode: nil -*-->
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
<!-- SPDX-License-Identifier: LGPL-2.1+ -->
<refentry id="sd_bus_slot_set_destroy_callback"
xmlns:xi="http://www.w3.org/2001/XInclude">
<refentryinfo>
<title>sd_bus_slot_set_destroy_callback</title>
<productname>systemd</productname>
</refentryinfo>
<refmeta>
<refentrytitle>sd_bus_slot_set_destroy_callback</refentrytitle>
<manvolnum>3</manvolnum>
</refmeta>
<refnamediv>
<refname>sd_bus_slot_set_destroy_callback</refname>
<refname>sd_bus_slot_get_destroy_callback</refname>
<refpurpose>Define the callback function for resource cleanup.</refpurpose>
</refnamediv>
<refsynopsisdiv>
<funcsynopsis>
<funcsynopsisinfo>#include &lt;systemd/sd-bus.h&gt;</funcsynopsisinfo>
<funcprototype>
<funcdef>typedef int (*<function>sd_bus_destroy_t</function>)</funcdef>
<paramdef>void *<parameter>userdata</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_bus_slot_set_destroy_callback</function></funcdef>
<paramdef>sd_bus_slot *<parameter>slot</parameter></paramdef>
<paramdef>sd_bus_destroy_t <parameter>callback</parameter></paramdef>
</funcprototype>
<funcprototype>
<funcdef>int <function>sd_bus_slot_get_destroy_callback</function></funcdef>
<paramdef>sd_bus_slot *<parameter>slot</parameter></paramdef>
<paramdef>sd_bus_destroy_t *<parameter>callback</parameter></paramdef>
</funcprototype>
</funcsynopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para><function>sd_bus_slot_set_destroy_callback()</function> sets
<parameter>callback</parameter> as the callback function to be called right before the bus slot
object <parameter>slot</parameter> is deallocated. The <parameter>userdata</parameter> pointer
from the slot object will be passed as the <parameter>userdata</parameter> parameter. This
pointer can be set specified as an argument to the constuctor functions, see
<citerefentry><refentrytitle>sd_bus_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
or directly, see
<citerefentry><refentrytitle>sd_bus_set_userdata</refentrytitle><manvolnum>3</manvolnum></citerefentry>.
This callback function is called even if <parameter>userdata</parameter> is
<constant>NULL</constant>.</para>
<para><function>sd_bus_slot_get_destroy_callback()</function> returns the current callback
for <parameter>slot</parameter> in the <parameter>callback</parameter> parameter.</para>
</refsect1>
<refsect1>
<title>Return Value</title>
<para>On success, <function>sd_bus_slot_set_destroy_callback()</function> returns 0 or a
positive integer. On failure, it returns a negative errno-style error code.</para>
<para><function>sd_bus_slot_get_destroy_callback()</function> returns 1 if the destroy callback
function is set, 0 if not. On failure, it returns a negative errno-style error code.</para>
</refsect1>
<refsect1>
<title>Errors</title>
<para>Returned errors may indicate the following problems:</para>
<variablelist>
<varlistentry>
<term><constant>-EINVAL</constant></term>
<listitem><para>The <parameter>slot</parameter> parameter is <constant>NULL</constant>.
</para></listitem>
</varlistentry>
</variablelist>
</refsect1>
<xi:include href="libsystemd-pkgconfig.xml" />
<refsect1>
<title>See Also</title>
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_slot_set_floating</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>
</refentry>

View File

@ -110,6 +110,7 @@
<para>
<citerefentry><refentrytitle>systemd</refentrytitle><manvolnum>1</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd-bus</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_slot_set_destroy_callback</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
<citerefentry><refentrytitle>sd_bus_add_match</refentrytitle><manvolnum>3</manvolnum></citerefentry>
</para>
</refsect1>

View File

@ -563,6 +563,8 @@ global:
sd_bus_open_system_with_description;
sd_bus_slot_get_floating;
sd_bus_slot_set_floating;
sd_bus_slot_get_destroy_callback;
sd_bus_slot_set_destroy_callback;
sd_event_add_inotify;
sd_event_source_get_inotify_mask;
} LIBSYSTEMD_238;

View File

@ -127,6 +127,7 @@ struct sd_bus_slot {
unsigned n_ref;
sd_bus *bus;
void *userdata;
sd_bus_destroy_t destroy_callback;
BusSlotType type:5;
/* Slots can be "floating" or not. If they are not floating (the usual case) then they reference the bus object

View File

@ -203,6 +203,10 @@ _public_ sd_bus_slot* sd_bus_slot_unref(sd_bus_slot *slot) {
}
bus_slot_disconnect(slot);
if (slot->destroy_callback)
slot->destroy_callback(slot->userdata);
free(slot->description);
return mfree(slot);
}
@ -230,6 +234,22 @@ _public_ void *sd_bus_slot_set_userdata(sd_bus_slot *slot, void *userdata) {
return ret;
}
_public_ int sd_bus_slot_set_destroy_callback(sd_bus_slot *slot, sd_bus_destroy_t callback) {
assert_return(slot, -EINVAL);
slot->destroy_callback = callback;
return 0;
}
_public_ int sd_bus_slot_get_destroy_callback(sd_bus_slot *slot, sd_bus_destroy_t *callback) {
assert_return(slot, -EINVAL);
if (callback)
*callback = slot->destroy_callback;
return !!slot->destroy_callback;
}
_public_ sd_bus_message *sd_bus_slot_get_current_message(sd_bus_slot *slot) {
assert_return(slot, NULL);
assert_return(slot->type >= 0, NULL);

View File

@ -111,6 +111,7 @@ typedef int (*sd_bus_property_set_t) (sd_bus *bus, const char *path, const char
typedef int (*sd_bus_object_find_t) (sd_bus *bus, const char *path, const char *interface, void *userdata, void **ret_found, sd_bus_error *ret_error);
typedef int (*sd_bus_node_enumerator_t) (sd_bus *bus, const char *prefix, void *userdata, char ***ret_nodes, sd_bus_error *ret_error);
typedef int (*sd_bus_track_handler_t) (sd_bus_track *track, void *userdata);
typedef void (*sd_bus_destroy_t)(void *userdata);
#include "sd-bus-protocol.h"
#include "sd-bus-vtable.h"
@ -230,6 +231,8 @@ int sd_bus_slot_set_description(sd_bus_slot *slot, const char *description);
int sd_bus_slot_get_description(sd_bus_slot *slot, const char **description);
int sd_bus_slot_get_floating(sd_bus_slot *slot);
int sd_bus_slot_set_floating(sd_bus_slot *slot, int b);
int sd_bus_slot_set_destroy_callback(sd_bus_slot *s, sd_bus_destroy_t callback);
int sd_bus_slot_get_destroy_callback(sd_bus_slot *s, sd_bus_destroy_t *callback);
sd_bus_message* sd_bus_slot_get_current_message(sd_bus_slot *slot);
sd_bus_message_handler_t sd_bus_slot_get_current_handler(sd_bus_slot *bus);