about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog35
-rw-r--r--hurd/Versions3
-rw-r--r--hurd/dtable.c103
-rw-r--r--hurd/hurdfchdir.c39
-rw-r--r--hurd/hurdioctl.c66
-rw-r--r--hurd/hurdsig.c55
-rw-r--r--hurd/msgportdemux.c10
-rw-r--r--hurd/report-wait.c2
-rw-r--r--sysdeps/mach/hurd/fork.c22
-rw-r--r--sysdeps/mach/hurd/setsid.c41
10 files changed, 265 insertions, 111 deletions
diff --git a/ChangeLog b/ChangeLog
index 9c3459ab28..98636dedcd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+1999-11-18  Roland McGrath  <roland@baalperazim.frob.com>
+
+        * hurd/hurdsig.c (_hurdsig_init): If __hurd_threadvar_stack_mask is
+        nonzero, use cthread_fork to create the signal thread.
+        * hurd/msgportdemux.c (_hurd_msgport_receive): Initialize
+        _hurd_msgport_thread here (to self).
+        * sysdeps/mach/hurd/fork.c (__fork): When __hurd_sigthread_stack_end
+        is zero, instead compute child signal thread's starting SP from parent
+        signal thread's current SP and the threadvar_stack variables.
+        * hurd/Versions (GLIBC_2.1.3): Add cthread_fork, cthread_detach.
+        These are now referenced weakly by _hurdsig_init.
+
+        * hurd/report-wait.c (_S_msg_report_wait): Fix typo:
+        &_hurd_itimer_thread not &_hurd_msgport_thread.
+
+1999-10-01  Roland McGrath  <roland@baalperazim.frob.com>
+
+        * hurd/hurdfchdir.c (_hurd_change_directory_port_from_fd): Rewrite
+        without HURD_DPORT_USE to clean up warnings.
+        * hurd/dtable.c (get_dtable_port): Likewise.
+
+        * hurd/hurdioctl.c (rectty_dtable): Renamed to install_ctty.
+        (install_ctty): Do the changing of the cttyid port cell here, inside
+        the critical section while we holding the dtable lock.
+        (_hurd_setcttyid, tiocsctty, tiocnotty): Use that instead of changing
+        the port cell and calling rectty_dtable.
+        (_hurd_locked_install_cttyid): New function, split out of install_ctty.
+        (install_ctty): Use it inside a critical section, with the lock held.
+        * sysdeps/mach/hurd/setsid.c (__setsid): Use
+        _hurd_locked_install_cttyid to effect the cttyid and dtable changes
+        after proc_setsid, having held the dtable lock throughout.
+        * hurd/dtable.c (ctty_new_pgrp): With the dtable lock held, check the
+        cttyid port for null and bail out early if so.  The dtable lock
+        serializes us after any cttyid change and its associated dtable update.
+
 1999-11-14  Roland McGrath  <roland@baalperazim.frob.com>
 
 	* sysdeps/mach/hurd/nfs/nfs.h: New file, empty but for comments.
diff --git a/hurd/Versions b/hurd/Versions
index 5dcdc355d9..a81bc551b2 100644
--- a/hurd/Versions
+++ b/hurd/Versions
@@ -108,6 +108,9 @@ libc {
     seteuids;
   }
   GLIBC_2.1.3 {
+    # c*
+    cthread_fork; cthread_detach;
+
     # d*
     directory_name_split;
 
diff --git a/hurd/dtable.c b/hurd/dtable.c
index 30f6a5ee82..f3eb88fb3a 100644
--- a/hurd/dtable.c
+++ b/hurd/dtable.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 1991, 92, 93, 94, 95, 96, 97 Free Software Foundation, Inc.
+/* Copyright (C) 1991,92,93,94,95,96,97,99 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -107,18 +107,35 @@ text_set_element (_hurd_subinit, init_dtable);
 static file_t
 get_dtable_port (int fd)
 {
+  struct hurd_fd *d = _hurd_fd_get (fd);
   file_t dport;
-  int err = HURD_DPORT_USE (fd, __mach_port_mod_refs (__mach_task_self (),
-						      (dport = port),
-						      MACH_PORT_RIGHT_SEND,
-						      1));
-  if (err)
-    {
-      errno = err;
-      return MACH_PORT_NULL;
-    }
-  else
-    return dport;
+
+  if (!d)
+    return __hurd_fail (EBADF), MACH_PORT_NULL;
+
+  HURD_CRITICAL_BEGIN;
+
+  dport = HURD_PORT_USE (&d->port,
+			 ({
+			   error_t err;
+			   mach_port_t outport;
+			   err = __mach_port_mod_refs (__mach_task_self (),
+						       port,
+						       MACH_PORT_RIGHT_SEND,
+						       1);
+			   if (err)
+			     {
+			       errno = err;
+			       outport = MACH_PORT_NULL;
+			     }
+			   else
+			     outport = port;
+			   outport;
+			 }));
+
+  HURD_CRITICAL_END;
+
+  return dport;
 }
 
 file_t (*_hurd_getdport_fn) (int fd) = get_dtable_port;
@@ -176,32 +193,46 @@ ctty_new_pgrp (void)
   HURD_CRITICAL_BEGIN;
   __mutex_lock (&_hurd_dtable_lock);
 
-  for (i = 0; i < _hurd_dtablesize; ++i)
+  if (__USEPORT (CTTYID, port == MACH_PORT_NULL))
     {
-      struct hurd_fd *const d = _hurd_dtable[i];
-      struct hurd_userlink ulink, ctty_ulink;
-      io_t port, ctty;
-
-      if (d == NULL)
-	/* Nothing to do for an unused descriptor cell.  */
-	continue;
-
-      port = _hurd_port_get (&d->port, &ulink);
-      ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
-
-      if (ctty != MACH_PORT_NULL)
-	{
-	  /* This fd has a ctty-special port.  We need a new one, to tell
-             the io server of our different process group.  */
-	  io_t new;
-	  if (__term_open_ctty (port, _hurd_pid, _hurd_pgrp, &new))
-	    new = MACH_PORT_NULL;
-	  _hurd_port_set (&d->ctty, new);
-	}
-
-      _hurd_port_free (&d->port, &ulink, port);
-      _hurd_port_free (&d->ctty, &ctty_ulink, ctty);
+      /* We have no controlling terminal.  If we haven't had one recently,
+	 but our pgrp is being pointlessly diddled anyway, then we will
+	 have nothing to do in the loop below because no fd will have a
+	 ctty port at all.
+
+	 More likely, a setsid call is responsible both for the change
+	 in pgrp and for clearing the cttyid port.  In that case, setsid
+	 held the dtable lock while updating the dtable to clear all the
+	 ctty ports, and ergo must have finished doing so before we run here.
+	 So we can be sure, again, that the loop below has no work to do.  */
     }
+  else
+    for (i = 0; i < _hurd_dtablesize; ++i)
+      {
+	struct hurd_fd *const d = _hurd_dtable[i];
+	struct hurd_userlink ulink, ctty_ulink;
+	io_t port, ctty;
+
+	if (d == NULL)
+	  /* Nothing to do for an unused descriptor cell.  */
+	  continue;
+
+	port = _hurd_port_get (&d->port, &ulink);
+	ctty = _hurd_port_get (&d->ctty, &ctty_ulink);
+
+	if (ctty != MACH_PORT_NULL)
+	  {
+	    /* This fd has a ctty-special port.  We need a new one, to tell
+	       the io server of our different process group.  */
+	    io_t new;
+	    if (__term_open_ctty (port, _hurd_pid, _hurd_pgrp, &new))
+	      new = MACH_PORT_NULL;
+	    _hurd_port_set (&d->ctty, new);
+	  }
+
+	_hurd_port_free (&d->port, &ulink, port);
+	_hurd_port_free (&d->ctty, &ctty_ulink, ctty);
+      }
 
   __mutex_unlock (&_hurd_dtable_lock);
   HURD_CRITICAL_END;
diff --git a/hurd/hurdfchdir.c b/hurd/hurdfchdir.c
index efb705393e..4a01f0719c 100644
--- a/hurd/hurdfchdir.c
+++ b/hurd/hurdfchdir.c
@@ -27,17 +27,30 @@
 int
 _hurd_change_directory_port_from_fd (struct hurd_port *portcell, int fd)
 {
-  error_t err;
-  file_t dir;
-
-  err = HURD_DPORT_USE (fd,
-			({
-			  dir = __file_name_lookup_under (port, ".", 0, 0);
-			  dir == MACH_PORT_NULL ? errno : 0;
-			}));
-
-  if (! err)
-    _hurd_port_set (portcell, dir);
-
-  return err ? __hurd_fail (err) : 0;
+  int ret;
+  struct hurd_fd *d = _hurd_fd_get (fd);
+
+  if (!d)
+    return __hurd_fail (EBADF);
+
+  HURD_CRITICAL_BEGIN;
+
+  ret = HURD_PORT_USE (&d->port,
+		       ({
+			 int ret;
+			 file_t dir = __file_name_lookup_under (port, ".",
+								0, 0);
+			 if (dir == MACH_PORT_NULL)
+			   ret = -1;
+			 else
+			   {
+			     _hurd_port_set (portcell, dir);
+			     ret = 0;
+			   }
+			 ret;
+		       }));
+
+  HURD_CRITICAL_END;
+
+  return ret;
 }
