about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog22
-rw-r--r--Makeconfig11
-rw-r--r--hurd/hurdsig.c6
-rw-r--r--hurd/intr-msg.c16
-rw-r--r--sysdeps/mach/hurd/fork.c72
-rw-r--r--sysdeps/mach/hurd/i386/trampoline.c29
6 files changed, 119 insertions, 37 deletions
diff --git a/ChangeLog b/ChangeLog
index 27b84aee7e..7c56c65ab0 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+Thu Aug 17 16:18:38 1995  Roland McGrath  <roland@churchy.gnu.ai.mit.edu>
+
+	* hurd/intr-msg.c: Use INTR_MSG_TRAP macro from machine-dependent
+ 	"intr-msg.h" for special syscall code, instead of i386-specific asm.
+	* hurd/hurdsig.c: Use INTR_MSG_BACK_OUT macro from
+ 	machine-dependent "intr-msg.h" before mutating thread state to
+ 	skip RPC.
+
+	* sysdeps/mach/hurd/i386/trampoline.c: If PC is inside
+ 	_hurd_intr_rpc_mach_msg special syscall code, use real SP saved in
+	%ecx.
+
+	* Makeconfig (link-libc): New variable; use shared library if
+ 	available.
+	(+link): Use it.
+
+	* sysdeps/mach/hurd/fork.c (_hurd_fork_locks): Variable removed.
+  	Instead, declare with `symbol_set_declare'.
+	(fork): Use symbol_set_* macros for _hurd_fork_locks.  
+	Use SS->thread instead of __mach_thread_self ().  Suspend all
+ 	other threads during task_create and port copying.
+
 Wed Aug 16 17:04:26 1995  Roland McGrath  <roland@churchy.gnu.ai.mit.edu>
 
 	* hurd/intr-msg.c: Fixed calculation of syscall %esp.
diff --git a/Makeconfig b/Makeconfig
index 0ebe04392b..23db67ff33 100644
--- a/Makeconfig
+++ b/Makeconfig
@@ -267,11 +267,18 @@ endif
 
 # Command for linking programs with the C library.
 ifndef +link
-+link = $(CC) -nostdlib $(LDFLAGS) -o $@ \
++link = $(CC) -nostdlib -nostartfiles $(LDFLAGS) -o $@ \
 	$(addprefix $(csu-objpfx),start.o $(+preinit)) \
-	$(^:lib=$(common-objpfx)libc.a) $(gnulib) $(common-objpfx)libc.a \
+	$(^:$(common-objpfx)libc.a=$(link-libc)) \
 	$(addprefix $(csu-objpfx),$(+postinit))
 endif
+ifndef link-libc
+ifeq (yes,$(build-shared))
+link-libc = -L$(common-objdir) -lc $(gnulib)
+else
+link-libc = $(common-objpfx)libc.a $(gnulib) $(common-objpfx)libc.a
+endif
+endif
 ifndef gnulib
 gnulib := -lgcc
 endif
diff --git a/hurd/hurdsig.c b/hurd/hurdsig.c
index 10dbceb4f4..ca4e22925b 100644
--- a/hurd/hurdsig.c
+++ b/hurd/hurdsig.c
@@ -250,7 +250,8 @@ interrupted_reply_port_location (struct machine_thread_all_state *thread_state,
 
   return portloc;
 }
-
+
+#include "intr-msg.h"
 
 /* SS->thread is suspended.
 
@@ -274,7 +275,7 @@ _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
 		     mach_msg_type_name_t reply_port_type,
 		     int untraced)
 {
-  extern const void _hurd_intr_rpc_msg_do_trap, _hurd_intr_rpc_msg_in_trap;
+  extern const void _hurd_intr_rpc_msg_in_trap;
   mach_port_t rcv_port = MACH_PORT_NULL;
   mach_port_t intr_port;
 
@@ -294,6 +295,7 @@ _hurdsig_abort_rpcs (struct hurd_sigstate *ss, int signo, int sigthread,
       /* The thread is about to do the RPC, but hasn't yet entered
 	 mach_msg.  Mutate the thread's state so it knows not to try
 	 the RPC.  */
+      INTR_MSG_BACK_OUT (&state->basic);
       MACHINE_THREAD_STATE_SET_PC (&state->basic,
 				   &_hurd_intr_rpc_msg_in_trap);
       state->basic.SYSRETURN = MACH_SEND_INTERRUPTED;
diff --git a/hurd/intr-msg.c b/hurd/intr-msg.c
index 6f670b538f..024cbfbd3e 100644
--- a/hurd/intr-msg.c
+++ b/hurd/intr-msg.c
@@ -21,6 +21,9 @@ Cambridge, MA 02139, USA.  */
 #include <mach/mig_errors.h>
 #include <hurd/signal.h>
 
+#include "intr-msg.h"
+
+
 error_t
 _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
 			 mach_msg_option_t option,
@@ -56,17 +59,8 @@ _hurd_intr_rpc_mach_msg (mach_msg_header_t *msg,
       ss->cancel = 0;
     }
   else 
-  /*       err = intr_msg_trap (msg, option, send_size,
-	   rcv_size, rcv_name, timeout, notify);
-	   */
-    asm (".globl _hurd_intr_rpc_msg_do_trap\n" 
-	 ".globl _hurd_intr_rpc_msg_in_trap\n"
-	 "				movl %%esp, %%ecx\n"
-	 "				leal %1, %%esp\n"
-	 "				movl $-25, %%eax\n"
-	 "_hurd_intr_rpc_msg_do_trap:	lcall $7, $0 # status in %0\n"
-	 "_hurd_intr_rpc_msg_in_trap:	movl %%ecx, %%esp"
-	 : "=a" (err) : "m" ((&msg)[-1]) : "%ecx");
+    err = INTR_MSG_TRAP (msg, option, send_size,
+			 rcv_size, rcv_name, timeout, notify);
 
   switch (err)
     {
diff --git a/sysdeps/mach/hurd/fork.c b/sysdeps/mach/hurd/fork.c
index b8b15743cd..66b1ba84c7 100644
--- a/sysdeps/mach/hurd/fork.c
+++ b/sysdeps/mach/hurd/fork.c
@@ -29,11 +29,7 @@ Cambridge, MA 02139, USA.  */
 
 
 /* Things that want to be locked while forking.  */
-struct
-  {
-    size_t n;
-    struct mutex *locks[0];
-  } _hurd_fork_locks;
+symbol_set_declare (_hurd_fork_locks)
 
 
 /* Things that want to be called before we fork, to prepare the parent for
@@ -62,7 +58,6 @@ __fork (void)
   pid_t pid;
   size_t i;
   error_t err;
-  thread_t thread_self = __mach_thread_self ();
   struct hurd_sigstate *volatile ss;
 
   ss = _hurd_self_sigstate ();
@@ -87,14 +82,32 @@ __fork (void)
       mach_msg_type_number_t nporttypes = 0;
       thread_t *threads = NULL;
       mach_msg_type_number_t nthreads = 0;
-      int ports_locked = 0;
+      int ports_locked = 0, stopped = 0;
+
+      void resume_threads (void)
+	{
+	  if (! stopped)
+	    return;
+
+	  assert (threads);
+
+	  for (i = 0; i < nthreads; ++i)
+	    if (threads[i] != ss->thread)
+	      __thread_resume (threads[i]);
+	  stopped = 0;
+	}
 
       /* Run things that prepare for forking before we create the task.  */
       RUN_HOOK (_hurd_fork_prepare_hook, ());
 
       /* Lock things that want to be locked before we fork.  */
-      for (i = 0; i < _hurd_fork_locks.n; ++i)
-	__mutex_lock (_hurd_fork_locks.locks[i]);
+      {
+	void *const *p;
+	for (p = symbol_set_first_element (_hurd_fork_locks);
+	     ! symbol_set_end_p (_hurd_fork_locks, p);
+	     ++p)
+	  __mutex_lock (*p);
+      }
       __mutex_lock (&_hurd_siglock);
       
       newtask = MACH_PORT_NULL;
@@ -108,8 +121,16 @@ __fork (void)
 	__spin_lock (&_hurd_ports[i].lock);
       ports_locked = 1;
 
-      /* Create the child task.  It will inherit a copy of our memory.  */
-      err = __task_create (__mach_task_self (), 1, &newtask);
+      /* Stop all other threads while copying the address space,
+	 so nothing changes.  */
+      err = __proc_dostop (_hurd_ports[INIT_PORT_PROC].port, ss->thread);
+      if (!err)
+        {
+          stopped = 1;
+
+	  /* Create the child task.  It will inherit a copy of our memory.  */
+	  err = __task_create (__mach_task_self (), 1, &newtask);
+        }
 
       /* Unlock the global signal state lock, so we do not
 	 block the signal thread any longer than necessary.  */
@@ -263,7 +284,7 @@ __fork (void)
 		  if (err = __proc_task2proc (portnames[i], newtask, &insert))
 		    LOSE;
 		}
-	      else if (portnames[i] == thread_self)
+	      else if (portnames[i] == ss->thread)
 		{
 		  /* For the name we use for our own thread port, we will
 		     insert the thread port for the child main user thread
@@ -372,6 +393,10 @@ __fork (void)
 	__spin_unlock (&_hurd_ports[i].lock);
       ports_locked = 0;
 
+      /* All state has now been copied from the parent.  It is safe to
+         resume other parent threads.  */
+      resume_threads ();
+
       /* Create the child main user thread and signal thread.  */
       if ((err = __thread_create (newtask, &thread)) ||
 	  (err = __thread_create (newtask, &sigthread)))
@@ -381,8 +406,8 @@ __fork (void)
          dead name rights with the names we want to give the thread ports
          in the child as placeholders.  Now deallocate them so we can use
          the names.  */
-      if ((err = __mach_port_deallocate (newtask, thread_self)) ||
-	  (err = __mach_port_insert_right (newtask, thread_self,
+      if ((err = __mach_port_deallocate (newtask, ss->thread)) ||
+	  (err = __mach_port_insert_right (newtask, ss->thread,
 					   thread, MACH_MSG_TYPE_COPY_SEND)))
 	LOSE;
       /* We have one extra user reference created at the beginning of this
@@ -390,9 +415,9 @@ __fork (void)
 	 accounted for in the child below).  This extra right gets consumed
 	 in the child by the store into _hurd_sigthread in the child fork.  */
       if (thread_refs > 1 &&
-	  (err = __mach_port_mod_refs (newtask, thread_self,
+	  (err = __mach_port_mod_refs (newtask, ss->thread,
 				       MACH_PORT_RIGHT_SEND,
-				       thread_refs - 1)))
+				       thread_refs)))
 	LOSE;
       if ((_hurd_msgport_thread != MACH_PORT_NULL) /* Let user have none.  */
 	  && ((err = __mach_port_deallocate (newtask, _hurd_msgport_thread)) ||
@@ -474,6 +499,8 @@ __fork (void)
 	for (i = 0; i < _hurd_nports; ++i)
 	  __spin_unlock (&_hurd_ports[i].lock);
 
+      resume_threads ();
+
       if (newtask != MACH_PORT_NULL)
 	{
 	  if (err)
@@ -486,8 +513,6 @@ __fork (void)
 	__mach_port_deallocate (__mach_task_self (), sigthread);
       if (newproc != MACH_PORT_NULL)
 	__mach_port_deallocate (__mach_task_self (), newproc);
-      if (thread_self != MACH_PORT_NULL)
-	__mach_port_deallocate (__mach_task_self (), thread_self);
 
       if (portnames)
 	__vm_deallocate (__mach_task_self (),
@@ -525,7 +550,7 @@ __fork (void)
 
       /* We are the only thread in this new task, so we will
 	 take the task-global signals.  */
-      _hurd_sigthread = thread_self;
+      _hurd_sigthread = ss->thread;
 
       /* Unchain the sigstate structures for threads that existed in the
 	 parent task but don't exist in this task (the child process).
@@ -575,8 +600,13 @@ __fork (void)
 
   /* Unlock things we locked before creating the child task.
      They are locked in both the parent and child tasks.  */
-  for (i = 0; i < _hurd_fork_locks.n; ++i)
-    __mutex_unlock (_hurd_fork_locks.locks[i]);
+  {
+    void *const *p;
+    for (p = symbol_set_first_element (_hurd_fork_locks);
+	 ! symbol_set_end_p (_hurd_fork_locks, p);
+	 ++p)
+      __mutex_unlock (*p);
+  }
 
   _hurd_critical_section_unlock (ss);
 
diff --git a/sysdeps/mach/hurd/i386/trampoline.c b/sysdeps/mach/hurd/i386/trampoline.c
index 7adffc40be..9e947a46e7 100644
--- a/sysdeps/mach/hurd/i386/trampoline.c
+++ b/sysdeps/mach/hurd/i386/trampoline.c
@@ -45,6 +45,9 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
 			struct machine_thread_all_state *state)
 {
   __label__ trampoline, rpc_wait_trampoline, firewall;
+  extern const void _hurd_intr_rpc_msg_in_trap;
+  extern const void _hurd_intr_rpc_msg_cx_sp;
+  extern const void _hurd_intr_rpc_msg_sp_restored;
   void *volatile sigsp;
   struct sigcontext *scp;
   struct 
@@ -80,6 +83,11 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
   if (! machine_get_basic_state (ss->thread, state))
     return NULL;
 
+  /* Save the original SP in the gratuitous `esp' slot.
+     We may need to reset the SP (the `uesp' slot) to avoid clobbering an
+     interrupted RPC frame.  */
+  state->basic.esp = state->basic.uesp;
+
   if ((ss->actions[signo].sa_flags & SA_ONSTACK) &&
       !(ss->sigaltstack.ss_flags & (SA_DISABLE|SA_ONSTACK)))
     {
@@ -88,6 +96,24 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
       /* XXX need to set up base of new stack for
 	 per-thread variables, cthreads.  */
     }
+  /* This code has intimate knowledge of the special mach_msg system call
+     done in intr-msg.c; that code does: 
+					movl %esp, %ecx
+					leal ARGS, %esp
+	_hurd_intr_rpc_msg_cx_sp:	movl $-25, %eax
+	_hurd_intr_rpc_msg_do_trap:	lcall $7, $0
+	_hurd_intr_rpc_msg_in_trap:	movl %ecx, %esp
+        _hurd_intr_rpc_msg_sp_restored:
+     We must check for the window during which %esp points at the
+     mach_msg arguments.  The space below until %ecx is used by
+     the _hurd_intr_rpc_mach_msg frame, and must not be clobbered.  */
+  else if (state->basic.eip >= (int) &_hurd_intr_rpc_msg_cx_sp && 
+	   state->basic.eip < (int) &_hurd_intr_rpc_msg_sp_restored)
+    /* The SP now points at the mach_msg args, but there is more stack
+       space used below it.  The real SP is saved in %ecx; we must push the
+       new frame below there, and restore that value as the SP on
+       sigreturn.  */
+    sigsp = (char *) (state->basic.uesp = state->basic.ecx);
   else
     sigsp = (char *) state->basic.uesp;
 
@@ -166,7 +192,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
 	 message reception, since the request message has already been
 	 sent.  */
 
-      struct mach_msg_trap_args *args = (void *) state->basic.uesp;
+      struct mach_msg_trap_args *args = (void *) state->basic.esp;
 
       if (_hurdsig_catch_fault (SIGSEGV))
 	{
@@ -192,6 +218,7 @@ _hurd_setup_sighandler (struct hurd_sigstate *ss, __sighandler_t handler,
       state->basic.eip = (int) &&rpc_wait_trampoline;
       /* The reply-receiving trampoline code runs initially on the original
 	 user stack.  We pass it the signal stack pointer in %ebx.  */
+      state->basic.uesp = state->basic.esp; /* Restore mach_msg syscall SP.  */
       state->basic.ebx = (int) sigsp;
       /* After doing the message receive, the trampoline code will need to
 	 update the %eax value to be restored by sigreturn.  To simplify