mirror of git://git.sysmocom.de/ofono
gdbus: Group interface changes to reduce the amount of signals emitted
InterfacesAdded and InterfacesRemoved can group all the interfaces changes together in one message.
This commit is contained in:
parent
7db2a0bfcc
commit
f28e6ae984
366
gdbus/object.c
366
gdbus/object.c
|
@ -45,6 +45,9 @@ struct generic_data {
|
|||
char *path;
|
||||
GSList *interfaces;
|
||||
GSList *objects;
|
||||
GSList *added;
|
||||
GSList *removed;
|
||||
guint process_id;
|
||||
char *introspect;
|
||||
struct generic_data *parent;
|
||||
};
|
||||
|
@ -70,6 +73,8 @@ struct property_data {
|
|||
DBusMessage *message;
|
||||
};
|
||||
|
||||
static gboolean process_changes(gpointer user_data);
|
||||
|
||||
static void print_arguments(GString *gstr, const GDBusArgInfo *args,
|
||||
const char *direction)
|
||||
{
|
||||
|
@ -491,21 +496,71 @@ static void reset_parent(gpointer data, gpointer user_data)
|
|||
child->parent = parent;
|
||||
}
|
||||
|
||||
static void generic_unregister(DBusConnection *connection, void *user_data)
|
||||
static void append_properties(struct interface_data *data,
|
||||
DBusMessageIter *iter)
|
||||
{
|
||||
struct generic_data *data = user_data;
|
||||
DBusMessageIter dict;
|
||||
|
||||
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
|
||||
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
||||
DBUS_TYPE_STRING_AS_STRING
|
||||
DBUS_TYPE_VARIANT_AS_STRING
|
||||
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
|
||||
|
||||
/* TODO: list properties */
|
||||
|
||||
dbus_message_iter_close_container(iter, &dict);
|
||||
}
|
||||
|
||||
static void append_interface(gpointer data, gpointer user_data)
|
||||
{
|
||||
struct interface_data *iface = data;
|
||||
DBusMessageIter *array = user_data;
|
||||
DBusMessageIter entry;
|
||||
|
||||
dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
|
||||
&entry);
|
||||
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &iface->name);
|
||||
append_properties(data, &entry);
|
||||
dbus_message_iter_close_container(array, &entry);
|
||||
}
|
||||
|
||||
static void emit_interfaces_added(struct generic_data *data)
|
||||
{
|
||||
DBusMessage *signal;
|
||||
DBusMessageIter iter, array;
|
||||
struct generic_data *parent = data->parent;
|
||||
|
||||
if (parent != NULL)
|
||||
parent->objects = g_slist_remove(parent->objects, data);
|
||||
if (parent == NULL)
|
||||
return;
|
||||
|
||||
g_slist_foreach(data->objects, reset_parent, data->parent);
|
||||
g_slist_free(data->objects);
|
||||
signal = dbus_message_new_signal(parent->path,
|
||||
DBUS_INTERFACE_OBJECT_MANAGER,
|
||||
"InterfacesAdded");
|
||||
if (signal == NULL)
|
||||
return;
|
||||
|
||||
dbus_connection_unref(data->conn);
|
||||
g_free(data->introspect);
|
||||
g_free(data->path);
|
||||
g_free(data);
|
||||
dbus_message_iter_init_append(signal, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
|
||||
&data->path);
|
||||
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
||||
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
||||
DBUS_TYPE_STRING_AS_STRING
|
||||
DBUS_TYPE_ARRAY_AS_STRING
|
||||
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
||||
DBUS_TYPE_STRING_AS_STRING
|
||||
DBUS_TYPE_VARIANT_AS_STRING
|
||||
DBUS_DICT_ENTRY_END_CHAR_AS_STRING
|
||||
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
|
||||
|
||||
g_slist_foreach(data->added, append_interface, &array);
|
||||
g_slist_free(data->added);
|
||||
data->added = NULL;
|
||||
|
||||
dbus_message_iter_close_container(&iter, &array);
|
||||
|
||||
g_dbus_send_message(data->conn, signal);
|
||||
}
|
||||
|
||||
static struct interface_data *find_interface(GSList *interfaces,
|
||||
|
@ -546,45 +601,37 @@ static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static DBusHandlerResult generic_message(DBusConnection *connection,
|
||||
DBusMessage *message, void *user_data)
|
||||
static gboolean remove_interface(struct generic_data *data, const char *name)
|
||||
{
|
||||
struct generic_data *data = user_data;
|
||||
struct interface_data *iface;
|
||||
const GDBusMethodTable *method;
|
||||
const char *interface;
|
||||
|
||||
interface = dbus_message_get_interface(message);
|
||||
|
||||
iface = find_interface(data->interfaces, interface);
|
||||
iface = find_interface(data->interfaces, name);
|
||||
if (iface == NULL)
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
return FALSE;
|
||||
|
||||
for (method = iface->methods; method &&
|
||||
method->name && method->function; method++) {
|
||||
if (dbus_message_is_method_call(message, iface->name,
|
||||
method->name) == FALSE)
|
||||
continue;
|
||||
data->interfaces = g_slist_remove(data->interfaces, iface);
|
||||
|
||||
if (g_dbus_args_have_signature(method->in_args,
|
||||
message) == FALSE)
|
||||
continue;
|
||||
|
||||
if (check_privilege(connection, message, method,
|
||||
iface->user_data) == TRUE)
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
|
||||
return process_message(connection, message, method,
|
||||
iface->user_data);
|
||||
if (iface->destroy) {
|
||||
iface->destroy(iface->user_data);
|
||||
iface->user_data = NULL;
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
if (data->parent == NULL) {
|
||||
g_free(iface->name);
|
||||
g_free(iface);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static DBusObjectPathVTable generic_table = {
|
||||
.unregister_function = generic_unregister,
|
||||
.message_function = generic_message,
|
||||
};
|
||||
data->removed = g_slist_prepend(data->removed, iface->name);
|
||||
g_free(iface);
|
||||
|
||||
if (data->process_id > 0)
|
||||
return TRUE;
|
||||
|
||||
data->process_id = g_idle_add(process_changes, data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static struct generic_data *invalidate_parent_data(DBusConnection *conn,
|
||||
const char *child_path)
|
||||
|
@ -636,12 +683,6 @@ done:
|
|||
return data;
|
||||
}
|
||||
|
||||
static const GDBusMethodTable introspect_methods[] = {
|
||||
{ GDBUS_METHOD("Introspect", NULL,
|
||||
GDBUS_ARGS({ "xml", "s" }), introspect) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static inline const GDBusPropertyTable *find_property(const GDBusPropertyTable *properties,
|
||||
const char *name)
|
||||
{
|
||||
|
@ -860,35 +901,128 @@ static const GDBusSignalTable properties_signals[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static void append_properties(struct interface_data *data,
|
||||
DBusMessageIter *iter)
|
||||
static void append_name(gpointer data, gpointer user_data)
|
||||
{
|
||||
DBusMessageIter dict;
|
||||
char *name = data;
|
||||
DBusMessageIter *iter = user_data;
|
||||
|
||||
dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
|
||||
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
||||
DBUS_TYPE_STRING_AS_STRING
|
||||
DBUS_TYPE_VARIANT_AS_STRING
|
||||
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
|
||||
|
||||
/* TODO: list properties */
|
||||
|
||||
dbus_message_iter_close_container(iter, &dict);
|
||||
dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &name);
|
||||
}
|
||||
|
||||
static void append_interface(gpointer data, gpointer user_data)
|
||||
static void emit_interfaces_removed(struct generic_data *data)
|
||||
{
|
||||
struct interface_data *iface = data;
|
||||
DBusMessageIter *array = user_data;
|
||||
DBusMessageIter entry;
|
||||
DBusMessage *signal;
|
||||
DBusMessageIter iter, array;
|
||||
struct generic_data *parent = data->parent;
|
||||
|
||||
dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
|
||||
&entry);
|
||||
dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &iface->name);
|
||||
append_properties(data, &entry);
|
||||
dbus_message_iter_close_container(array, &entry);
|
||||
if (parent == NULL)
|
||||
return;
|
||||
|
||||
signal = dbus_message_new_signal(parent->path,
|
||||
DBUS_INTERFACE_OBJECT_MANAGER,
|
||||
"InterfacesRemoved");
|
||||
if (signal == NULL)
|
||||
return;
|
||||
|
||||
dbus_message_iter_init_append(signal, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
|
||||
&data->path);
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_STRING_AS_STRING, &array);
|
||||
|
||||
g_slist_foreach(data->removed, append_name, &array);
|
||||
g_slist_free_full(data->removed, g_free);
|
||||
data->removed = NULL;
|
||||
|
||||
dbus_message_iter_close_container(&iter, &array);
|
||||
|
||||
g_dbus_send_message(data->conn, signal);
|
||||
}
|
||||
|
||||
static gboolean process_changes(gpointer user_data)
|
||||
{
|
||||
struct generic_data *data = user_data;
|
||||
|
||||
data->process_id = 0;
|
||||
|
||||
if (data->added != NULL)
|
||||
emit_interfaces_added(data);
|
||||
|
||||
if (data->removed != NULL)
|
||||
emit_interfaces_removed(data);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void generic_unregister(DBusConnection *connection, void *user_data)
|
||||
{
|
||||
struct generic_data *data = user_data;
|
||||
struct generic_data *parent = data->parent;
|
||||
|
||||
if (parent != NULL)
|
||||
parent->objects = g_slist_remove(parent->objects, data);
|
||||
|
||||
if (data->process_id > 0) {
|
||||
g_source_remove(data->process_id);
|
||||
if (data->removed != NULL)
|
||||
emit_interfaces_removed(data);
|
||||
}
|
||||
|
||||
g_slist_foreach(data->objects, reset_parent, data->parent);
|
||||
g_slist_free(data->objects);
|
||||
|
||||
dbus_connection_unref(data->conn);
|
||||
g_free(data->introspect);
|
||||
g_free(data->path);
|
||||
g_free(data);
|
||||
}
|
||||
|
||||
static DBusHandlerResult generic_message(DBusConnection *connection,
|
||||
DBusMessage *message, void *user_data)
|
||||
{
|
||||
struct generic_data *data = user_data;
|
||||
struct interface_data *iface;
|
||||
const GDBusMethodTable *method;
|
||||
const char *interface;
|
||||
|
||||
interface = dbus_message_get_interface(message);
|
||||
|
||||
iface = find_interface(data->interfaces, interface);
|
||||
if (iface == NULL)
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
|
||||
for (method = iface->methods; method &&
|
||||
method->name && method->function; method++) {
|
||||
if (dbus_message_is_method_call(message, iface->name,
|
||||
method->name) == FALSE)
|
||||
continue;
|
||||
|
||||
if (g_dbus_args_have_signature(method->in_args,
|
||||
message) == FALSE)
|
||||
continue;
|
||||
|
||||
if (check_privilege(connection, message, method,
|
||||
iface->user_data) == TRUE)
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
|
||||
return process_message(connection, message, method,
|
||||
iface->user_data);
|
||||
}
|
||||
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
}
|
||||
|
||||
static DBusObjectPathVTable generic_table = {
|
||||
.unregister_function = generic_unregister,
|
||||
.message_function = generic_message,
|
||||
};
|
||||
|
||||
static const GDBusMethodTable introspect_methods[] = {
|
||||
{ GDBUS_METHOD("Introspect", NULL,
|
||||
GDBUS_ARGS({ "xml", "s" }), introspect) },
|
||||
{ }
|
||||
};
|
||||
|
||||
static void append_interfaces(struct generic_data *data, DBusMessageIter *iter)
|
||||
{
|
||||
DBusMessageIter array;
|
||||
|
@ -973,43 +1107,6 @@ static const GDBusSignalTable manager_signals[] = {
|
|||
{ }
|
||||
};
|
||||
|
||||
static void emit_interface_added(struct generic_data *data,
|
||||
struct interface_data *iface)
|
||||
{
|
||||
DBusMessage *signal;
|
||||
DBusMessageIter iter, array;
|
||||
struct generic_data *parent = data->parent;
|
||||
|
||||
if (parent == NULL)
|
||||
return;
|
||||
|
||||
signal = dbus_message_new_signal(parent->path,
|
||||
DBUS_INTERFACE_OBJECT_MANAGER,
|
||||
"InterfacesAdded");
|
||||
if (signal == NULL)
|
||||
return;
|
||||
|
||||
dbus_message_iter_init_append(signal, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
|
||||
&data->path);
|
||||
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
||||
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
||||
DBUS_TYPE_STRING_AS_STRING
|
||||
DBUS_TYPE_ARRAY_AS_STRING
|
||||
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
|
||||
DBUS_TYPE_STRING_AS_STRING
|
||||
DBUS_TYPE_VARIANT_AS_STRING
|
||||
DBUS_DICT_ENTRY_END_CHAR_AS_STRING
|
||||
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
|
||||
|
||||
append_interface(iface, &array);
|
||||
|
||||
dbus_message_iter_close_container(&iter, &array);
|
||||
|
||||
g_dbus_send_message(data->conn, signal);
|
||||
}
|
||||
|
||||
static void add_interface(struct generic_data *data,
|
||||
const char *name,
|
||||
const GDBusMethodTable *methods,
|
||||
|
@ -1029,8 +1126,14 @@ static void add_interface(struct generic_data *data,
|
|||
iface->destroy = destroy;
|
||||
|
||||
data->interfaces = g_slist_append(data->interfaces, iface);
|
||||
if (data->parent == NULL)
|
||||
return;
|
||||
|
||||
emit_interface_added(data, iface);
|
||||
data->added = g_slist_append(data->added, iface);
|
||||
if (data->process_id > 0)
|
||||
return;
|
||||
|
||||
data->process_id = g_idle_add(process_changes, data);
|
||||
}
|
||||
|
||||
static struct generic_data *object_path_ref(DBusConnection *connection,
|
||||
|
@ -1074,55 +1177,6 @@ static struct generic_data *object_path_ref(DBusConnection *connection,
|
|||
return data;
|
||||
}
|
||||
|
||||
static void emit_interface_remove(struct generic_data *data,
|
||||
struct interface_data *iface)
|
||||
{
|
||||
DBusMessage *signal;
|
||||
DBusMessageIter iter, array;
|
||||
struct generic_data *parent = data->parent;
|
||||
|
||||
if (parent == NULL)
|
||||
return;
|
||||
|
||||
signal = dbus_message_new_signal(parent->path,
|
||||
DBUS_INTERFACE_OBJECT_MANAGER,
|
||||
"InterfacesRemoved");
|
||||
if (signal == NULL)
|
||||
return;
|
||||
|
||||
dbus_message_iter_init_append(signal, &iter);
|
||||
dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
|
||||
&data->path);
|
||||
|
||||
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
|
||||
DBUS_TYPE_STRING_AS_STRING, &array);
|
||||
dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &iface->name);
|
||||
dbus_message_iter_close_container(&iter, &array);
|
||||
|
||||
g_dbus_send_message(data->conn, signal);
|
||||
}
|
||||
|
||||
static gboolean remove_interface(struct generic_data *data, const char *name)
|
||||
{
|
||||
struct interface_data *iface;
|
||||
|
||||
iface = find_interface(data->interfaces, name);
|
||||
if (iface == NULL)
|
||||
return FALSE;
|
||||
|
||||
emit_interface_remove(data, iface);
|
||||
|
||||
data->interfaces = g_slist_remove(data->interfaces, iface);
|
||||
|
||||
if (iface->destroy)
|
||||
iface->destroy(iface->user_data);
|
||||
|
||||
g_free(iface->name);
|
||||
g_free(iface);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void object_path_unref(DBusConnection *connection, const char *path)
|
||||
{
|
||||
struct generic_data *data = NULL;
|
||||
|
@ -1143,9 +1197,9 @@ static void object_path_unref(DBusConnection *connection, const char *path)
|
|||
remove_interface(data, DBUS_INTERFACE_PROPERTIES);
|
||||
remove_interface(data, DBUS_INTERFACE_OBJECT_MANAGER);
|
||||
|
||||
invalidate_parent_data(connection, path);
|
||||
invalidate_parent_data(data->conn, data->path);
|
||||
|
||||
dbus_connection_unregister_object_path(connection, path);
|
||||
dbus_connection_unregister_object_path(data->conn, data->path);
|
||||
}
|
||||
|
||||
static gboolean check_signal(DBusConnection *conn, const char *path,
|
||||
|
@ -1270,7 +1324,7 @@ gboolean g_dbus_unregister_interface(DBusConnection *connection,
|
|||
g_free(data->introspect);
|
||||
data->introspect = NULL;
|
||||
|
||||
object_path_unref(connection, path);
|
||||
object_path_unref(connection, data->path);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue