
On Fri, Nov 11, 2011 at 16:21:59 +0000, Daniel P. Berrange wrote:
From: "Daniel P. Berrange" <berrange@redhat.com>
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