diff --git a/hurd/hurdioctl.c b/hurd/hurdioctl.c
index 8482571299..073c15edcc 100644
--- a/hurd/hurdioctl.c
+++ b/hurd/hurdioctl.c
@@ -1,5 +1,5 @@
 /* ioctl commands which must be done in the C library.
-   Copyright (C) 1994, 1995, 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1994, 1995, 1996, 1997, 1999 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -132,13 +132,39 @@ _HURD_HANDLE_IOCTLS (fioclex, FIOCLEX, FIONCLEX);
 #include <hurd/term.h>
 #include <hurd/tioctl.h>
 
-static void
-rectty_dtable (mach_port_t cttyid)
+/* Install a new CTTYID port, atomically updating the dtable appropriately.
+   This consumes the send right passed in.  */
+
+void
+_hurd_locked_install_cttyid (mach_port_t cttyid)
 {
+  mach_port_t old;
+  struct hurd_port *const port = &_hurd_ports[INIT_PORT_CTTYID];
+  struct hurd_userlink ulink;
   int i;
 
-  HURD_CRITICAL_BEGIN;
-  __mutex_lock (&_hurd_dtable_lock);
+  /* Install the new cttyid port, and preserve it with a ulink.
+     We unroll the _hurd_port_set + _hurd_port_get here so that
+     there is no window where the cell is unlocked and CTTYID could
+     be changed by another thread.  (We also delay the deallocation
+     of the old port until the end, to minimize the duration of the
+     critical section.)
+
+     It is important that changing the cttyid port is only ever done by
+     holding the dtable lock continuously while updating the port cell and
+     re-ctty'ing the dtable; dtable.c assumes we do this.  Otherwise, the
+     pgrp-change notification code in dtable.c has to worry about racing
+     against us here in odd situations.  The one exception to this is
+     setsid, which holds the dtable lock while changing the pgrp and
+     clearing the cttyid port, and then unlocks the dtable lock to allow
+
+
+  */
+
+  __spin_lock (&port->lock);
+  old = _hurd_userlink_clear (&port->users) ? port->port : MACH_PORT_NULL;
+  port->port = cttyid;
+  cttyid = _hurd_port_locked_get (port, &ulink);
 
   for (i = 0; i < _hurd_dtablesize; ++i)
     {
@@ -178,6 +204,18 @@ rectty_dtable (mach_port_t cttyid)
     }
 
   __mutex_unlock (&_hurd_dtable_lock);
+
+  if (old != MACH_PORT_NULL)
+    __mach_port_deallocate (__mach_task_self (), old);
+  _hurd_port_free (port, &ulink, cttyid);
+}
+
+static void
+install_ctty (mach_port_t cttyid)
+{
+  HURD_CRITICAL_BEGIN;
+  __mutex_lock (&_hurd_dtable_lock);
+  _hurd_locked_install_cttyid (cttyid);
   HURD_CRITICAL_END;
 }
 
@@ -199,10 +237,7 @@ _hurd_setcttyid (mach_port_t cttyid)
     }
 
   /* Install the port, consuming the reference we just created.  */
-  _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid);
-
-  /* Reset all the ctty ports in all the descriptors.  */
-  __USEPORT (CTTYID, (rectty_dtable (cttyid), 0));
+  install_ctty (cttyid);
 
   return 0;
 }
@@ -233,10 +268,7 @@ tiocsctty (int fd,
     return __hurd_fail (err);
 
   /* Make it our own.  */
-  _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], cttyid);
-
-  /* Reset all the ctty ports in all the descriptors.  */
-  __USEPORT (CTTYID, (rectty_dtable (cttyid), 0));
+  install_ctty (cttyid);
 
   return 0;
 }
@@ -262,12 +294,8 @@ tiocnotty (int fd,
   if (err)
     return __hurd_fail (err);
 
-  /* Clear our cttyid port cell.  */
-  _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], MACH_PORT_NULL);
-
-  /* Reset all the ctty ports in all the descriptors.  */
-
-  __USEPORT (CTTYID, (rectty_dtable (MACH_PORT_NULL), 0));
+  /* Clear our cttyid port.  */
+  install_ctty (MACH_PORT_NULL);
 
   return 0;
 }
diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index 2c9625b474..47f5fbf0a4 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -1227,28 +1227,47 @@ _hurdsig_init (const int *intarray, size_t intarraysize)
 
   /* Start the signal thread listening on the message port.  */
 
-  err = __thread_create (__mach_task_self (), &_hurd_msgport_thread);
-  assert_perror (err);
+  if (__hurd_threadvar_stack_mask == 0)
+    {
+      err = __thread_create (__mach_task_self (), &_hurd_msgport_thread);
+      assert_perror (err);
 
-  stacksize = __vm_page_size * 8; /* Small stack for signal thread.  */
-  err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread,
-			     _hurd_msgport_receive,
-			     (vm_address_t *) &__hurd_sigthread_stack_base,
-			     &stacksize);
-  assert_perror (err);
+      stacksize = ~__hurd_threadvar_stack_mask + 1;
+      stacksize = __vm_page_size * 8; /* Small stack for signal thread.  */
+      err = __mach_setup_thread (__mach_task_self (), _hurd_msgport_thread,
+				 _hurd_msgport_receive,
+				 (vm_address_t *) &__hurd_sigthread_stack_base,
+				 &stacksize);
+      assert_perror (err);
 
-  __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize;
-  __hurd_sigthread_variables =
-    malloc (__hurd_threadvar_max * sizeof (unsigned long int));
-  if (__hurd_sigthread_variables == NULL)
-    __libc_fatal ("hurd: Can't allocate thread variables for signal thread\n");
+      __hurd_sigthread_stack_end = __hurd_sigthread_stack_base + stacksize;
+      __hurd_sigthread_variables =
+	malloc (__hurd_threadvar_max * sizeof (unsigned long int));
+      if (__hurd_sigthread_variables == NULL)
+	__libc_fatal ("hurd: Can't allocate threadvars for signal thread\n");
 
-  /* Reinitialize the MiG support routines so they will use a per-thread
-     variable for the cached reply port.  */
-  __mig_init ((void *) __hurd_sigthread_stack_base);
+      /* Reinitialize the MiG support routines so they will use a per-thread
+	 variable for the cached reply port.  */
+      __mig_init ((void *) __hurd_sigthread_stack_base);
 
-  err = __thread_resume (_hurd_msgport_thread);
-  assert_perror (err);
+      err = __thread_resume (_hurd_msgport_thread);
+      assert_perror (err);
+    }
+  else
+    {
+      /* When cthreads is being used, we need to make the signal thread a
+         proper cthread.  Otherwise it cannot use mutex_lock et al, which
+         will be the cthreads versions.  Various of the message port RPC
+         handlers need to take locks, so we need to be able to call into
+         cthreads code and meet its assumptions about how our thread and
+         its stack are arranged.  Since cthreads puts it there anyway,
+         we'll let the signal thread's per-thread variables be found as for
+         any normal cthread, and just leave the magic __hurd_sigthread_*
+         values all zero so they'll be ignored.  */
+#pragma weak cthread_fork
+#pragma weak cthread_detach
+      cthread_detach (cthread_fork ((cthread_fn_t) &_hurd_msgport_receive, 0));
+    }
 
   /* Receive exceptions on the signal port.  */
   __task_set_special_port (__mach_task_self (),
diff --git a/hurd/msgportdemux.c b/hurd/msgportdemux.c
index 4250affd0b..7f61758cc3 100644
--- a/hurd/msgportdemux.c
+++ b/hurd/msgportdemux.c
@@ -1,5 +1,5 @@
 /* Demux messages sent on the signal port.
-   Copyright (C) 1991, 1992, 1994, 1995, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1991,92,94,95,97,99 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -57,8 +57,12 @@ _hurd_msgport_receive (void)
 {
   /* Get our own sigstate cached so we never again have to take a lock to
      fetch it.  There is much code in hurdsig.c that operates with some
-     sigstate lock held, which will deadlock with _hurd_thread_sigstate.  */
-  (void) _hurd_self_sigstate ();
+     sigstate lock held, which will deadlock with _hurd_thread_sigstate.
+
+     Furthermore, in the cthreads case this is the convenient spot
+     to initialize _hurd_msgport_thread (see hurdsig.c:_hurdsig_init).  */
+
+  _hurd_msgport_thread = _hurd_self_sigstate ()->thread;
 
   while (1)
     (void) __mach_msg_server (msgport_server, __vm_page_size, _hurd_msgport);
diff --git a/hurd/report-wait.c b/hurd/report-wait.c
index 41fdca1619..d0e3d47ad9 100644
--- a/hurd/report-wait.c
+++ b/hurd/report-wait.c
@@ -112,7 +112,7 @@ _S_msg_report_wait (mach_port_t msgport, thread_t thread,
   if (thread == _hurd_msgport_thread)
     /* Cute.  */
     strcpy (description, "msgport");
-  else if (&_hurd_msgport_thread && thread == _hurd_itimer_thread)
+  else if (&_hurd_itimer_thread && thread == _hurd_itimer_thread)
     strcpy (description, "itimer");
   else
     {
diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
index 3981ed2087..b28f5cb5d4 100644
--- a/sysdeps/mach/hurd/fork.c
+++ b/sysdeps/mach/hurd/fork.c
@@ -480,9 +480,27 @@ __fork (void)
 				    (natural_t *) &state, &statecount))
 	LOSE;
 #if STACK_GROWTH_UP
-      state.SP = __hurd_sigthread_stack_base;
+#define THREADVAR_SPACE (__hurd_threadvar_max \
+			 * sizeof *__hurd_sightread_variables)
+      if (__hurd_sigthread_stack_base == 0)
+	{
+	  state.SP &= __hurd_threadvar_stack_mask;
+	  state.SP += __hurd_threadvar_stack_offset + THREADVAR_SPACE;
+	}
+      else
+	state.SP = __hurd_sigthread_stack_base;
 #else
