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