Re: [LEDE-DEV] [PATCH] ubusd: Use linked list for queued messages (alt.)
Hi, What is the acceptance state of this patch? In patchwork it has the status `superseded'. Does it mean that the issue has been or will be solved by other means? Thanks, Benjamin On Thu, 2018-05-03 at 12:06 +0200, Benjamin Hansmann wrote: > The fixed size array for queuing messages led to discarding messages > when it was full, using a linked list instead solves this issue. > > The motivation was that for a recursive "ubus list" the function > ubusd_proto.c:ubusd_handle_lookup() produces more than n messages in > one uloop cycle when n objects are registered on the bus. > > Signed-off-by: Benjamin Hansmann > --- > ubusd.c | 29 + > ubusd.h | 10 +++--- > ubusd_proto.c | 1 + > 3 files changed, 25 insertions(+), 15 deletions(-) > > diff --git a/ubusd.c b/ubusd.c > index ba1ff07..e58624a 100644 > --- a/ubusd.c > +++ b/ubusd.c > @@ -138,11 +138,11 @@ static int ubus_msg_writev(int fd, struct > ubus_msg_buf *ub, int offset) > > static void ubus_msg_enqueue(struct ubus_client *cl, struct > ubus_msg_buf *ub) > { > - if (cl->tx_queue[cl->txq_tail]) > + struct ubus_msg_qentry *entry = calloc(1, sizeof(*entry)); > + if (!entry) > return; > - > - cl->tx_queue[cl->txq_tail] = ubus_msg_ref(ub); > - cl->txq_tail = (cl->txq_tail + 1) % ARRAY_SIZE(cl- > >tx_queue); > + entry->msg = ubus_msg_ref(ub); > + list_add_tail(>queue, >tx_queue); > } > > /* takes the msgbuf reference */ > @@ -153,7 +153,7 @@ void ubus_msg_send(struct ubus_client *cl, struct > ubus_msg_buf *ub) > if (ub->hdr.type != UBUS_MSG_MONITOR) > ubusd_monitor_message(cl, ub, true); > > - if (!cl->tx_queue[cl->txq_cur]) { > + if (list_empty(>tx_queue)) { > written = ubus_msg_writev(cl->sock.fd, ub, 0); > > if (written < 0) > @@ -172,20 +172,25 @@ void ubus_msg_send(struct ubus_client *cl, > struct ubus_msg_buf *ub) > > static struct ubus_msg_buf *ubus_msg_head(struct ubus_client *cl) > { > - return cl->tx_queue[cl->txq_cur]; > + if (list_empty(>tx_queue)) > + return NULL; > + struct ubus_msg_qentry *entry; > + entry = list_first_entry(>tx_queue, struct > ubus_msg_qentry, queue); > + return entry->msg; > } > > static void ubus_msg_dequeue(struct ubus_client *cl) > { > - struct ubus_msg_buf *ub = ubus_msg_head(cl); > - > - if (!ub) > + if (list_empty(>tx_queue)) > return; > > - ubus_msg_free(ub); > + struct ubus_msg_qentry *entry; > + entry = list_first_entry(>tx_queue, struct > ubus_msg_qentry, queue); > + > + list_del(>queue); > cl->txq_ofs = 0; > - cl->tx_queue[cl->txq_cur] = NULL; > - cl->txq_cur = (cl->txq_cur + 1) % ARRAY_SIZE(cl->tx_queue); > + ubus_msg_free(entry->msg); > + free(entry); > } > > static void handle_client_disconnect(struct ubus_client *cl) > diff --git a/ubusd.h b/ubusd.h > index 4d87920..8758916 100644 > --- a/ubusd.h > +++ b/ubusd.h > @@ -23,7 +23,6 @@ > #include "ubusmsg.h" > #include "ubusd_acl.h" > > -#define UBUSD_CLIENT_BACKLOG 32 > #define UBUS_OBJ_HASH_BITS 4 > > extern struct blob_buf b; > @@ -36,6 +35,11 @@ struct ubus_msg_buf { > int len; > }; > > +struct ubus_msg_qentry { > + struct list_head queue; > + struct ubus_msg_buf *msg; > +}; > + > struct ubus_client { > struct ubus_id id; > struct uloop_fd sock; > @@ -48,8 +52,8 @@ struct ubus_client { > > struct list_head objects; > > - struct ubus_msg_buf *tx_queue[UBUSD_CLIENT_BACKLOG]; > - unsigned int txq_cur, txq_tail, txq_ofs; > + struct list_head tx_queue; > + unsigned int txq_ofs; > > struct ubus_msg_buf *pending_msg; > struct ubus_msg_buf *retmsg; > diff --git a/ubusd_proto.c b/ubusd_proto.c > index 2d04b5a..ac9d075 100644 > --- a/ubusd_proto.c > +++ b/ubusd_proto.c > @@ -495,6 +495,7 @@ struct ubus_client *ubusd_proto_new_client(int > fd, uloop_fd_handler cb) > goto free; > > INIT_LIST_HEAD(>objects); > + INIT_LIST_HEAD(>tx_queue); > cl->sock.fd = fd; > cl->sock.cb = cb; > cl->pending_msg_fd = -1; ___ Lede-dev mailing list Lede-dev@lists.infradead.org http://lists.infradead.org/mailman/listinfo/lede-dev
Re: [LEDE-DEV] [PATCH] ubusd: Use linked list for queued messages
Hi Felix, I understand. I just sent an alternative patch which maintains an independent linked list which I think should circumvent the corruption of the same. This of course introduces some additional memory allocation on the heap. When this shouldn't be an option, what would be your suggestion to deal with the problem of a higher number of objects and then trying to list them? Maybe we could also wait until the written data to the socket is flushed for each found object in that case? Benjamin On Thu, 2018-05-03 at 11:07 +0200, Felix Fietkau wrote: > Hi Benjamin, > > On 2018-05-02 22:55, Benjamin Hansmann wrote: > > The fixed size array for queuing messages led to discarding > > messages > > when it was full, using a linked list instead solves this issue. > > > > Having the list_head link in the ubus_msg_buf itself avoids the > > allocation of more memory for an independent list. > > > > The motivation was that for a recursive "ubus list" the function > > ubusd_proto.c:ubusd_handle_lookup() produces more than n messages > > in > > one uloop cycle when n objects are registered on the bus. > > > > Signed-off-by: Benjamin Hansmann > > The reason for using an array is that a message can be queued for > multiple clients. Doing that with your patch could corrupt the list > in > that case. > > - Felix > > ___ > Lede-dev mailing list > Lede-dev@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/lede-dev ___ Lede-dev mailing list Lede-dev@lists.infradead.org http://lists.infradead.org/mailman/listinfo/lede-dev
[LEDE-DEV] [PATCH] ubusd: Use linked list for queued messages (alt.)
The fixed size array for queuing messages led to discarding messages when it was full, using a linked list instead solves this issue. The motivation was that for a recursive "ubus list" the function ubusd_proto.c:ubusd_handle_lookup() produces more than n messages in one uloop cycle when n objects are registered on the bus. Signed-off-by: Benjamin Hansmann --- ubusd.c | 29 + ubusd.h | 10 +++--- ubusd_proto.c | 1 + 3 files changed, 25 insertions(+), 15 deletions(-) diff --git a/ubusd.c b/ubusd.c index ba1ff07..e58624a 100644 --- a/ubusd.c +++ b/ubusd.c @@ -138,11 +138,11 @@ static int ubus_msg_writev(int fd, struct ubus_msg_buf *ub, int offset) static void ubus_msg_enqueue(struct ubus_client *cl, struct ubus_msg_buf *ub) { - if (cl->tx_queue[cl->txq_tail]) + struct ubus_msg_qentry *entry = calloc(1, sizeof(*entry)); + if (!entry) return; - - cl->tx_queue[cl->txq_tail] = ubus_msg_ref(ub); - cl->txq_tail = (cl->txq_tail + 1) % ARRAY_SIZE(cl->tx_queue); + entry->msg = ubus_msg_ref(ub); + list_add_tail(>queue, >tx_queue); } /* takes the msgbuf reference */ @@ -153,7 +153,7 @@ void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub) if (ub->hdr.type != UBUS_MSG_MONITOR) ubusd_monitor_message(cl, ub, true); - if (!cl->tx_queue[cl->txq_cur]) { + if (list_empty(>tx_queue)) { written = ubus_msg_writev(cl->sock.fd, ub, 0); if (written < 0) @@ -172,20 +172,25 @@ void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub) static struct ubus_msg_buf *ubus_msg_head(struct ubus_client *cl) { - return cl->tx_queue[cl->txq_cur]; + if (list_empty(>tx_queue)) + return NULL; + struct ubus_msg_qentry *entry; + entry = list_first_entry(>tx_queue, struct ubus_msg_qentry, queue); + return entry->msg; } static void ubus_msg_dequeue(struct ubus_client *cl) { - struct ubus_msg_buf *ub = ubus_msg_head(cl); - - if (!ub) + if (list_empty(>tx_queue)) return; - ubus_msg_free(ub); + struct ubus_msg_qentry *entry; + entry = list_first_entry(>tx_queue, struct ubus_msg_qentry, queue); + + list_del(>queue); cl->txq_ofs = 0; - cl->tx_queue[cl->txq_cur] = NULL; - cl->txq_cur = (cl->txq_cur + 1) % ARRAY_SIZE(cl->tx_queue); + ubus_msg_free(entry->msg); + free(entry); } static void handle_client_disconnect(struct ubus_client *cl) diff --git a/ubusd.h b/ubusd.h index 4d87920..8758916 100644 --- a/ubusd.h +++ b/ubusd.h @@ -23,7 +23,6 @@ #include "ubusmsg.h" #include "ubusd_acl.h" -#define UBUSD_CLIENT_BACKLOG 32 #define UBUS_OBJ_HASH_BITS 4 extern struct blob_buf b; @@ -36,6 +35,11 @@ struct ubus_msg_buf { int len; }; +struct ubus_msg_qentry { + struct list_head queue; + struct ubus_msg_buf *msg; +}; + struct ubus_client { struct ubus_id id; struct uloop_fd sock; @@ -48,8 +52,8 @@ struct ubus_client { struct list_head objects; - struct ubus_msg_buf *tx_queue[UBUSD_CLIENT_BACKLOG]; - unsigned int txq_cur, txq_tail, txq_ofs; + struct list_head tx_queue; + unsigned int txq_ofs; struct ubus_msg_buf *pending_msg; struct ubus_msg_buf *retmsg; diff --git a/ubusd_proto.c b/ubusd_proto.c index 2d04b5a..ac9d075 100644 --- a/ubusd_proto.c +++ b/ubusd_proto.c @@ -495,6 +495,7 @@ struct ubus_client *ubusd_proto_new_client(int fd, uloop_fd_handler cb) goto free; INIT_LIST_HEAD(>objects); + INIT_LIST_HEAD(>tx_queue); cl->sock.fd = fd; cl->sock.cb = cb; cl->pending_msg_fd = -1; -- 2.11.0 ___ Lede-dev mailing list Lede-dev@lists.infradead.org http://lists.infradead.org/mailman/listinfo/lede-dev
Re: [LEDE-DEV] [PATCH] ubusd: Use linked list for queued messages
Hi Benjamin, On 2018-05-02 22:55, Benjamin Hansmann wrote: > The fixed size array for queuing messages led to discarding messages > when it was full, using a linked list instead solves this issue. > > Having the list_head link in the ubus_msg_buf itself avoids the > allocation of more memory for an independent list. > > The motivation was that for a recursive "ubus list" the function > ubusd_proto.c:ubusd_handle_lookup() produces more than n messages in > one uloop cycle when n objects are registered on the bus. > > Signed-off-by: Benjamin Hansmann The reason for using an array is that a message can be queued for multiple clients. Doing that with your patch could corrupt the list in that case. - Felix ___ Lede-dev mailing list Lede-dev@lists.infradead.org http://lists.infradead.org/mailman/listinfo/lede-dev
Re: [LEDE-DEV] [PATCH] ubusd: Use linked list for queued messages
On Wed, May 2, 2018 at 11:55 PM, Benjamin Hansmann wrote: > The fixed size array for queuing messages led to discarding messages > when it was full, using a linked list instead solves this issue. > > Having the list_head link in the ubus_msg_buf itself avoids the > allocation of more memory for an independent list. > > The motivation was that for a recursive "ubus list" the function > ubusd_proto.c:ubusd_handle_lookup() produces more than n messages in > one uloop cycle when n objects are registered on the bus. > Hey, I second this patch. I also proposed it a while back http://patchwork.ozlabs.org/patch/772366/ This was part of a series of ubus fixes. I added a test that shows the issue [I was seeing]: http://patchwork.ozlabs.org/patch/772365/ The issue [I was seeing] was]more of a fast-producer - slow-consumer issue. This was caused mostly when running a ubus cmd on the TTY serial [ causing a slowdown which showed the issue ]. But in my case, another patch had a greater impact that the dynamic TX queue ; this one: http://patchwork.ozlabs.org/patch/772364/ I was never hitting the 32 entries limit. I also discarded this patch [at the time] because I was unsure whether it causes more issues [than it solves]. And did not have time to go more in-depth with it. But I think, that if this helps your case, it should be good. Also [with this occasion]: thanks Felix for merging my other ubus patches. Thanks Alex > Signed-off-by: Benjamin Hansmann > --- > ubusd.c | 19 --- > ubusd.h | 6 +++--- > ubusd_proto.c | 1 + > 3 files changed, 12 insertions(+), 14 deletions(-) > > diff --git a/ubusd.c b/ubusd.c > index ba1ff07..b7e1f79 100644 > --- a/ubusd.c > +++ b/ubusd.c > @@ -138,11 +138,8 @@ static int ubus_msg_writev(int fd, struct ubus_msg_buf > *ub, int offset) > > static void ubus_msg_enqueue(struct ubus_client *cl, struct ubus_msg_buf *ub) > { > - if (cl->tx_queue[cl->txq_tail]) > - return; > - > - cl->tx_queue[cl->txq_tail] = ubus_msg_ref(ub); > - cl->txq_tail = (cl->txq_tail + 1) % ARRAY_SIZE(cl->tx_queue); > + struct ubus_msg_buf *qub = ubus_msg_ref(ub); > + list_add_tail(>queue, >tx_queue); > } > > /* takes the msgbuf reference */ > @@ -153,7 +150,7 @@ void ubus_msg_send(struct ubus_client *cl, struct > ubus_msg_buf *ub) > if (ub->hdr.type != UBUS_MSG_MONITOR) > ubusd_monitor_message(cl, ub, true); > > - if (!cl->tx_queue[cl->txq_cur]) { > + if (list_empty(>tx_queue)) { > written = ubus_msg_writev(cl->sock.fd, ub, 0); > > if (written < 0) > @@ -172,20 +169,20 @@ void ubus_msg_send(struct ubus_client *cl, struct > ubus_msg_buf *ub) > > static struct ubus_msg_buf *ubus_msg_head(struct ubus_client *cl) > { > - return cl->tx_queue[cl->txq_cur]; > + if (list_empty(>tx_queue)) > + return NULL; > + return list_first_entry(>tx_queue, struct ubus_msg_buf, queue); > } > > static void ubus_msg_dequeue(struct ubus_client *cl) > { > struct ubus_msg_buf *ub = ubus_msg_head(cl); > - > if (!ub) > return; > > - ubus_msg_free(ub); > + list_del_init(>queue); > cl->txq_ofs = 0; > - cl->tx_queue[cl->txq_cur] = NULL; > - cl->txq_cur = (cl->txq_cur + 1) % ARRAY_SIZE(cl->tx_queue); > + ubus_msg_free(ub); > } > > static void handle_client_disconnect(struct ubus_client *cl) > diff --git a/ubusd.h b/ubusd.h > index 4d87920..375f31f 100644 > --- a/ubusd.h > +++ b/ubusd.h > @@ -23,13 +23,13 @@ > #include "ubusmsg.h" > #include "ubusd_acl.h" > > -#define UBUSD_CLIENT_BACKLOG 32 > #define UBUS_OBJ_HASH_BITS 4 > > extern struct blob_buf b; > > struct ubus_msg_buf { > uint32_t refcount; /* ~0: uses external data buffer */ > + struct list_head queue; > struct ubus_msghdr hdr; > struct blob_attr *data; > int fd; > @@ -48,8 +48,8 @@ struct ubus_client { > > struct list_head objects; > > - struct ubus_msg_buf *tx_queue[UBUSD_CLIENT_BACKLOG]; > - unsigned int txq_cur, txq_tail, txq_ofs; > + struct list_head tx_queue; > + unsigned int txq_ofs; > > struct ubus_msg_buf *pending_msg; > struct ubus_msg_buf *retmsg; > diff --git a/ubusd_proto.c b/ubusd_proto.c > index 2d04b5a..ac9d075 100644 > --- a/ubusd_proto.c > +++ b/ubusd_proto.c > @@ -495,6 +495,7 @@ struct ubus_client *ubusd_proto_new_client(int fd, > uloop_fd_handler cb) > goto free; > > INIT_LIST_HEAD(>objects); > + INIT_LIST_HEAD(>tx_queue); > cl->sock.fd = fd; > cl->sock.cb = cb; > cl->pending_msg_fd = -1; > -- > 2.11.0 > > > ___ > Lede-dev mailing list > Lede-dev@lists.infradead.org > http://lists.infradead.org/mailman/listinfo/lede-dev ___ Lede-dev mailing list
[LEDE-DEV] [PATCH] ubusd: Use linked list for queued messages
The fixed size array for queuing messages led to discarding messages when it was full, using a linked list instead solves this issue. Having the list_head link in the ubus_msg_buf itself avoids the allocation of more memory for an independent list. The motivation was that for a recursive "ubus list" the function ubusd_proto.c:ubusd_handle_lookup() produces more than n messages in one uloop cycle when n objects are registered on the bus. Signed-off-by: Benjamin Hansmann --- ubusd.c | 19 --- ubusd.h | 6 +++--- ubusd_proto.c | 1 + 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/ubusd.c b/ubusd.c index ba1ff07..b7e1f79 100644 --- a/ubusd.c +++ b/ubusd.c @@ -138,11 +138,8 @@ static int ubus_msg_writev(int fd, struct ubus_msg_buf *ub, int offset) static void ubus_msg_enqueue(struct ubus_client *cl, struct ubus_msg_buf *ub) { - if (cl->tx_queue[cl->txq_tail]) - return; - - cl->tx_queue[cl->txq_tail] = ubus_msg_ref(ub); - cl->txq_tail = (cl->txq_tail + 1) % ARRAY_SIZE(cl->tx_queue); + struct ubus_msg_buf *qub = ubus_msg_ref(ub); + list_add_tail(>queue, >tx_queue); } /* takes the msgbuf reference */ @@ -153,7 +150,7 @@ void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub) if (ub->hdr.type != UBUS_MSG_MONITOR) ubusd_monitor_message(cl, ub, true); - if (!cl->tx_queue[cl->txq_cur]) { + if (list_empty(>tx_queue)) { written = ubus_msg_writev(cl->sock.fd, ub, 0); if (written < 0) @@ -172,20 +169,20 @@ void ubus_msg_send(struct ubus_client *cl, struct ubus_msg_buf *ub) static struct ubus_msg_buf *ubus_msg_head(struct ubus_client *cl) { - return cl->tx_queue[cl->txq_cur]; + if (list_empty(>tx_queue)) + return NULL; + return list_first_entry(>tx_queue, struct ubus_msg_buf, queue); } static void ubus_msg_dequeue(struct ubus_client *cl) { struct ubus_msg_buf *ub = ubus_msg_head(cl); - if (!ub) return; - ubus_msg_free(ub); + list_del_init(>queue); cl->txq_ofs = 0; - cl->tx_queue[cl->txq_cur] = NULL; - cl->txq_cur = (cl->txq_cur + 1) % ARRAY_SIZE(cl->tx_queue); + ubus_msg_free(ub); } static void handle_client_disconnect(struct ubus_client *cl) diff --git a/ubusd.h b/ubusd.h index 4d87920..375f31f 100644 --- a/ubusd.h +++ b/ubusd.h @@ -23,13 +23,13 @@ #include "ubusmsg.h" #include "ubusd_acl.h" -#define UBUSD_CLIENT_BACKLOG 32 #define UBUS_OBJ_HASH_BITS 4 extern struct blob_buf b; struct ubus_msg_buf { uint32_t refcount; /* ~0: uses external data buffer */ + struct list_head queue; struct ubus_msghdr hdr; struct blob_attr *data; int fd; @@ -48,8 +48,8 @@ struct ubus_client { struct list_head objects; - struct ubus_msg_buf *tx_queue[UBUSD_CLIENT_BACKLOG]; - unsigned int txq_cur, txq_tail, txq_ofs; + struct list_head tx_queue; + unsigned int txq_ofs; struct ubus_msg_buf *pending_msg; struct ubus_msg_buf *retmsg; diff --git a/ubusd_proto.c b/ubusd_proto.c index 2d04b5a..ac9d075 100644 --- a/ubusd_proto.c +++ b/ubusd_proto.c @@ -495,6 +495,7 @@ struct ubus_client *ubusd_proto_new_client(int fd, uloop_fd_handler cb) goto free; INIT_LIST_HEAD(>objects); + INIT_LIST_HEAD(>tx_queue); cl->sock.fd = fd; cl->sock.cb = cb; cl->pending_msg_fd = -1; -- 2.11.0 ___ Lede-dev mailing list Lede-dev@lists.infradead.org http://lists.infradead.org/mailman/listinfo/lede-dev