[libvirt] [PATCH v4 07/13] Add support for async close of client RPC socket

2011-10-27 Thread Jiri Denemark
---
Notes:
ACKed

Version 4:
- no changes

Version 3:
- no changes

Version 2:
- no changes

 src/rpc/virnetclient.c |   76 ++--
 1 files changed, 67 insertions(+), 9 deletions(-)

diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 58ba66d..aaf072a 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -95,9 +95,13 @@ struct _virNetClient {
 
 size_t nstreams;
 virNetClientStreamPtr *streams;
+
+bool wantClose;
 };
 
 
+void virNetClientRequestClose(virNetClientPtr client);
+
 static int virNetClientSendInternal(virNetClientPtr client,
 virNetMessagePtr msg,
 bool expectReply,
@@ -307,12 +311,14 @@ void virNetClientFree(virNetClientPtr client)
 }
 
 
-void virNetClientClose(virNetClientPtr client)
+static void
+virNetClientCloseLocked(virNetClientPtr client)
 {
-if (!client)
+VIR_DEBUG("client=%p, sock=%p", client, client->sock);
+
+if (!client->sock)
 return;
 
-virNetClientLock(client);
 virNetSocketRemoveIOCallback(client->sock);
 virNetSocketFree(client->sock);
 client->sock = NULL;
@@ -322,6 +328,41 @@ void virNetClientClose(virNetClientPtr client)
 virNetSASLSessionFree(client->sasl);
 client->sasl = NULL;
 #endif
+client->wantClose = false;
+}
+
+void virNetClientClose(virNetClientPtr client)
+{
+if (!client)
+return;
+
+virNetClientLock(client);
+virNetClientCloseLocked(client);
+virNetClientUnlock(client);
+}
+
+void
+virNetClientRequestClose(virNetClientPtr client)
+{
+VIR_DEBUG("client=%p", client);
+
+virNetClientLock(client);
+
+/* If there is a thread polling for data on the socket, set wantClose flag
+ * and wake the thread up or just immediately close the socket when no-one
+ * is polling on it.
+ */
+if (client->waitDispatch) {
+char ignore = 1;
+int len = sizeof(ignore);
+
+client->wantClose = true;
+if (safewrite(client->wakeupSendFD, &ignore, len) != len)
+VIR_ERROR(_("failed to wake up polling thread"));
+} else {
+virNetClientCloseLocked(client);
+}
+
 virNetClientUnlock(client);
 }
 
@@ -978,11 +1019,12 @@ static int virNetClientIOEventLoop(virNetClientPtr 
client,
 sigset_t oldmask, blockedsigs;
 int timeout = -1;
 
-/* If we have existing SASL decoded data we
- * don't want to sleep in the poll(), just
- * check if any other FDs are also ready
+/* If we have existing SASL decoded data we don't want to sleep in
+ * the poll(), just check if any other FDs are also ready.
+ * If the connection is going to be closed, we don't want to sleep in
+ * poll() either.
  */
-if (virNetSocketHasCachedData(client->sock))
+if (virNetSocketHasCachedData(client->sock) || client->wantClose)
 timeout = 0;
 
 fds[0].events = fds[0].revents = 0;
@@ -1047,6 +1089,11 @@ static int virNetClientIOEventLoop(virNetClientPtr 
client,
 if (virNetSocketHasCachedData(client->sock))
 fds[0].revents |= POLLIN;
 
+/* If wantClose flag is set, pretend there was an error on the socket
+ */
+if (client->wantClose)
+fds[0].revents = POLLERR;
+
 if (fds[1].revents) {
 VIR_DEBUG("Woken up from poll by other thread");
 if (saferead(client->wakeupReadFD, &ignore, sizeof(ignore)) != 
sizeof(ignore)) {
@@ -1140,6 +1187,8 @@ pass:
 if (client->waitDispatch) {
 VIR_DEBUG("Passing the buck to %p", client->waitDispatch);
 virCondSignal(&client->waitDispatch->cond);
+} else if (client->wantClose) {
+virNetClientCloseLocked(client);
 }
 return ret;
 }
@@ -1281,7 +1330,8 @@ static int virNetClientIO(virNetClientPtr client,
 virResetLastError();
 rv = virNetClientIOEventLoop(client, thiscall);
 
-virNetSocketUpdateIOCallback(client->sock, VIR_EVENT_HANDLE_READABLE);
+if (client->sock)
+virNetSocketUpdateIOCallback(client->sock, VIR_EVENT_HANDLE_READABLE);
 
 if (rv == 0 &&
 virGetLastError())
@@ -1305,7 +1355,7 @@ void virNetClientIncomingEvent(virNetSocketPtr sock,
 goto done;
 
 /* This should be impossible, but it doesn't hurt to check */
-if (client->waitDispatch)
+if (client->waitDispatch || client->wantClose)
 goto done;
 
 VIR_DEBUG("Event fired %p %d", sock, events);
@@ -1357,6 +1407,12 @@ virNetClientSendInternal(virNetClientPtr client,
 
 virNetClientLock(client);
 
+if (!client->sock || client->wantClose) {
+virNetError(VIR_ERR_INTERNAL_ERROR, "%s",
+_("Client socket is closed"));
+goto unlock;
+}
+
 /* We don't need call->cond for non-blocking calls since there's no
  * thread to be woken up anyway
  */
@@

Re: [libvirt] [PATCH v4 07/13] Add support for async close of client RPC socket

2011-11-07 Thread Daniel P. Berrange
On Thu, Oct 27, 2011 at 06:05:43PM +0200, Jiri Denemark wrote:
> ---
> Notes:
> ACKed
> 
> Version 4:
> - no changes
> 
> Version 3:
> - no changes
> 
> Version 2:
> - no changes
> 
>  src/rpc/virnetclient.c |   76 
> ++--
>  1 files changed, 67 insertions(+), 9 deletions(-)

ACK

Daniel
-- 
|: http://berrange.com  -o-http://www.flickr.com/photos/dberrange/ :|
|: http://libvirt.org  -o- http://virt-manager.org :|
|: http://autobuild.org   -o- http://search.cpan.org/~danberr/ :|
|: http://entangle-photo.org   -o-   http://live.gnome.org/gtk-vnc :|

--
libvir-list mailing list
libvir-list@redhat.com
https://www.redhat.com/mailman/listinfo/libvir-list