about summary refs log tree commit diff
path: root/sysdeps/mach/hurd/select.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/mach/hurd/select.c')
-rw-r--r--sysdeps/mach/hurd/select.c191
1 files changed, 102 insertions, 89 deletions
diff --git a/sysdeps/mach/hurd/select.c b/sysdeps/mach/hurd/select.c
index 60bb489612..aa99944e84 100644
--- a/sysdeps/mach/hurd/select.c
+++ b/sysdeps/mach/hurd/select.c
@@ -117,67 +117,76 @@ DEFUN(__select, (nfds, readfds, writefds, exceptfds, timeout),
     return -1;
 
   /* Send them all io_select request messages.  */
-  err = 0;
-  got = 0;
-  portset = MACH_PORT_NULL;
-  for (i = firstfd; i <= lastfd; ++i)
-    if (d[i].type)
-      {
-	int type = d[i].type;
-	d[i].reply_port = __mach_reply_port ();
-	err = __io_select (d[i].io_port, d[i].reply_port,
-			   /* Poll only when there's a single descriptor.  */
-			   (firstfd == lastfd) ? to : 0,
-			   &type);
-	switch (err)
+		     
+  if (firstfd == -1)
+    /* But not if there were no ports to deal with at all. */
+    portset = __mach_reply_port ();
+  else
+    {
+      err = 0;
+      got = 0;
+      portset = MACH_PORT_NULL;
+      
+      for (i = firstfd; i <= lastfd; ++i)
+	if (d[i].type)
 	  {
-	  case MACH_RCV_TIMED_OUT:
-	    /* No immediate response.  This is normal.  */
-	    err = 0;
-	    if (firstfd == lastfd)
-	      /* When there's a single descriptor, we don't need a portset,
-		 so just pretend we have one, but really use the single reply
-		 port.  */
-	      portset = d[i].reply_port;
-	    else if (got == 0)
-	      /* We've got multiple reply ports, so we need a port set to
-		 multiplex them.  */
+	    int type = d[i].type;
+	    d[i].reply_port = __mach_reply_port ();
+	    err = __io_select (d[i].io_port, d[i].reply_port,
+			       /* Poll only if there's a single descriptor.  */
+			       (firstfd == lastfd) ? to : 0,
+			       &type);
+	    switch (err)
 	      {
-		/* We will wait again for a reply later.  */
-		if (portset == MACH_PORT_NULL)
-		  /* Create the portset to receive all the replies on.  */
-		  err = __mach_port_allocate (__mach_task_self (),
-					      MACH_PORT_RIGHT_PORT_SET,
-					      &portset);
-		if (! err)
-		  /* Put this reply port in the port set.  */
-		  __mach_port_move_member (__mach_task_self (),
-					   d[i].reply_port, portset);
+	      case MACH_RCV_TIMED_OUT:
+		/* No immediate response.  This is normal.  */
+		err = 0;
+		if (firstfd == lastfd)
+		  /* When there's a single descriptor, we don't need a
+		     portset, so just pretend we have one, but really
+		     use the single reply port.  */
+		  portset = d[i].reply_port;
+		else if (got == 0)
+		  /* We've got multiple reply ports, so we need a port set to
+		     multiplex them.  */
+		  {
+		    /* We will wait again for a reply later.  */
+		    if (portset == MACH_PORT_NULL)
+		      /* Create the portset to receive all the replies on.  */
+		      err = __mach_port_allocate (__mach_task_self (),
+						  MACH_PORT_RIGHT_PORT_SET,
+						  &portset);
+		    if (! err)
+		      /* Put this reply port in the port set.  */
+		      __mach_port_move_member (__mach_task_self (),
+					       d[i].reply_port, portset);
+		  }
+		break;
+
+	      default:
+		/* No other error should happen.  Callers of select
+		   don't expect to see errors, so we simulate
+		   readiness of the erring object and the next call
+		   hopefully will get the error again.  */
+		type = SELECT_ALL;
+		/* FALLTHROUGH */
+
+	      case 0:
+		/* We got an answer.  */
+		if ((type & SELECT_ALL) == 0)
+		  /* Bogus answer; treat like an error, as a fake positive.  */
+		  type = SELECT_ALL;
+		
+		/* This port is already ready already.  */
+		d[i].type &= type;
+		d[i].type |= SELECT_RETURNED;
+		++got;
+		break;
 	      }
-	    break;
-
-	  default:
-	    /* No other error should happen.  Callers of select don't
-	       expect to see errors, so we simulate readiness of the erring
-	       object and the next call hopefully will get the error again.  */
-	    type = SELECT_ALL;
-	    /* FALLTHROUGH */
-
-	  case 0:
-	    /* We got an answer.  */
-	    if ((type & SELECT_ALL) == 0)
-	      /* Bogus answer; treat like an error, as a fake positive.  */
-	      type = SELECT_ALL;
-
-	    /* This port is already ready already.  */
-	    d[i].type &= type;
-	    d[i].type |= SELECT_RETURNED;
-	    ++got;
-	    break;
+	    _hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
 	  }
-	_hurd_port_free (&d[i].cell->port, &d[i].ulink, d[i].io_port);
-      }
-
+    }
+  
   /* Now wait for reply messages.  */
   if (!err && got == 0)
     {
@@ -234,7 +243,7 @@ DEFUN(__select, (nfds, readfds, writefds, exceptfds, timeout),
 		  (msg.success.result & SELECT_ALL) == 0)
 		{
 		  /* Error or bogus reply.  Simulate readiness.  */
-		  __mach_msg_destroy (&msg);
+		  __mach_msg_destroy (&msg.head);
 		  msg.success.result = SELECT_ALL;
 		}
 
@@ -242,13 +251,15 @@ DEFUN(__select, (nfds, readfds, writefds, exceptfds, timeout),
                  readiness.  */
 	      {
 		int had = got;
-		for (i = firstfd; i <= lastfd; ++i)
-		  if (d[i].type && d[i].reply_port == msg.head.msgh_local_port)
-		    {
-		      d[i].type &= msg.success.result;
-		      d[i].type |= SELECT_RETURNED;
-		      ++got;
-		    }
+		if (firstfd != -1)
+		  for (i = firstfd; i <= lastfd; ++i)
+		    if (d[i].type
+			&& d[i].reply_port == msg.head.msgh_local_port)
+		      {
+			d[i].type &= msg.success.result;
+			d[i].type |= SELECT_RETURNED;
+			++got;
+		      }
 		assert (got > had);
 	      }
 	    }
@@ -280,10 +291,11 @@ DEFUN(__select, (nfds, readfds, writefds, exceptfds, timeout),
 	err = 0;
     }
 
-  for (i = firstfd; i <= lastfd; ++i)
-    if (d[i].type)
-      __mach_port_destroy (__mach_task_self (), d[i].reply_port);
-  if (firstfd != lastfd && portset != MACH_PORT_NULL)
+  if (firstfd != -1)
+    for (i = firstfd; i <= lastfd; ++i)
+      if (d[i].type)
+	__mach_port_destroy (__mach_task_self (), d[i].reply_port);
+  if (firstfd == -1 || (firstfd != lastfd && portset != MACH_PORT_NULL))
     /* Destroy PORTSET, but only if it's not actually the reply port for a
        single descriptor (in which case it's destroyed in the previous loop;
        not doing it here is just a bit more efficient).  */
@@ -298,26 +310,27 @@ DEFUN(__select, (nfds, readfds, writefds, exceptfds, timeout),
 
   /* Set the user bitarrays.  We only ever have to clear bits, as all desired
      ones are initially set.  */
-  for (i = firstfd; i <= lastfd; ++i)
-    {
-      int type = d[i].type;
-
-      if ((type & SELECT_RETURNED) == 0)
-	type = 0;
-
-      if (type & SELECT_READ)
-	got++;
-      else if (readfds)
-	FD_CLR (i, readfds);
-      if (type & SELECT_WRITE)
-	got++;
-      else if (writefds)
-	FD_CLR (i, writefds);
-      if (type & SELECT_URG)
-	got++;
-      else if (exceptfds)
-	FD_CLR (i, exceptfds);
-    }
+  if (firstfd != -1)
+    for (i = firstfd; i <= lastfd; ++i)
+      {
+	int type = d[i].type;
+	
+	if ((type & SELECT_RETURNED) == 0)
+	  type = 0;
+
+	if (type & SELECT_READ)
+	  got++;
+	else if (readfds)
+	  FD_CLR (i, readfds);
+	if (type & SELECT_WRITE)
+	  got++;
+	else if (writefds)
+	  FD_CLR (i, writefds);
+	if (type & SELECT_URG)
+	  got++;
+	else if (exceptfds)
+	  FD_CLR (i, exceptfds);
+      }
 
   return got;
 }