watchlist: added watchlist functionality
PATCH v2 1/3 watchlist: added watchlist functionality
These two files (watchlist.[ch]) were copied from IWD, and public API's changed to l_ prefix.
--- Makefile.am | 6 +- ell/ell.h | 1 + ell/watchlist.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++ ell/watchlist.h | 129 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 ell/watchlist.c create mode 100644 ell/watchlist.h
Makefile.am +4 -2
@@ -48,7 +48,8 @@ pkginclude_HEADERS = ell/ell.h \ ell/file.h \ ell/dir.h \ ell/net.h \ - ell/dhcp.h + ell/dhcp.h \ + ell/watchlist.h lib_LTLIBRARIES = ell/libell.la
@@ -109,7 +110,8 @@ ell_libell_la_SOURCES = $(linux_headers) \ ell/dhcp-private.h \ ell/dhcp.c \ ell/dhcp-transport.c \ - ell/dhcp-lease.c + ell/dhcp-lease.c \ + ell/watchlist.c ell_libell_la_LDFLAGS = -no-undefined \ -Wl,--version-script=$(top_srcdir)/ell/ell.sym \
ell/ell.h +1 -0
@@ -56,3 +56,4 @@#include <ell/dbus-service.h> #include <ell/dbus-client.h> #include <ell/dhcp.h> +#include <ell/watchlist.h>
ell/watchlist.c new file +149 -0
149 lines not on this page · raw message
ell/watchlist.h new file +129 -0
130 lines not on this page · raw message
Signature · 1 line
2.17.1
PATCH v2 2/3 genl: rework l_genl_family to avoid extra lookups
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(-)
ell/genl.c +338 -167
@@ -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;
ell/genl.h +15 -11
@@ -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,
Signature · 1 line
2.17.1
PATCH v2 3/3 unit: test-genl: Reworked genl tests after restructuring
In reply to James Prestwood--- unit/test-genl.c | 351 ++++++++++++++++++++++++++++++++++++----------- 1 file changed, 270 insertions(+), 81 deletions(-)
unit/test-genl.c +270 -81
@@ -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
@@ -32,10 +32,13 @@struct test_data {struct l_genl_family *appeared_family; -struct l_genl_family *vanished_family; -unsigned int group_id; -bool vanished_called; +bool destroyed_called; +bool appeared_called; +bool genl_destroyed; +int message_destroy; + +int idle_count; };static void do_debug (const char *str,void *user_data)
@@ -45,138 +48,324 @@ static void do_debug(const char *str, void *user_data)l_info ("%s%s" , prefix, str); } -static void notify_callback (struct l_genl_msg *msg,void *user_data) -{ -} - -static void family_appeared (void *user_data) +static void family_appeared (struct l_genl_family *family,void *user_data) {struct test_data *data = user_data; - data->group_id =l_genl_family_register (data->appeared_family, -"notify" , - notify_callback, -NULL , -NULL ); + data->appeared_called = true; + data->appeared_family = family; } -static void family_vanished (void *user_data) +static void family_destroyed (void *user_data) { -struct test_data *data = user_data; +struct test_data *td = user_data; - data->vanished_called = true; + td->destroyed_called = true; } -static bool prep_family_appeared (struct l_genl *genl, -struct test_data *data) +static void idle_callback (struct l_idle *idle,void *user_data) { +struct test_data *data = user_data; +/* -* Set a family_appeared watch for the "nlctrl" family. +* Exit the event loop if the desired results have been +* obtained, but limit the number of iterations to prevent the +* loop from running indefinitely if the conditions for +* success are never reached. * -* The "nlctrl" generic netlink family always exists in the -* kernel so it is a suitable family to use for testing -* the family_appeared watch and related family registration -* operations. +* Allow the main loop to iterate at least four times to allow +* the generic netlink watches and family registration to be +* called and completed, respectively. */ - data->appeared_family =l_genl_family_new (genl,"nlctrl" ); - -return l_genl_family_set_watches (data->appeared_family, - family_appeared,NULL , - data,NULL ); +if (++data->idle_count >3 ) +l_main_quit (); } -static bool prep_family_vanished (struct l_genl *genl, -struct test_data *data) +static void test_basic (const void *user_data) { -/* -* Use a bogus family name to trigger the vanished watch to -* be called during the ELL event loop run. -*/ -static const char BOGUS_GENL_NAME [] ="bogusgenlfamily" ; +struct l_genl *genl; +struct l_idle *idle; +struct test_data td1 = {0 }; +struct test_data td2 = {0 }; - data->vanished_family =l_genl_family_new (genl,BOGUS_GENL_NAME ); -return l_genl_family_set_watches (data->vanished_family, -NULL , family_vanished, - data,NULL ); -} +if (!l_main_init ()) { +assert (false); +return ; + } -static bool name_too_long (struct l_genl *genl,struct test_data *data) -{ -static const char LONG_GENL_NAME [] ="long_genl_family_name" ; +l_log_set_stderr (); + + genl =l_genl_new_default (); + +l_genl_set_debug (genl, do_debug,"[GENL] " ,NULL ); -assert (!l_genl_family_new (genl,LONG_GENL_NAME )); +assert (l_genl_get_family (genl,"nlctrl" , family_appeared, + &td1, family_destroyed)); +assert (l_genl_get_family (genl,"bogusgenlfamily" , family_appeared, + &td2, family_destroyed)); +assert (!l_genl_get_family (genl,"long_genl_family_name" , + family_appeared,NULL , + family_destroyed)); + + idle =l_idle_create (idle_callback, &td1,NULL ); + +l_main_run (); + +l_idle_remove (idle); + +assert (td1.appeared_called && td1.appeared_family); +assert (td2.destroyed_called); + +l_genl_family_destroy (td1.appeared_family); + +l_genl_unref (genl); -return true; +l_main_exit (); } -static bool check_test_data (struct test_data *data) +static void test_gets_before_lookup (const void *user_data) { -return data->group_id !=0 && data->vanished_called; +struct l_genl *genl; +struct l_idle *idle; +struct test_data td1 = {0 }; +struct test_data td2 = {0 }; + +if (!l_main_init ()) { +assert (false); +return ; + } + +l_log_set_stderr (); + + genl =l_genl_new_default (); + +l_genl_set_debug (genl, do_debug,"[GENL] " ,NULL ); + +assert (l_genl_get_family (genl,"nlctrl" , family_appeared, &td1, + family_destroyed)); +assert (l_genl_get_family (genl,"nlctrl" , family_appeared, &td2, + family_destroyed)); + + idle =l_idle_create (idle_callback, &td1,NULL ); + +l_main_run (); + +l_idle_remove (idle); + +assert (td1.appeared_called && td1.appeared_family); +assert (td1.appeared_called && td1.appeared_family); + +l_genl_family_destroy (td1.appeared_family); +l_genl_family_destroy (td2.appeared_family); + +l_genl_unref (genl); + +l_main_exit (); } -static void idle_callback (struct l_idle *idle,void *user_data) +static void test_destroy_before_lookup (const void *user_data) { -struct test_data *data = user_data; -static int count =0 ; +struct l_genl *genl; +struct test_data td1 = {0 }; +struct test_data td2 = {0 }; + +if (!l_main_init ()) { +assert (false); +return ; + } + +l_log_set_stderr (); + + genl =l_genl_new_default (); + +l_genl_set_debug (genl, do_debug,"[GENL] " ,NULL ); + +assert (l_genl_get_family (genl,"nlctrl" , family_appeared, &td1, + family_destroyed)); +assert (l_genl_get_family (genl,"nlctrl" , family_appeared, &td2, + family_destroyed));/* -* Exit the event loop if the desired results have been -* obtained, but limit the number of iterations to prevent the -* loop from running indefinitely if the conditions for -* success are never reached. -* -* Allow the main loop to iterate at least four times to allow -* the generic netlink watches and family registration to be -* called and completed, respectively. +* In practice you would never do this. But it effectively simulates +* the genl transport disappearing while you have family lookups +* pending. */ -if (check_test_data (data) || ++count >3 ) -l_main_quit (); +l_genl_unref (genl); +l_genl_unref (genl); + +assert (td1.destroyed_called); +assert (td2.destroyed_called); + +l_main_exit (); } -static bool destroy_test_data (struct test_data *data) +static void test_family_after_lookup (const void *user_data) { -bool unregistered = -l_genl_family_unregister (data->appeared_family, - data->group_id); +struct l_genl *genl; +struct l_idle *idle; +struct test_data td1 = {0 }; +struct test_data td2 = {0 }; + +if (!l_main_init ()) { +assert (false); +return ; + } + +l_log_set_stderr (); + + genl =l_genl_new_default (); + +l_genl_set_debug (genl, do_debug,"[GENL] " ,NULL ); + +assert (l_genl_get_family (genl,"nlctrl" , family_appeared, &td1, + family_destroyed)); + + idle =l_idle_create (idle_callback, &td1,NULL ); + +l_main_run (); + +l_idle_remove (idle); + +assert (td1.appeared_called); + +l_main_exit (); + +if (!l_main_init ()) { +assert (false); +return ; + } + +assert (l_genl_get_family (genl,"nlctrl" , family_appeared, &td2, + family_destroyed)); + + idle =l_idle_create (idle_callback, &td2,NULL ); + +l_main_run (); + +l_idle_remove (idle); + +assert (td2.appeared_called); + +l_genl_family_destroy (td1.appeared_family); +l_genl_family_destroy (td2.appeared_family); -l_genl_family_unref (data->vanished_family); -l_genl_family_unref (data->appeared_family); +l_genl_unref (genl); -return unregistered; +l_main_exit (); } -int main (int argc,char *argv[]) +static void message_destroy (void *user_data) +{ +struct test_data *td = user_data; + + td->message_destroy++; +} + +static void test_cancel_all_request (const void *user_data) {struct l_genl *genl; +struct l_genl_msg *msg1, *msg2, *msg3, *msg4; +unsigned int msg3_id;struct l_idle *idle; -struct test_data data = { .group_id =0 }; -if (!l_main_init ()) -return -1 ; +struct test_data td1 = {0 }; +struct test_data td2 = {0 }; -l_log_set_stderr (); +if (!l_main_init ()) { +assert (false); +return ; + } genl =l_genl_new_default ();l_genl_set_debug (genl, do_debug,"[GENL] " ,NULL ); -assert (prep_family_appeared (genl, &data)); -assert (prep_family_vanished (genl, &data)); +assert (l_genl_get_family (genl,"nlctrl" , family_appeared, &td1, + family_destroyed)); +assert (l_genl_get_family (genl,"nlctrl" , family_appeared, &td2, + family_destroyed)); -assert (name_too_long (genl, &data)); - - idle =l_idle_create (idle_callback, &data,NULL ); + idle =l_idle_create (idle_callback, &td1,NULL );l_main_run ();l_idle_remove (idle); -assert (check_test_data (&data)); -assert (destroy_test_data (&data)); +assert (td1.appeared_called); +assert (td2.appeared_called); + +/* create some dummy messages to send on both families */ + msg1 =l_genl_msg_new (1 ); + msg2 =l_genl_msg_new (1 ); + msg3 =l_genl_msg_new (1 ); + msg4 =l_genl_msg_new (1 ); + +l_genl_family_send (td1.appeared_family, msg1,NULL , &td1, + message_destroy); +l_genl_family_send (td1.appeared_family, msg2,NULL , &td1, + message_destroy); + msg3_id =l_genl_family_send (td2.appeared_family, msg3,NULL , &td2, + message_destroy); +l_genl_family_send (td2.appeared_family, msg4,NULL , &td2, + message_destroy); + +/* this should cancel msg1 and msg2 */ +l_genl_family_destroy (td1.appeared_family); + +assert (td1.message_destroy ==2 ); +assert (td2.message_destroy ==0 ); + +/* cancel just message 3 */ +l_genl_family_cancel (td2.appeared_family, msg3_id); +assert (td2.message_destroy ==1 ); + +/* cancel all remaining (just message 4) */ +l_genl_family_destroy (td2.appeared_family); +assert (td2.message_destroy ==2 );l_genl_unref (genl);l_main_exit (); +} + +static void genl_destroyed (void *user_data) +{ +struct test_data *td = user_data; + + td->genl_destroyed = true; +} + +static void test_genl_disappearing (const void *user_data) +{ +struct l_genl *genl; +struct test_data td = {0 }; + +if (!l_main_init ()) { +assert (false); +return ; + } + + genl =l_genl_new_default (); + +l_genl_add_destroy_watch (genl, genl_destroyed, &td); + +l_genl_unref (genl); + +assert (td.genl_destroyed); + +l_main_exit (); +} + +int main (int argc,char *argv[]) +{ +l_test_init (&argc, &argv); + +l_test_add ("Basic" , test_basic,NULL ); +l_test_add ("Gets before lookup" , test_gets_before_lookup,NULL ); +l_test_add ("Destroy before lookup" , test_destroy_before_lookup,NULL ); +l_test_add ("New family after lookup" , test_family_after_lookup,NULL ); +l_test_add ("Cancel all family requests" , test_cancel_all_request,NULL ); +l_test_add ("Genl disappearing" , test_genl_disappearing,NULL ); -return 0 ; +return l_test_run (); }
Signature · 1 line
2.17.1
Quoted 50 lines · James Prestwood
These two files (watchlist.[ch]) were copied from IWD, and public API's changed to l_ prefix.
---Makefile.am | 6 +- ell/ell.h | 1 + ell/watchlist.c | 149 ++++++++++++++++++++++++++++++++++++++++++++++++ ell/watchlist.h | 129 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 283 insertions(+), 2 deletions(-)create mode 100644
ell/watchlist.c
create mode 100644ell/watchlist.hMakefile.am +2
-1@@ -48,7 +48,8 @@ pkginclude_HEADERS = ell/ell.h \ ell/file.h \ ell/dir.h \ ell/net.h \ - ell/dhcp.h + ell/dhcp.h \ + ell/watchlist.h
lib_LTLIBRARIES= ell/libell.laMakefile.am +2
-1@@ -109,7 +110,8 @@ ell_libell_la_SOURCES = $(linux_headers) \ ell/dhcp-private.h \ ell/dhcp.c \ ell/dhcp-transport.c \ - ell/dhcp-lease.c + ell/dhcp-lease.c \ + ell/watchlist.c ell_libell_la_LDFLAGS = -no-undefined \ -Wl,--version-script=$(top_srcdir)/ell/ell.sym \ell/ell.h +1
-0@@ -56,3 +56,4 @@#include <ell/dbus-service.h> #include <ell/dbus-client.h> #include <ell/dhcp.h> +#include <ell/watchlist.h> ell/watchlist.c new file +0
-0
ell/watchlist.c line 3
Quoted 3 lines
ell/watchlist.c new file +3
-0@@ -0,0 +1,149 @@ +/* +* +* Wireless daemon for Linux
Change this to match ELL files? Probably update the copyright dates too.
Quoted 14 lines
ell/watchlist.c new file +14
-0+* +* Copyright (C) 2016 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 +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public
ell/watchlist.c line 27
Quoted 10 lines
ell/watchlist.c new file +10
-0+* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <ell/ell.h>
Can this include the relevant header files instead?
Quoted 12 lines
ell/watchlist.c new file +12
-0+ +static bool watchlist_item_match (const void *a,const void *b) +{ +const struct l_watchlist_item *item = a; +uint32_t id =L_PTR_TO_UINT (b); + +return item->id == id; +} + +static void __watchlist_item_free (struct l_watchlist *watchlist, +struct l_watchlist_item *item) +{
ell/watchlist.c line 49
Quoted 10 lines
ell/watchlist.c new file +10
-0+if (item->destroy) + item->destroy (item->notify_data); + +if (watchlist->ops && watchlist->ops->item_free) + watchlist->ops->item_free (item); +else +l_free (item); +} + +struct l_watchlist *l_watchlist_new (const struct l_watchlist_ops *ops)
You'll need to add LIB_EXPORT to functions that are public, and also update ell.sym.
Quoted 106 lines
ell/watchlist.c new file +100
-0+{ +struct l_watchlist *watchlist; + + watchlist = l_new(struct l_watchlist, 1); + watchlist->items =l_queue_new (); + watchlist->ops = ops; +return watchlist; +} + +void l_watchlist_init (struct l_watchlist *watchlist, +const struct l_watchlist_ops *ops) +{ + watchlist->next_id =0 ; + watchlist->items =l_queue_new (); + watchlist->ops = ops; +} + +unsigned int l_watchlist_link (struct l_watchlist *watchlist, +struct l_watchlist_item *item, +void *notify,void *notify_data, +l_watchlist_item_destroy_func_t destroy) +{ + item->id = ++watchlist->next_id; + item->notify = notify; + item->notify_data = notify_data; + item->destroy = destroy; + +l_queue_push_tail (watchlist->items, item); + +return item->id; +} + +unsigned int l_watchlist_add (struct l_watchlist *watchlist,void *notify, +void *notify_data, +l_watchlist_item_destroy_func_t destroy) +{ +struct l_watchlist_item *item; + + item = l_new(struct l_watchlist_item, 1); +return l_watchlist_link (watchlist, item, notify, notify_data, destroy); +} + +bool l_watchlist_remove (struct l_watchlist *watchlist,unsigned int id) +{ +struct l_watchlist_item *item; + +if (watchlist->in_notify) { + item =l_queue_find (watchlist->items, watchlist_item_match, +L_UINT_TO_PTR (id)); +if (!item) +return false; + + item->id =0 ;/* Mark stale */ + watchlist->stale_items = true; + +return true; + } + + item =l_queue_remove_if (watchlist->items, watchlist_item_match, +L_UINT_TO_PTR (id)); +if (!item) +return false; + +__watchlist_item_free (watchlist, item); + +return true; +} + +static void __watchlist_clear (struct l_watchlist *watchlist) +{ +struct l_watchlist_item *item; + +while ((item =l_queue_pop_head (watchlist->items))) +__watchlist_item_free (watchlist, item); +} + +void l_watchlist_destroy (struct l_watchlist *watchlist) +{ +__watchlist_clear (watchlist); +l_queue_destroy (watchlist->items,NULL ); + watchlist->items =NULL ; +} + +void l_watchlist_free (struct l_watchlist *watchlist) +{ +__watchlist_clear (watchlist); +l_queue_destroy (watchlist->items,NULL ); +l_free (watchlist); +} + +void __watchlist_prune_stale (struct l_watchlist *watchlist) +{ +struct l_watchlist_item *item; + +while ((item =l_queue_remove_if (watchlist->items, watchlist_item_match, +L_UINT_TO_PTR (0 )))) +__watchlist_item_free (watchlist, item); + + watchlist->stale_items = false; +}ell/watchlist.h new file +0
-0
ell/watchlist.h line 3
Quoted 3 lines
ell/watchlist.h new file +3
-0@@ -0,0 +1,129 @@ +/* +* +* Wireless daemon for Linux
Update this too.
Quoted 52 lines
ell/watchlist.h new file +52
-0+* +* Copyright (C) 2016-2017 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 +* License as published by the Free Software Foundation; either +* version 2.1 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public +* License along with this library; if not, write to the Free Software +* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +* +*/ + +#ifndef __ELL_WATCHLIST_H +#define __ELL_WATCHLIST_H + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*l_watchlist_item_destroy_func_t)(void *data); + +struct l_watchlist_item { + unsigned int id; + void *notify; + void *notify_data; + l_watchlist_item_destroy_func_t destroy; +}; + +struct l_watchlist_ops { + void (*item_free)(struct l_watchlist_item *item); +}; + +struct l_watchlist { + int next_id; + struct l_queue *items; + bool in_notify : 1; + bool stale_items : 1; + const struct l_watchlist_ops *ops; +}; + +struct l_watchlist *l_watchlist_new(const struct l_watchlist_ops *ops); +void l_watchlist_init(struct l_watchlist *watchlist, + const struct l_watchlist_ops *ops); +unsigned int l_watchlist_add(struct l_watchlist *watchlist, void *notify, + void *notify_data,
ell/watchlist.h line 65
Quoted 10 lines
ell/watchlist.h new file +10
-0+ l_watchlist_item_destroy_func_t destroy); +unsigned int l_watchlist_link (struct l_watchlist *watchlist, +struct l_watchlist_item *item, +void *notify,void *notify_data, +l_watchlist_item_destroy_func_t destroy); +bool l_watchlist_remove (struct l_watchlist *watchlist,unsigned int id); +void l_watchlist_destroy (struct l_watchlist *watchlist); +void l_watchlist_free (struct l_watchlist *watchlist); + +void __watchlist_prune_stale (struct l_watchlist *watchlist);
Should this be in the public header?
Thanks,
Mat
Quoted 73 lines
ell/watchlist.h new file +64
-0+ +#define L_WATCHLIST_NOTIFY(watchlist, type, args...) \ + do { \ + const struct l_queue_entry *entry = \ + l_queue_get_entries((watchlist)->items);\ + \ + (watchlist)->in_notify = true; \ + for (; entry; entry = entry->next) { \ + struct l_watchlist_item *item = entry->data; \ + type t = item->notify; \ + if (item->id == 0) \ + continue; \ + t(args, item->notify_data); \ + } \ + (watchlist)->in_notify = false; \ + if ((watchlist)->stale_items) \ + __watchlist_prune_stale(watchlist); \ + } while (false) \ + +#define L_WATCHLIST_NOTIFY_MATCHES(watchlist, match, match_data, type, args...) \ + do { \ + const struct l_queue_entry *entry = \ + l_queue_get_entries((watchlist)->items);\ + \ + (watchlist)->in_notify = true; \ + for (; entry; entry = entry->next) { \ + struct l_watchlist_item *item = entry->data; \ + type t = item->notify; \ + \ + if (item->id == 0) \ + continue; \ + if (!match(item, match_data)) \ + continue; \ + \ + t(args, item->notify_data); \ + } \ + (watchlist)->in_notify = false; \ + if ((watchlist)->stale_items) \ + __watchlist_prune_stale(watchlist); \ + } while (false) + +#define L_WATCHLIST_NOTIFY_NO_ARGS (watchlist, type) \ + do { \ + const struct l_queue_entry *entry = \ + l_queue_get_entries((watchlist)->items);\ + \ + (watchlist)->in_notify = true; \ + for (; entry; entry = entry->next) { \ + struct l_watchlist_item *item = entry->data; \ + type t = item->notify; \ + if (item->id == 0) \ + continue; \ + t(item->notify_data); \ + } \ + (watchlist)->in_notify = false; \ + if ((watchlist)->stale_items) \ + __watchlist_prune_stale(watchlist); \ + } while (false) + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_WATCHLIST_H */ Signature · 6 lines
2.17.1 _______________________________________________ ell mailing list ell(a)lists.01.org https://lists.01.org/mailman/listinfo/ell
--
Mat Martineau
Intel OTC
Hi Mat,
Quoted 4 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ +void __watchlist_prune_stale(struct l_watchlist *watchlist);Should this be in the public header?
Yeah.. I meant to inquire about this. Its needed for the macros below so it does need to be available as a public API, but its not meant to be called directly. Not sure if ELL has anything else like this. Any suggestions?
Quoted 107 lines
Thanks,
MatQuoted 102 lines
(quoted diff) +2
-0+ +#define L_WATCHLIST_NOTIFY(watchlist, type, args...)\(quoted diff) +1
-0+ do {\
(quoted diff) +2
-0+ const struct l_queue_entry *entry = \ + l_queue_get_entries((watchlist)-Quoted 1 line
items);\
(quoted diff) +1
-0+\
(quoted diff) +1
-0+ (watchlist)->in_notify = true;\
(quoted diff) +1
-0+ for (; entry; entry = entry->next) {\
(quoted diff) +1
-0+ struct l_watchlist_item *item = entry->data;\
(quoted diff) +1
-0+ type t = item->notify;\
ell/watchlist.h new file +5
-0+if (item->id ==0 ) \ +continue ; \ +t (args, item->notify_data); \ + } \ + (watchlist)->in_notify = false;\
(quoted diff) +1
-0+ if ((watchlist)->stale_items)\
(quoted diff) +2
-0+ __watchlist_prune_stale(watchlist); \ + } while (false)\
(quoted diff) +2
-0+ +#define L_WATCHLIST_NOTIFY_MATCHES(watchlist, match, match_data,type, args...) \
(quoted diff) +1
-0+ do {\
(quoted diff) +2
-0+ const struct l_queue_entry *entry = \ + l_queue_get_entries((watchlist)-Quoted 1 line
items);\
(quoted diff) +1
-0+\
(quoted diff) +1
-0+ (watchlist)->in_notify = true;\
(quoted diff) +1
-0+ for (; entry; entry = entry->next) {\
(quoted diff) +1
-0+ struct l_watchlist_item *item = entry->data;\
(quoted diff) +1
-0+ type t = item->notify;\
(quoted diff) +1
-0+\
ell/watchlist.h new file +3
-0+if (item->id ==0 ) \ +continue ; \ +if (!match (item, match_data))\
(quoted diff) +2
-0+ continue; \ +\
ell/watchlist.h new file +3
-0+t (args, item->notify_data); \ + } \ + (watchlist)->in_notify = false;\
(quoted diff) +1
-0+ if ((watchlist)->stale_items)\
ell/watchlist.h new file +4
-0+__watchlist_prune_stale (watchlist); \ + }while (false) + +#define L_WATCHLIST_NOTIFY_NO_ARGS(watchlist, type)\(quoted diff) +1
-0+ do {\
(quoted diff) +2
-0+ const struct l_queue_entry *entry = \ + l_queue_get_entries((watchlist)-Quoted 1 line
items);\
(quoted diff) +1
-0+\
(quoted diff) +1
-0+ (watchlist)->in_notify = true;\
(quoted diff) +1
-0+ for (; entry; entry = entry->next) {\
(quoted diff) +1
-0+ struct l_watchlist_item *item = entry->data;\
(quoted diff) +1
-0+ type t = item->notify;\
ell/watchlist.h new file +5
-0+if (item->id ==0 ) \ +continue ; \ +t (item->notify_data); \ + } \ + (watchlist)->in_notify = false;\
(quoted diff) +1
-0+ if ((watchlist)->stale_items)\
ell/watchlist.h new file +8
-0+__watchlist_prune_stale (watchlist); \ + } while (false) + +#ifdef __cplusplus +} +#endif + +#endif /* __ELL_WATCHLIST_H */ Signature · 1 line
2.17.1
Quoted 9 lines
Quoted 5 lines
_______________________________________________
ell mailing list
ell(a)lists.01.org
https://lists.01.org/mailman/listinfo/ell--
Mat Martineau
Intel OTC
Thanks,
James
Hi James,
Quoted 9 lines
Quoted 4 lines
Review
Quoted 2 lines
(quoted diff) +2
-0+ +void __watchlist_prune_stale(struct l_watchlist *watchlist);Should this be in the public header?
Yeah.. I meant to inquire about this. Its needed for the macros below so it does need to be available as a public API, but its not meant to be called directly. Not sure if ELL has anything else like this. Any suggestions?
you need to create a watchlist-private.h for these.
Regards
Marcel