On Fri, Nov 11, 2011 at 16:21:59 +0000, Daniel P. Berrange wrote:
> From: "Daniel P. Berrange" <[email protected]>
>
> Directly messing around with the linked list is potentially
> dangerous. Introduce some helper APIs to deal with list
> manipulating the list
>
> * src/rpc/virnetclient.c: Create linked list handlers
> ---
> src/rpc/virnetclient.c | 207
> +++++++++++++++++++++++++++++++++---------------
> 1 files changed, 144 insertions(+), 63 deletions(-)
>
> diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
> index 4b7d4a9..463dc5a 100644
> --- a/src/rpc/virnetclient.c
> +++ b/src/rpc/virnetclient.c
> @@ -110,6 +110,97 @@ static void virNetClientIncomingEvent(virNetSocketPtr
> sock,
> int events,
> void *opaque);
>
> +/* Append a call to the end of the list */
> +static void virNetClientCallQueue(virNetClientCallPtr *head,
> + virNetClientCallPtr call)
> +{
> + virNetClientCallPtr tmp = *head;
> + while (tmp && tmp->next) {
> + tmp = tmp->next;
> + }
> + if (tmp)
> + tmp->next = call;
> + else
> + *head = call;
> + call->next = NULL;
> +}
> +
> +#if 0
> +/* Obtain a call from the head of the list */
> +static virNetClientCallPtr virNetClientCallServe(virNetClientCallPtr *head)
> +{
> + virNetClientCallPtr tmp = *head;
> + if (tmp)
> + *head = tmp->next;
> + else
> + *head = NULL;
> + tmp->next = NULL;
> + return tmp;
> +}
> +#endif
> +
> +/* Remove a call from anywhere in the list */
> +static void virNetClientCallRemove(virNetClientCallPtr *head,
> + virNetClientCallPtr call)
> +{
> + virNetClientCallPtr tmp = *head;
> + virNetClientCallPtr prev = NULL;
> + while (tmp) {
> + if (tmp == call) {
> + if (prev)
> + prev->next = tmp->next;
> + else
> + *head = tmp->next;
> + tmp->next = NULL;
> + return;
> + }
> + prev = tmp;
> + tmp = tmp->next;
> + }
> +}
> +
> +/* Predicate returns true if matches */
> +typedef bool (*virNetClientCallPredicate)(virNetClientCallPtr call, void
> *opaque);
> +
> +/* Remove a list of calls from the list based on a predicate */
> +static void virNetClientCallRemovePredicate(virNetClientCallPtr *head,
> + virNetClientCallPredicate pred,
> + void *opaque)
> +{
> + virNetClientCallPtr tmp = *head;
> + virNetClientCallPtr prev = NULL;
> + while (tmp) {
> + virNetClientCallPtr next = tmp->next;
> + tmp->next = NULL; /* Temp unlink */
> + if (pred(tmp, opaque)) {
> + if (prev)
> + prev->next = next;
> + else
> + *head = next;
> + } else {
> + tmp->next = next; /* Reverse temp unlink */
> + prev = tmp;
> + }
> + tmp = next;
> + }
> +}
> +
> +/* Returns true if the predicate matches at least one call in the list */
> +static bool virNetClientCallMatchPredicate(virNetClientCallPtr head,
> + virNetClientCallPredicate pred,
> + void *opaque)
> +{
> + virNetClientCallPtr tmp = head;
> + while (tmp) {
> + if (pred(tmp, opaque)) {
> + return true;
> + }
> + tmp = tmp->next;
> + }
> + return false;
> +}
> +
> +
> static void virNetClientEventFree(void *opaque)
> {
> virNetClientPtr client = opaque;
> @@ -896,6 +987,42 @@ virNetClientIOHandleInput(virNetClientPtr client)
> }
>
>
> +static bool virNetClientIOEventLoopPollEvents(virNetClientCallPtr call,
> + void *opaque)
> +{
> + struct pollfd *fd = opaque;
> +
> + if (call->mode == VIR_NET_CLIENT_MODE_WAIT_RX)
> + fd->events |= POLLIN;
> + if (call->mode == VIR_NET_CLIENT_MODE_WAIT_TX)
> + fd->events |= POLLOUT;
> +
> + return true;
> +}
This should return false otherwise we only set fd->events according to the
first call in the queue. We need to go through all calls.
> +
> +
> +static bool virNetClientIOEventLoopRemoveDone(virNetClientCallPtr call,
> + void *opaque)
> +{
> + virNetClientCallPtr thiscall = opaque;
> +
> + if (call == thiscall)
> + return false;
> +
> + if (call->mode != VIR_NET_CLIENT_MODE_COMPLETE)
> + return false;
> +
> + /*
> + * ...they won't actually wakeup until
> + * we release our mutex a short while
> + * later...
> + */
> + VIR_DEBUG("Waking up sleeping call %p", call);
> + virCondSignal(&call->cond);
> +
> + return true;
> +}
> +
> /*
> * Process all calls pending dispatch/receive until we
> * get a reply to our own call. Then quit and pass the buck
> @@ -911,8 +1038,6 @@ static int virNetClientIOEventLoop(virNetClientPtr
> client,
> fds[1].fd = client->wakeupReadFD;
>
> for (;;) {
> - virNetClientCallPtr tmp = client->waitDispatch;
> - virNetClientCallPtr prev;
> char ignore;
> sigset_t oldmask, blockedsigs;
> int timeout = -1;
> @@ -928,14 +1053,11 @@ static int virNetClientIOEventLoop(virNetClientPtr
> client,
> fds[1].events = fds[1].revents = 0;
>
> fds[1].events = POLLIN;
> - while (tmp) {
> - if (tmp->mode == VIR_NET_CLIENT_MODE_WAIT_RX)
> - fds[0].events |= POLLIN;
> - if (tmp->mode == VIR_NET_CLIENT_MODE_WAIT_TX)
> - fds[0].events |= POLLOUT;
>
> - tmp = tmp->next;
> - }
> + /* Calculate poll events for calls */
> + virNetClientCallMatchPredicate(client->waitDispatch,
> + virNetClientIOEventLoopPollEvents,
> + &fds[0]);
>
> /* We have to be prepared to receive stream data
> * regardless of whether any of the calls waiting
...
And we should avoid lines longer than 80 character, which is mostly not a
problem of this patch but some of the other patches in this series don't
follow this rule (mainly in function prototypes).
ACK with the small issue fixed.
Jirka
--
libvir-list mailing list
[email protected]
https://www.redhat.com/mailman/listinfo/libvir-list