-      state.SP = __hurd_sigthread_stack_end;
+      if (__hurd_sigthread_stack_end == 0)
+	{
+	  /* The signal thread has a normal stack assigned by cthreads.
+	     The threadvar_stack variables conveniently tell us how
+	     to get to the highest address in the stack, just below
+	     the per-thread variables.  */
+	  state.SP &= __hurd_threadvar_stack_mask;
+	  state.SP += __hurd_threadvar_stack_offset;
+	}
+      else
+	state.SP = __hurd_sigthread_stack_end;
 #endif
       MACHINE_THREAD_STATE_SET_PC (&state,
 				   (unsigned long int) _hurd_msgport_receive);
diff --git a/sysdeps/mach/hurd/setsid.c b/sysdeps/mach/hurd/setsid.c
index 6653b81164..a1e84b0a1d 100644
--- a/sysdeps/mach/hurd/setsid.c
+++ b/sysdeps/mach/hurd/setsid.c
@@ -38,29 +38,32 @@ __setsid (void)
 
   /* Tell the proc server we want to start a new session.  */
   err = __USEPORT (PROC, __proc_setsid (port));
-  if (!err)
-    /* Punt our current ctty.  We hold the dtable lock from before the
-       proc_setsid call through clearing the cttyid port so that we can be
-       sure that it's been cleared by the time the signal thread attempts
-       to re-ctty the dtable in response to the pgrp change notification.  */
-    _hurd_port_set (&_hurd_ports[INIT_PORT_CTTYID], MACH_PORT_NULL);
+  if (err)
+    __mutex_unlock (&_hurd_dtable_lock);
+  else
+    {
+      /* Punt our current ctty, and update the dtable accordingly.  We hold
+	 the dtable lock from before the proc_setsid call through clearing
+	 the cttyid port and processing the dtable, so that we can be sure
+	 that it's all done by the time the signal thread processes the
+	 pgrp change notification.  */
+      _hurd_locked_install_cttyid (MACH_PORT_NULL);
 
-  __mutex_unlock (&_hurd_dtable_lock);
-
-  if (!err)
-    /* Synchronize with the signal thread to make sure we have
-       received and processed proc_newids before returning to the user.
-       This both updates _hurd_pgrp, and
-    */
-    while (_hurd_pids_changed_stamp == stamp)
-      {
+      /* Synchronize with the signal thread to make sure we have received
+	 and processed proc_newids before returning to the user.
+	 This is necessary to ensure that _hurd_pgrp (and thus the value
+	 returned by `getpgrp ()' in other threads) has been updated before
+	 we return.  */
+      while (_hurd_pids_changed_stamp == stamp)
+	{
 #ifdef noteven
-	/* XXX we have no need for a mutex, but cthreads demands one.  */
-	__condition_wait (&_hurd_pids_changed_sync, NULL);
+	  /* XXX we have no need for a mutex, but cthreads demands one.  */
+	  __condition_wait (&_hurd_pids_changed_sync, NULL);
 #else
-	__swtch_pri (0);
+	  __swtch_pri (0);
 #endif
-      }
+	}
+    }
 
   HURD_CRITICAL_END;