dbus: Optimize introspection to use single pass for interfaces

There is no need to go through methods, signals, and properties in
two loops and only collect interfaces in the first run. Get rid of
unnecessary CPU use by generating the XML data for interfaces with
a single pass.
This commit is contained in:
Jouni Malinen 2010-01-01 18:08:23 +02:00
parent ce4f7fdbdd
commit d316584c6a

View file

@ -30,26 +30,69 @@ struct interfaces {
};
static void add_interface(struct dl_list *list, const char *dbus_interface)
static struct interfaces * add_interface(struct dl_list *list,
const char *dbus_interface)
{
struct interfaces *iface;
dl_list_for_each(iface, list, struct interfaces, list) {
if (os_strcmp(iface->dbus_interface, dbus_interface) == 0)
return; /* already in the list */
return iface; /* already in the list */
}
iface = os_zalloc(sizeof(struct interfaces));
if (!iface)
return;
return NULL;
iface->xml = wpabuf_alloc(3000);
if (iface->xml == NULL) {
os_free(iface);
return;
return NULL;
}
wpabuf_printf(iface->xml, "<interface name=\"%s\">", dbus_interface);
dl_list_add_tail(list, &iface->list);
iface->dbus_interface = os_strdup(dbus_interface);
return iface;
}
static void add_arg(struct wpabuf *xml, const char *name, const char *type,
const char *direction)
{
wpabuf_printf(xml, "<arg name=\"%s\"", name);
if (type)
wpabuf_printf(xml, " type=\"%s\"", type);
if (direction)
wpabuf_printf(xml, " direction=\"%s\"", direction);
wpabuf_put_str(xml, "/>");
}
static void add_entry(struct wpabuf *xml, char *type, char *name, int args_num,
struct wpa_dbus_argument *args, int include_dir)
{
int i;
if (args_num == 0) {
wpabuf_printf(xml, "<%s name=\"%s\"/>", type, name);
return;
}
wpabuf_printf(xml, "<%s name=\"%s\">", type, name);
for (i = 0; i < args_num; i++) {
struct wpa_dbus_argument *arg = &args[i];
add_arg(xml, arg->name, arg->type,
include_dir ? (arg->dir == ARG_IN ? "in" : "out") :
NULL);
}
wpabuf_printf(xml, "</%s>", type);
}
static void add_property(struct wpabuf *xml,
struct wpa_dbus_property_desc *dsc)
{
wpabuf_printf(xml, "<property name=\"%s\" type=\"%s\" access=\"%s\"/>",
dsc->dbus_property, dsc->type,
(dsc->access == R ? "read" :
(dsc->access == W ? "write" : "readwrite")));
}
@ -57,8 +100,13 @@ static void extract_interfaces_methods(struct dl_list *list,
struct wpa_dbus_method_desc *methods)
{
struct wpa_dbus_method_desc *dsc;
for (dsc = methods; dsc; dsc = dsc->next)
add_interface(list, dsc->dbus_interface);
struct interfaces *iface;
for (dsc = methods; dsc; dsc = dsc->next) {
iface = add_interface(list, dsc->dbus_interface);
if (iface)
add_entry(iface->xml, "method", dsc->dbus_method,
dsc->args_num, dsc->args, 1);
}
}
@ -66,8 +114,13 @@ static void extract_interfaces_signals(struct dl_list *list,
struct wpa_dbus_signal_desc *signals)
{
struct wpa_dbus_signal_desc *dsc;
for (dsc = signals; dsc; dsc = dsc->next)
add_interface(list, dsc->dbus_interface);
struct interfaces *iface;
for (dsc = signals; dsc; dsc = dsc->next) {
iface = add_interface(list, dsc->dbus_interface);
if (iface)
add_entry(iface->xml, "signal", dsc->dbus_signal,
dsc->args_num, dsc->args, 0);
}
}
@ -75,8 +128,12 @@ static void extract_interfaces_properties(
struct dl_list *list, struct wpa_dbus_property_desc *properties)
{
struct wpa_dbus_property_desc *dsc;
for (dsc = properties; dsc; dsc = dsc->next)
add_interface(list, dsc->dbus_interface);
struct interfaces *iface;
for (dsc = properties; dsc; dsc = dsc->next) {
iface = add_interface(list, dsc->dbus_interface);
if (iface)
add_property(iface->xml, dsc);
}
}
@ -103,8 +160,10 @@ static void add_interfaces(struct dl_list *list, struct wpabuf *xml)
{
struct interfaces *iface, *n;
dl_list_for_each_safe(iface, n, list, struct interfaces, list) {
if (wpabuf_len(iface->xml) + 20 < wpabuf_tailroom(xml)) {
wpabuf_put_buf(xml, iface->xml);
wpabuf_put_str(xml, "</interface>");
}
dl_list_del(&iface->list);
wpabuf_free(iface->xml);
os_free(iface->dbus_interface);
@ -113,18 +172,6 @@ static void add_interfaces(struct dl_list *list, struct wpabuf *xml)
}
static struct interfaces * get_interface(struct dl_list *list,
const char *dbus_interface)
{
struct interfaces *iface;
dl_list_for_each(iface, list, struct interfaces, list) {
if (os_strcmp(iface->dbus_interface, dbus_interface) == 0)
return iface;
}
return NULL;
}
static void add_child_nodes(struct wpabuf *xml, DBusConnection *con,
const char *path)
{
@ -139,18 +186,6 @@ static void add_child_nodes(struct wpabuf *xml, DBusConnection *con,
}
static void add_arg(struct wpabuf *xml, const char *name, const char *type,
const char *direction)
{
wpabuf_printf(xml, "<arg name=\"%s\"", name);
if (type)
wpabuf_printf(xml, " type=\"%s\"", type);
if (direction)
wpabuf_printf(xml, " direction=\"%s\"", direction);
wpabuf_put_str(xml, "/>");
}
static void add_introspectable_interface(struct wpabuf *xml)
{
wpabuf_printf(xml, "<interface name=\"%s\">"
@ -189,91 +224,12 @@ static void add_properties_interface(struct wpabuf *xml)
}
static void add_entry(struct wpabuf *xml, char *type, char *name, int args_num,
struct wpa_dbus_argument *args, int include_dir)
{
int i;
if (args_num == 0) {
wpabuf_printf(xml, "<%s name=\"%s\"/>", type, name);
return;
}
wpabuf_printf(xml, "<%s name=\"%s\">", type, name);
for (i = 0; i < args_num; i++) {
struct wpa_dbus_argument *arg = &args[i];
add_arg(xml, arg->name, arg->type,
include_dir ? (arg->dir == ARG_IN ? "in" : "out") :
NULL);
}
wpabuf_printf(xml, "</%s>", type);
}
static void add_property(struct wpabuf *xml,
struct wpa_dbus_property_desc *dsc)
{
wpabuf_printf(xml, "<property name=\"%s\" type=\"%s\" access=\"%s\"/>",
dsc->dbus_property, dsc->type,
(dsc->access == R ? "read" :
(dsc->access == W ? "write" : "readwrite")));
}
static void create_method_nodes(struct dl_list *list,
struct wpa_dbus_method_desc *methods)
{
struct wpa_dbus_method_desc *dsc;
struct interfaces *iface;
for (dsc = methods; dsc; dsc = dsc->next) {
iface = get_interface(list, dsc->dbus_interface);
if (!iface)
continue;
add_entry(iface->xml, "method", dsc->dbus_method,
dsc->args_num, dsc->args, 1);
}
}
static void create_signal_nodes(struct dl_list *list,
struct wpa_dbus_signal_desc *signals)
{
struct wpa_dbus_signal_desc *dsc;
struct interfaces *iface;
for (dsc = signals; dsc; dsc = dsc->next) {
iface = get_interface(list, dsc->dbus_interface);
if (!iface)
continue;
add_entry(iface->xml, "signal", dsc->dbus_signal,
dsc->args_num, dsc->args, 0);
}
}
static void create_property_nodes(struct dl_list *list,
struct wpa_dbus_property_desc *properties)
{
struct wpa_dbus_property_desc *dsc;
struct interfaces *iface;
for (dsc = properties; dsc; dsc = dsc->next) {
iface = get_interface(list, dsc->dbus_interface);
if (!iface)
continue;
add_property(iface->xml, dsc);
}
}
static void add_wpas_interfaces(struct wpabuf *xml,
struct wpa_dbus_object_desc *obj_dsc)
{
struct dl_list ifaces;
dl_list_init(&ifaces);
extract_interfaces(&ifaces, obj_dsc);
create_method_nodes(&ifaces, obj_dsc->methods);
create_signal_nodes(&ifaces, obj_dsc->signals);
create_property_nodes(&ifaces, obj_dsc->properties);
add_interfaces(&ifaces, xml);
}
@ -293,7 +249,6 @@ DBusMessage * wpa_dbus_introspect(DBusMessage *message,
DBusMessage *reply;
struct wpabuf *xml;
const char *intro_str;
xml = wpabuf_alloc(4000);
if (xml == NULL)
@ -306,20 +261,17 @@ DBusMessage * wpa_dbus_introspect(DBusMessage *message,
add_introspectable_interface(xml);
add_properties_interface(xml);
add_wpas_interfaces(xml, obj_dsc);
add_child_nodes(xml, obj_dsc->connection,
dbus_message_get_path(message));
wpabuf_put_str(xml, "</node>\n");
reply = dbus_message_new_method_return(message);
if (reply == NULL) {
wpabuf_free(xml);
return NULL;
}
intro_str = wpabuf_head(xml);
if (reply) {
const char *intro_str = wpabuf_head(xml);
dbus_message_append_args(reply, DBUS_TYPE_STRING, &intro_str,
DBUS_TYPE_INVALID);
}
wpabuf_free(xml);
return reply;