Rather than doing a full lookup in the kernel when creating a new family
object, we can use a previous lookup that matches our family name. Several
API changes were introduced in order for this to work cleanly.
l_genl_family_new was removed, and instead l_genl_get_family should be used.
This is an async function that returns the l_genl_family object in the
callback. This better matches how the lookup actually works. Because of this
l_genl_set_watches was also removed (since the "appeared" callback is now
provided directly to l_genl_get_family, "vanished" callback is explained
further below). It is up to the caller to manage the l_genl_family object
memory (genl does not keep a list of created family objects).
l_genl_family_set_watches was removed in place of l_genl_add_destroy_watch.
This is a watch on the genl object rather than on each family object. This
watchlist will get notified if the genl object disappears.
l_genl_family_[ref|unref] were both removed as they no longer made sense.
l_genl_family objects should now be cleaned up with l_genl_family_destroy.
The main intent with this patch is for each module that requires genl to
"get" its own family object and send messages on that object rather than
a shared global object. This, in most cases, will remove the need for
command ID message tracking since messages on a family object can be
canceled without affecting other family objects under the same name using
l_genl_family_cancel_all.
Internally, the l_genl_family object is now a thin struct containing only
a pointer back to the parent and a group ID. The parent object
(genl_family_internal) now holds all the lookup information for a given
name. If a new family is requested and a parent object already exists
then we do not need to lookup the family in the kernel then the new
l_genl_family object is returned in the callback. All l_genl_family
objects are tagged with a unique group ID (gid), and any messages sent
on that family are also tagged with the same gid. This allows cancelling
all messages by gid, which leaves other l_genl_family messages untouched,
even if they are under the same family name.
---
ell/genl.c | 505 +++++++++++++++++++++++++++++++++++------------------
ell/genl.h | 26 +--
2 files changed, 353 insertions(+), 178 deletions(-)
diff --git a/ell/genl.c b/ell/genl.c
index 3a0281a..b38d044 100644
--- a/ell/genl.c
+++ b/ell/genl.c
@@ -2,7 +2,7 @@
*
* Embedded Linux library
*
- * Copyright (C) 2011-2014 Intel Corporation. All rights reserved.
+ * Copyright (C) 2011-2018 Intel Corporation. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -36,6 +36,8 @@
#include "genl.h"
#include "genl-private.h"
#include "private.h"
+#include "watchlist.h"
+#include "idle.h"
#define MAX_NESTING_LEVEL 4
@@ -63,12 +65,14 @@ struct l_genl {
struct l_queue *notify_list;
unsigned int next_request_id;
unsigned int next_notify_id;
+ unsigned int next_gid;
struct l_queue *family_list;
- struct l_genl_family *nlctrl;
+ struct genl_family_internal *nlctrl;
struct genl_unicast_notify *unicast_notify;
l_genl_debug_func_t debug_callback;
l_genl_destroy_func_t debug_destroy;
void *debug_data;
+ struct l_watchlist destroy_watches;
};
struct l_genl_msg {
@@ -85,6 +89,7 @@ struct l_genl_msg {
struct genl_request {
unsigned int id;
+ unsigned int gid;
uint16_t type;
uint16_t flags;
uint32_t seq;
@@ -114,8 +119,8 @@ struct genl_mcast {
unsigned int users;
};
-struct l_genl_family {
- int ref_count;
+struct genl_family_internal {
+ unsigned int ref_count;
struct l_genl *genl;
char name[GENL_NAMSIZ];
uint16_t id;
@@ -124,11 +129,21 @@ struct l_genl_family {
uint32_t maxattr;
struct l_queue *op_list;
struct l_queue *mcast_list;
- l_genl_watch_func_t watch_appeared;
- l_genl_watch_func_t watch_vanished;
- l_genl_destroy_func_t watch_destroy;
- void *watch_data;
unsigned int nlctrl_cmd;
+ struct l_queue *pending_lookups;
+ bool live;
+};
+
+struct l_genl_family {
+ struct genl_family_internal *internal;
+ unsigned int gid;
+};
+
+struct cb_data {
+ l_genl_get_family_func_t cb;
+ l_genl_destroy_func_t destroy;
+ struct l_genl_family *family;
+ void *user_data;
};
static void destroy_request(void *data)
@@ -153,20 +168,42 @@ static void destroy_notify(void *data)
l_free(notify);
}
-static struct l_genl_family *family_alloc(struct l_genl *genl,
- const char *name)
+static struct genl_family_internal *family_internal_ref(
+ struct genl_family_internal *internal)
{
- struct l_genl_family *family;
+ if (unlikely(!internal))
+ return NULL;
- family = l_new(struct l_genl_family, 1);
+ __sync_fetch_and_add(&internal->ref_count, 1);
- family->genl = genl;
- strncpy(family->name, name, GENL_NAMSIZ);
+ return internal;
+}
+
+static struct l_genl_family *family_alloc(
+ struct genl_family_internal *internal)
+{
+ struct l_genl_family *family = l_new(struct l_genl_family, 1);
- family->op_list = l_queue_new();
- family->mcast_list = l_queue_new();
+ family->internal = family_internal_ref(internal);
+ family->gid = ++internal->genl->next_gid;
- return l_genl_family_ref(family);
+ return family;
+}
+
+static struct genl_family_internal *family_alloc_internal(struct l_genl *genl,
+ const char *name)
+{
+ struct genl_family_internal *internal = l_new(
+ struct genl_family_internal, 1);
+
+ internal->genl = l_genl_ref(genl);
+ strncpy(internal->name, name, GENL_NAMSIZ);
+
+ internal->op_list = l_queue_new();
+ internal->mcast_list = l_queue_new();
+ internal->pending_lookups = l_queue_new();
+
+ return internal;
}
static void op_free(void *data)
@@ -191,16 +228,56 @@ static void mcast_free(void *data, void *user_data)
l_free(mcast);
}
-static void family_free(void *data)
+static void destroy_lookups(void *user_data)
{
- struct l_genl_family *family = data;
+ struct cb_data *cbd = user_data;
- family->genl = NULL;
+ if (cbd->destroy)
+ cbd->destroy(cbd->user_data);
- l_genl_family_unref(family);
+ l_free(cbd->family);
+ l_free(cbd);
}
-static void family_add_op(struct l_genl_family *family, uint32_t id,
+static void internal_free(void *data)
+{
+ struct genl_family_internal *internal = data;
+ struct l_genl *genl = internal->genl;
+
+ if (internal->pending_lookups) {
+ l_queue_destroy(internal->pending_lookups, destroy_lookups);
+ internal->pending_lookups = NULL;
+ }
+
+ l_queue_destroy(internal->op_list, op_free);
+
+ l_queue_foreach(internal->mcast_list, mcast_free, internal->genl);
+ l_queue_destroy(internal->mcast_list, NULL);
+ internal->mcast_list = NULL;
+
+ l_genl_unref(genl);
+
+ l_free(internal);
+}
+
+static void family_internal_unref(struct genl_family_internal *internal)
+{
+ struct l_genl *genl;
+
+ if (unlikely(!internal))
+ return;
+
+ if (__sync_sub_and_fetch(&internal->ref_count, 1))
+ return;
+
+ genl = internal->genl;
+ if (genl)
+ l_queue_remove(genl->family_list, internal);
+
+ internal_free(internal);
+}
+
+static void family_add_op(struct genl_family_internal *internal, uint32_t id,
uint32_t flags)
{
struct genl_op *op;
@@ -210,7 +287,7 @@ static void family_add_op(struct l_genl_family *family, uint32_t id,
op->id = id;
op->flags = flags;
- l_queue_push_tail(family->op_list, op);
+ l_queue_push_tail(internal->op_list, op);
}
static bool match_mcast_name(const void *a, const void *b)
@@ -221,16 +298,16 @@ static bool match_mcast_name(const void *a, const void *b)
return !strcmp(mcast->name, name);
}
-static void family_add_mcast(struct l_genl_family *family, const char *name,
+static void family_add_mcast(struct genl_family_internal *internal, const char *name,
uint32_t id)
{
- struct l_genl *genl = family->genl;
+ struct l_genl *genl = internal->genl;
struct genl_mcast *mcast;
if (!genl)
return;
- mcast = l_queue_find(family->mcast_list, match_mcast_name,
+ mcast = l_queue_find(internal->mcast_list, match_mcast_name,
(char *) name);
if (mcast)
return;
@@ -241,7 +318,26 @@ static void family_add_mcast(struct l_genl_family *family, const char
*name,
mcast->id = id;
mcast->users = 0;
- l_queue_push_tail(family->mcast_list, mcast);
+ l_queue_push_tail(internal->mcast_list, mcast);
+}
+
+/* special initializer for the nlctrl object */
+static struct genl_family_internal *family_alloc_ctrl(struct l_genl *genl)
+{
+ struct genl_family_internal *nlctrl;
+
+ nlctrl = l_new(struct genl_family_internal, 1);
+
+ nlctrl->genl = genl;
+ strncpy(nlctrl->name, "nlctrl", GENL_NAMSIZ);
+
+ nlctrl->op_list = l_queue_new();
+ nlctrl->mcast_list = l_queue_new();
+ nlctrl->id = GENL_ID_CTRL;
+
+ family_add_mcast(nlctrl, "notify", GENL_ID_CTRL);
+
+ return nlctrl;
}
static struct l_genl_msg *msg_alloc(uint8_t cmd, uint8_t version, uint32_t size)
@@ -473,6 +569,10 @@ static void process_multicast(struct l_genl *genl, uint32_t group,
static void read_watch_destroy(void *user_data)
{
+ struct l_genl *genl = user_data;
+
+ L_WATCHLIST_NOTIFY_NO_ARGS(&genl->destroy_watches,
+ l_genl_destroy_func_t);
}
static bool received_data(struct l_io *io, void *user_data)
@@ -549,13 +649,7 @@ LIB_EXPORT struct l_genl *l_genl_new(int fd)
genl->fd = fd;
genl->close_on_unref = false;
- genl->nlctrl = family_alloc(genl, "nlctrl");
-
- genl->nlctrl->id = GENL_ID_CTRL;
-
- family_add_mcast(genl->nlctrl, "notify", GENL_ID_CTRL);
-
- l_queue_push_tail(genl->family_list, genl->nlctrl);
+ genl->nlctrl = family_alloc_ctrl(genl);
genl->io = l_io_new(genl->fd);
@@ -563,6 +657,7 @@ LIB_EXPORT struct l_genl *l_genl_new(int fd)
genl->pending_list = l_queue_new();
genl->notify_list = l_queue_new();
genl->family_list = l_queue_new();
+ l_watchlist_init(&genl->destroy_watches, NULL);
l_io_set_read_handler(genl->io, received_data, genl,
read_watch_destroy);
@@ -611,6 +706,20 @@ LIB_EXPORT struct l_genl *l_genl_new_default(void)
return genl;
}
+LIB_EXPORT unsigned int l_genl_add_destroy_watch(struct l_genl *genl,
+ l_genl_destroy_func_t destroy,
+ void *user_data)
+{
+ return l_watchlist_add(&genl->destroy_watches, (void *)destroy,
+ user_data, NULL);
+}
+
+LIB_EXPORT void l_genl_remove_destroy_watch(struct l_genl *genl,
+ unsigned int id)
+{
+ l_watchlist_remove(&genl->destroy_watches, id);
+}
+
LIB_EXPORT struct l_genl *l_genl_ref(struct l_genl *genl)
{
if (unlikely(!genl))
@@ -632,6 +741,7 @@ LIB_EXPORT void l_genl_unref(struct l_genl *genl)
l_queue_destroy(genl->notify_list, destroy_notify);
l_queue_destroy(genl->pending_list, destroy_request);
l_queue_destroy(genl->request_queue, destroy_request);
+ genl->request_queue = NULL;
l_io_set_write_handler(genl->io, NULL, NULL, NULL);
l_io_set_read_handler(genl->io, NULL, NULL, NULL);
@@ -639,9 +749,10 @@ LIB_EXPORT void l_genl_unref(struct l_genl *genl)
l_io_destroy(genl->io);
genl->io = NULL;
- l_genl_family_unref(genl->nlctrl);
+ internal_free(genl->nlctrl);
- l_queue_destroy(genl->family_list, family_free);
+ l_queue_destroy(genl->family_list, internal_free);
+ l_watchlist_destroy(&genl->destroy_watches);
if (genl->close_on_unref)
close(genl->fd);
@@ -984,7 +1095,7 @@ LIB_EXPORT bool l_genl_attr_recurse(struct l_genl_attr *attr,
return true;
}
-static void family_ops(struct l_genl_family *family, struct l_genl_attr *attr)
+static void family_ops(struct genl_family_internal *internal, struct l_genl_attr *attr)
{
uint16_t type, len;
const void *data;
@@ -1007,11 +1118,11 @@ static void family_ops(struct l_genl_family *family, struct
l_genl_attr *attr)
}
if (id > 0)
- family_add_op(family, id, flags);
+ family_add_op(internal, id, flags);
}
}
-static void family_mcast_groups(struct l_genl_family *family,
+static void family_mcast_groups(struct genl_family_internal *internal,
struct l_genl_attr *attr)
{
uint16_t type, len;
@@ -1036,27 +1147,37 @@ static void family_mcast_groups(struct l_genl_family *family,
}
if (name && id > 0)
- family_add_mcast(family, name, id);
+ family_add_mcast(internal, name, id);
}
}
+static void family_notify_appeared(void *data)
+{
+ struct cb_data *cbd = data;
+
+ if (cbd->cb)
+ cbd->cb(cbd->family, cbd->user_data);
+
+ l_free(cbd);
+}
+
static void get_family_callback(struct l_genl_msg *msg, void *user_data)
{
- struct l_genl_family *family = user_data;
+ struct genl_family_internal *internal = user_data;
struct l_genl_attr attr, nested;
uint16_t type, len;
const void *data;
int error;
- family->nlctrl_cmd = 0;
+ internal->nlctrl_cmd = 0;
- if (family->id > 0)
+ if (internal->id > 0)
return;
error = l_genl_msg_get_error(msg);
if (error < 0) {
- if (family->watch_vanished)
- family->watch_vanished(family->watch_data);
+ l_queue_remove(internal->genl->family_list, internal);
+ internal_free(internal);
return;
}
@@ -1066,127 +1187,164 @@ static void get_family_callback(struct l_genl_msg *msg, void
*user_data)
while (l_genl_attr_next(&attr, &type, &len, &data)) {
switch (type) {
case CTRL_ATTR_FAMILY_ID:
- family->id = *((uint16_t *) data);
+ internal->id = *((uint16_t *) data);
break;
case CTRL_ATTR_FAMILY_NAME:
- strncpy(family->name, data, GENL_NAMSIZ);
+ strncpy(internal->name, data, GENL_NAMSIZ);
break;
case CTRL_ATTR_VERSION:
- family->version = *((uint32_t *) data);
+ internal->version = *((uint32_t *) data);
break;
case CTRL_ATTR_HDRSIZE:
- family->hdrsize = *((uint32_t *) data);
+ internal->hdrsize = *((uint32_t *) data);
break;
case CTRL_ATTR_MAXATTR:
- family->maxattr = *((uint32_t *) data);
+ internal->maxattr = *((uint32_t *) data);
break;
case CTRL_ATTR_OPS:
if (l_genl_attr_recurse(&attr, &nested))
- family_ops(family, &nested);
+ family_ops(internal, &nested);
break;
case CTRL_ATTR_MCAST_GROUPS:
if (l_genl_attr_recurse(&attr, &nested))
- family_mcast_groups(family, &nested);
+ family_mcast_groups(internal, &nested);
break;
}
}
- if (family->watch_appeared)
- family->watch_appeared(family->watch_data);
+ internal->live = true;
+
+ l_queue_destroy(internal->pending_lookups, family_notify_appeared);
+ internal->pending_lookups = NULL;
}
-LIB_EXPORT struct l_genl_family *l_genl_family_new(struct l_genl *genl,
- const char *name)
+static bool match_family_name(const void *a, const void *b)
{
- struct l_genl_family *family;
- struct l_genl_msg *msg;
+ const struct genl_family_internal *internal = a;
- if (unlikely(!genl) || unlikely(!name) ||
- unlikely(strlen(name) >= GENL_NAMSIZ))
- return NULL;
+ return !strncmp(internal->name, (const char *)b, GENL_NAMSIZ);
+}
- family = family_alloc(genl, name);
- if (!family)
- return NULL;
+static unsigned int send_common(struct genl_family_internal *internal, uint16_t flags,
+ struct l_genl_msg *msg, unsigned int gid,
+ l_genl_msg_func_t callback, void *user_data,
+ l_genl_destroy_func_t destroy)
+{
+ struct l_genl *genl;
+ struct genl_request *request;
- msg = l_genl_msg_new_sized(CTRL_CMD_GETFAMILY, NLA_HDRLEN + GENL_NAMSIZ);
+ if (!internal || !msg)
+ return 0;
- l_genl_msg_append_attr(msg, CTRL_ATTR_FAMILY_NAME,
- GENL_NAMSIZ, family->name);
+ genl = internal->genl;
+ if (!genl)
+ return 0;
- family->nlctrl_cmd = l_genl_family_send(genl->nlctrl, msg,
- get_family_callback, family, NULL);
+ request = l_new(struct genl_request, 1);
- if (!family->nlctrl_cmd) {
- family_free(family);
- return NULL;
- }
+ request->type = internal->id;
+ request->flags = NLM_F_REQUEST | flags;
- l_queue_push_tail(genl->family_list, family);
+ request->msg = msg;
+ request->gid = gid;
- return family;
+ request->callback = callback;
+ request->destroy = destroy;
+ request->user_data = user_data;
+
+ if (genl->next_request_id < 1)
+ genl->next_request_id = 1;
+
+ request->id = genl->next_request_id++;
+
+ l_queue_push_tail(genl->request_queue, request);
+
+ wakeup_writer(genl);
+
+ return request->id;
}
-LIB_EXPORT struct l_genl_family *l_genl_family_ref(
- struct l_genl_family *family)
+static struct cb_data *cb_data_new(struct l_genl_family *family,
+ l_genl_get_family_func_t cb, void *user_data,
+ l_genl_destroy_func_t destroy)
{
- if (unlikely(!family))
- return NULL;
+ struct cb_data *cbd = l_new(struct cb_data, 1);
- __sync_fetch_and_add(&family->ref_count, 1);
+ cbd->family = family;
+ cbd->cb = cb;
+ cbd->destroy = destroy;
+ cbd->user_data = user_data;
- return family;
+ return cbd;
+}
+static void idle_get_family(void *user_data)
+{
+ struct cb_data *cbd = user_data;
+
+ if (cbd->cb)
+ cbd->cb(cbd->family, cbd->user_data);
}
-LIB_EXPORT void l_genl_family_unref(struct l_genl_family *family)
+LIB_EXPORT bool l_genl_get_family(struct l_genl *genl, const char *name,
+ l_genl_get_family_func_t callback,
+ void *user_data,
+ l_genl_destroy_func_t destroy)
{
- struct l_genl *genl;
+ struct genl_family_internal *internal;
+ struct l_genl_family *family;
+ struct l_genl_msg *msg;
+ struct cb_data *cbd;
- if (unlikely(!family))
- return;
+ if (unlikely(!genl) || unlikely(!name) ||
+ unlikely(strlen(name) >= GENL_NAMSIZ))
+ return false;
- if (__sync_sub_and_fetch(&family->ref_count, 1))
- return;
+ internal = l_queue_find(genl->family_list, match_family_name, name);
+ if (internal) {
+ family = family_alloc(internal);
- if (family->nlctrl_cmd > 0)
- l_genl_family_cancel(family, family->nlctrl_cmd);
+ cbd = cb_data_new(family, callback, user_data, destroy);
- genl = family->genl;
- if (genl)
- l_queue_remove(genl->family_list, family);
+ /*
+ * If family is looked up, just call the callback in the next
+ * event loop. Otherwise we must have a currently pending lookup
+ * so add the callback data to the pending queue
+ */
+ if (internal->live)
+ return l_idle_oneshot(idle_get_family, cbd, l_free);
+ else
+ return l_queue_push_tail(internal->pending_lookups,
+ cbd);
+ }
+
+ internal = family_alloc_internal(genl, name);
+ if (!internal)
+ return false;
- l_queue_destroy(family->op_list, op_free);
+ family = family_alloc(internal);
- l_queue_foreach(family->mcast_list, mcast_free, genl);
+ cbd = cb_data_new(family, callback, user_data, destroy);
- l_queue_destroy(family->mcast_list, NULL);
- family->mcast_list = NULL;
+ l_queue_push_tail(internal->pending_lookups, cbd);
- if (family->id > 0 && family->watch_vanished)
- family->watch_vanished(family->watch_data);
+ /* family has not yet been looked up */
+ msg = l_genl_msg_new_sized(CTRL_CMD_GETFAMILY,
+ NLA_HDRLEN + GENL_NAMSIZ);
- if (family->watch_destroy)
- family->watch_destroy(family->watch_data);
+ l_genl_msg_append_attr(msg, CTRL_ATTR_FAMILY_NAME,
+ GENL_NAMSIZ, internal->name);
- l_free(family);
-}
+ internal->nlctrl_cmd = send_common(genl->nlctrl, NLM_F_ACK, msg, 0,
+ get_family_callback, internal,
+ NULL);
-LIB_EXPORT bool l_genl_family_set_watches(struct l_genl_family *family,
- l_genl_watch_func_t appeared,
- l_genl_watch_func_t vanished,
- void *user_data,
- l_genl_destroy_func_t destroy)
-{
- if (unlikely(!family))
+ if (!internal->nlctrl_cmd) {
+ l_genl_family_destroy(family);
+ internal_free(internal);
return false;
+ }
- if (family->watch_destroy)
- family->watch_destroy(family->watch_data);
-
- family->watch_appeared = appeared;
- family->watch_vanished = vanished;
- family->watch_destroy = destroy;
- family->watch_data = user_data;
+ l_queue_push_tail(genl->family_list, internal);
return true;
}
@@ -1196,7 +1354,7 @@ LIB_EXPORT uint32_t l_genl_family_get_version(struct l_genl_family
*family)
if (unlikely(!family))
return 0;
- return family->version;
+ return family->internal->version;
}
LIB_EXPORT struct l_genl *l_genl_family_get_genl(struct l_genl_family *family)
@@ -1204,7 +1362,7 @@ LIB_EXPORT struct l_genl *l_genl_family_get_genl(struct
l_genl_family *family)
if (unlikely(!family))
return 0;
- return family->genl;
+ return family->internal->genl;
}
static bool match_op_id(const void *a, const void *b)
@@ -1223,7 +1381,8 @@ LIB_EXPORT bool l_genl_family_can_send(struct l_genl_family
*family,
if (unlikely(!family))
return false;
- op = l_queue_find(family->op_list, match_op_id, L_UINT_TO_PTR(cmd));
+ op = l_queue_find(family->internal->op_list, match_op_id,
+ L_UINT_TO_PTR(cmd));
if (!op)
return false;
@@ -1241,7 +1400,8 @@ LIB_EXPORT bool l_genl_family_can_dump(struct l_genl_family
*family,
if (!family)
return false;
- op = l_queue_find(family->op_list, match_op_id, L_UINT_TO_PTR(cmd));
+ op = l_queue_find(family->internal->op_list, match_op_id,
+ L_UINT_TO_PTR(cmd));
if (!op)
return false;
@@ -1251,51 +1411,14 @@ LIB_EXPORT bool l_genl_family_can_dump(struct l_genl_family
*family,
return false;
}
-static unsigned int send_common(struct l_genl_family *family, uint16_t flags,
- struct l_genl_msg *msg, l_genl_msg_func_t callback,
- void *user_data, l_genl_destroy_func_t destroy)
-{
- struct l_genl *genl;
- struct genl_request *request;
-
- if (!family || !msg)
- return 0;
-
- genl = family->genl;
- if (!genl)
- return 0;
-
- request = l_new(struct genl_request, 1);
-
- request->type = family->id;
- request->flags = NLM_F_REQUEST | flags;
-
- request->msg = msg;
-
- request->callback = callback;
- request->destroy = destroy;
- request->user_data = user_data;
-
- if (genl->next_request_id < 1)
- genl->next_request_id = 1;
-
- request->id = genl->next_request_id++;
-
- l_queue_push_tail(genl->request_queue, request);
-
- wakeup_writer(genl);
-
- return request->id;
-}
-
LIB_EXPORT unsigned int l_genl_family_send(struct l_genl_family *family,
struct l_genl_msg *msg,
l_genl_msg_func_t callback,
void *user_data,
l_genl_destroy_func_t destroy)
{
- return send_common(family, NLM_F_ACK, msg, callback,
- user_data, destroy);
+ return send_common(family->internal, NLM_F_ACK, msg, family->gid,
+ callback, user_data, destroy);
}
LIB_EXPORT unsigned int l_genl_family_dump(struct l_genl_family *family,
@@ -1304,8 +1427,9 @@ LIB_EXPORT unsigned int l_genl_family_dump(struct l_genl_family
*family,
void *user_data,
l_genl_destroy_func_t destroy)
{
- return send_common(family, NLM_F_ACK | NLM_F_DUMP, msg, callback,
- user_data, destroy);
+ return send_common(family->internal, NLM_F_ACK | NLM_F_DUMP, msg,
+ family->gid, callback,
+ user_data, destroy);
}
static bool match_request_id(const void *a, const void *b)
@@ -1325,7 +1449,7 @@ LIB_EXPORT bool l_genl_family_cancel(struct l_genl_family *family,
if (unlikely(!family) || unlikely(!id))
return false;
- genl = family->genl;
+ genl = family->internal->genl;
if (!genl)
return false;
@@ -1345,6 +1469,53 @@ done:
return true;
}
+static bool remove_by_gid(void *data, void *user_data)
+{
+ struct genl_request *request = data;
+ unsigned int gid = L_PTR_TO_UINT(user_data);
+
+ if (request->gid != gid)
+ return false;
+
+ destroy_request(request);
+
+ return true;
+}
+
+LIB_EXPORT bool l_genl_family_cancel_all(struct l_genl_family *family)
+{
+ struct l_genl *genl;
+ unsigned int removed;
+
+ if (unlikely(!family))
+ return false;
+
+ genl = family->internal->genl;
+ if (!genl)
+ return false;
+
+ removed = l_queue_foreach_remove(genl->request_queue, remove_by_gid,
+ L_UINT_TO_PTR(family->gid));
+ if (removed)
+ return true;
+
+ removed = l_queue_foreach_remove(genl->pending_list, remove_by_gid,
+ L_UINT_TO_PTR(family->gid));
+ if (!removed)
+ return false;
+
+ return true;
+}
+
+LIB_EXPORT void l_genl_family_destroy(struct l_genl_family *family)
+{
+ l_genl_family_cancel_all(family);
+
+ family_internal_unref(family->internal);
+
+ l_free(family);
+}
+
static void add_membership(struct l_genl *genl, struct genl_mcast *mcast)
{
int group = mcast->id;
@@ -1367,7 +1538,7 @@ LIB_EXPORT bool l_genl_family_has_group(struct l_genl_family
*family,
if (unlikely(!family))
return false;
- mcast = l_queue_find(family->mcast_list, match_mcast_name,
+ mcast = l_queue_find(family->internal->mcast_list, match_mcast_name,
(char *) group);
if (!mcast)
return false;
@@ -1388,18 +1559,18 @@ LIB_EXPORT unsigned int l_genl_family_register(struct
l_genl_family *family,
if (unlikely(!family) || unlikely(!group))
return 0;
- genl = family->genl;
+ genl = family->internal->genl;
if (!genl)
return 0;
- mcast = l_queue_find(family->mcast_list, match_mcast_name,
+ mcast = l_queue_find(family->internal->mcast_list, match_mcast_name,
(char *) group);
if (!mcast)
return 0;
notify = l_new(struct genl_mcast_notify, 1);
- notify->type = family->id;
+ notify->type = family->internal->id;
notify->group = mcast->id;
notify->callback = callback;
@@ -1435,7 +1606,7 @@ LIB_EXPORT bool l_genl_family_unregister(struct l_genl_family
*family,
if (!family || !id)
return false;
- genl = family->genl;
+ genl = family->internal->genl;
if (!genl)
return false;
diff --git a/ell/genl.h b/ell/genl.h
index ff5687c..1a92e3a 100644
--- a/ell/genl.h
+++ b/ell/genl.h
@@ -2,7 +2,7 @@
*
* Embedded Linux library
*
- * Copyright (C) 2011-2014 Intel Corporation. All rights reserved.
+ * Copyright (C) 2011-2018 Intel Corporation. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -33,12 +33,16 @@ extern "C" {
typedef void (*l_genl_destroy_func_t)(void *user_data);
-
struct l_genl;
struct l_genl *l_genl_new(int fd);
struct l_genl *l_genl_new_default(void);
+unsigned int l_genl_add_destroy_watch(struct l_genl *genl,
+ l_genl_destroy_func_t destroy,
+ void *user_data);
+void l_genl_remove_destroy_watch(struct l_genl *genl, unsigned int id);
+
struct l_genl *l_genl_ref(struct l_genl *genl);
void l_genl_unref(struct l_genl *genl);
@@ -49,7 +53,6 @@ bool l_genl_set_debug(struct l_genl *genl, l_genl_debug_func_t
callback,
bool l_genl_set_close_on_unref(struct l_genl *genl, bool do_close);
-
struct l_genl_msg;
struct l_genl_attr {
@@ -85,17 +88,17 @@ bool l_genl_attr_recurse(struct l_genl_attr *attr, struct l_genl_attr
*nested);
struct l_genl_family;
-struct l_genl_family *l_genl_family_new(struct l_genl *genl, const char *name);
+typedef void (*l_genl_get_family_func_t)(struct l_genl_family *family,
+ void *user_data);
-struct l_genl_family *l_genl_family_ref(struct l_genl_family *family);
-void l_genl_family_unref(struct l_genl_family *family);
+bool l_genl_get_family(struct l_genl *genl, const char *name,
+ l_genl_get_family_func_t callback,
+ void *user_data,
+ l_genl_destroy_func_t destroy);
-typedef void (*l_genl_watch_func_t)(void *user_data);
+void l_genl_family_destroy(struct l_genl_family *family);
-bool l_genl_family_set_watches(struct l_genl_family *family,
- l_genl_watch_func_t appeared,
- l_genl_watch_func_t vanished,
- void *user_data, l_genl_destroy_func_t destroy);
+typedef void (*l_genl_watch_func_t)(void *user_data);
typedef void (*l_genl_msg_func_t)(struct l_genl_msg *msg, void *user_data);
@@ -116,6 +119,7 @@ unsigned int l_genl_family_dump(struct l_genl_family *family,
struct l_genl_msg *msg, l_genl_msg_func_t callback,
void *user_data, l_genl_destroy_func_t destroy);
bool l_genl_family_cancel(struct l_genl_family *family, unsigned int id);
+bool l_genl_family_cancel_all(struct l_genl_family *family);
bool l_genl_family_has_group(struct l_genl_family *family, const char *group);
unsigned int l_genl_family_register(struct l_genl_family *family,
--
2.17.1