bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: test-poll failing on FreeBSD 10/11


From: Daniel P . Berrangé
Subject: Re: test-poll failing on FreeBSD 10/11
Date: Tue, 15 May 2018 08:39:20 +0100
User-agent: Mutt/1.9.5 (2018-04-13)

On Mon, May 14, 2018 at 11:49:55PM -0700, Pádraig Brady wrote:
> On 08/05/18 09:40, Daniel P. Berrangé wrote:
> > Libvirt CI recently started running "make check" on our FreeBSD 10 & 11
> > hosts, and we see frequent failure of the test-poll unit test in gnulib
> > IIUC,  gnulib is not actually building a replacement poll() function
> > on FreeBSD, it is merely running the gnulib test suite against the
> > FreeBSD system impl of poll() and hitting this behaviour.
> > 
> > $ ./gnulib/tests/test-poll
> > Unconnected socket test... passed
> > Connected sockets test... failed (expecting POLLHUP after shutdown)
> > General socket test with fork... failed (expecting POLLHUP after shutdown)
> > Pipe test... passed
> > 
> > Looking at the first failure in test_socket_pair method.
> > 
> > It sets up a listener socket, connects a client, accepts the client
> > and then closes the remote end. It expects the server's client socket
> > to thus show POLLHUP or POLLERR.
> > 
> > When it fails, the poll() is in fact still showing POLLOUT. If you put
> > a sleep between the close () and poll() calls, it will succeed.
> > 
> > So, IIUC, the test is racing with the BSD kernel's handling of socket
> > close - the test can't assume that just because the remote end of the
> > client has been closed, that poll() will immediately show POLLHUP|ERR.
> > 
> > Anyone have ideas on how to make this test more reliable and not depend
> > on the kernel synchronizing the close() state with poll() results
> > immediately ?
> > 
> > Regards,
> > Daniel
> > 
> 
> Yes that test looks racy as the network shutdown is async.
> How about we s/nowait/wait/, and only check for input events.
> The following works on Linux at least:
> 
> --- tests/test-poll.c   2018-05-14 23:46:09.595448490 -0700
> +++ pb/gltests/test-poll.c      2018-05-14 23:45:46.827048159 -0700
> @@ -334,8 +334,9 @@
> 
>    test_pair (c1, c2);
>    close (c1);
> -  ASSERT (write (c2, "foo", 3) == 3);
> -  if ((poll1_nowait (c2, POLLIN | POLLOUT) & (POLLHUP | POLLERR)) == 0)
> +
> +  (void) write (c2, "foo", 3);  // Initiate shutdown
> +  if ((poll1_wait (c2, POLLIN) & (POLLHUP | POLLERR)) == 0)
>      failed ("expecting POLLHUP after shutdown");

Unfortunately that doesn't help at all. I've tried various other tricks
to help synchronization too. For example I put sockets into blocking
mode and then did a read() which returns 0 for EOF as expected, but
poll() still returns POLLIN rather than POLLHUP after that read. I
also tried tweaking SO_LINGER to not effect.  The only awful solution
I can make work is to simply sleep() a short while. eg this patch

diff --git a/tests/test-poll.c b/tests/test-poll.c
index c5e0a92de..e99ab3f4d 100644
--- a/tests/test-poll.c
+++ b/tests/test-poll.c
@@ -252,7 +252,7 @@ test_accept_first (void)
   struct sockaddr_in ia;
   socklen_t addrlen;
   char buf[3];
-  int c, pid;
+  int c, pid, i, rv;
 
   pid = fork ();
   if (pid < 0)
@@ -284,7 +284,12 @@ test_accept_first (void)
         failed ("cannot read data left in the socket by closed process");
       ASSERT (read (c, buf, 3) == 3);
       ASSERT (write (c, "foo", 3) == 3);
-      if ((poll1_wait (c, POLLIN | POLLOUT) & (POLLHUP | POLLERR)) == 0)
+      do {
+          rv = poll1_nowait (c, POLLIN | POLLOUT);
+          usleep(1000);
+          i++;
+      } while ((rv & (POLLHUP | POLLERR)) == 0 && i < 20);
+      if ((rv & (POLLHUP | POLLERR)) == 0)
         failed ("expecting POLLHUP after shutdown");
       close (c);
     }
@@ -330,6 +335,7 @@ test_socket_pair (void)
   int s = open_server_socket ();
   int c1 = connect_to_socket (false);
   int c2 = accept (s, (struct sockaddr *) &ia, &addrlen);
+  int i, rv;
   ASSERT (s >= 0);
   ASSERT (c1 >= 0);
   ASSERT (c2 >= 0);
@@ -339,9 +345,14 @@ test_socket_pair (void)
   test_pair (c1, c2);
   close (c1);
   ASSERT (write (c2, "foo", 3) == 3);
-  if ((poll1_nowait (c2, POLLIN | POLLOUT) & (POLLHUP | POLLERR)) == 0)
-    failed ("expecting POLLHUP after shutdown");
-
+  
+  do {
+      rv = poll1_nowait (c2, POLLIN | POLLOUT);
+      usleep(1000);
+      i++;
+  } while ((rv & (POLLHUP | POLLERR)) == 0 && i < 20);
+  if ((rv & (POLLHUP | POLLERR)) == 0)
+      failed ("expecting POLLHUP after shutdown");
   close (c2);
 }
 


Regards,
Daniel
-- 
|: https://berrange.com      -o-    https://www.flickr.com/photos/dberrange :|
|: https://libvirt.org         -o-            https://fstop138.berrange.com :|
|: https://entangle-photo.org    -o-    https://www.instagram.com/dberrange :|



reply via email to

[Prev in Thread] Current Thread [Next in Thread]