OSDN Git Service

* exceptions.cc (interruptible): Change method for determining if something is
authorcgf <cgf>
Thu, 24 Feb 2000 02:49:44 +0000 (02:49 +0000)
committercgf <cgf>
Thu, 24 Feb 2000 02:49:44 +0000 (02:49 +0000)
interruptible.
(call_handler): Avoid suspending a thread if it owns a mutex.  Only set
signal_arrived if the thread was actually interrupted.
(events_init): Initialize module information needed by interruptible().
(sigdelayed): Don't call sig_dispatch_pending since it could screw up
* init.cc (dll_entry): Record module handle of main for use by interruptible().
(proc_subproc): Reorganize handling of terminated child so that the bulk of the
processing comes from the signal thread.
(wait_sig): Force processing of waiting threads if SIGCHLD is not processed.
* sync.cc (muto::release): Set tid == 0 after lock is released or signal
processor will be confused.

17 files changed:
winsup/cygwin/ChangeLog
winsup/cygwin/autoload.h
winsup/cygwin/errno.cc
winsup/cygwin/exceptions.cc
winsup/cygwin/external.cc
winsup/cygwin/fhandler_floppy.cc
winsup/cygwin/fork.cc
winsup/cygwin/heap.cc
winsup/cygwin/init.cc
winsup/cygwin/pipe.cc
winsup/cygwin/registry.cc
winsup/cygwin/sigproc.cc
winsup/cygwin/sigproc.h
winsup/cygwin/sync.cc
winsup/cygwin/sync.h
winsup/cygwin/thread.h
winsup/cygwin/wait.cc

index 71a7a5c..13c22d8 100644 (file)
@@ -1,3 +1,20 @@
+Wed Feb 23 21:34:58 2000  Christopher Faylor <cgf@cygnus.com>
+
+       * exceptions.cc (interruptible): Change method for determining if
+       something is interruptible.
+       (call_handler): Avoid suspending a thread if it owns a mutex.  Only set
+       signal_arrived if the thread was actually interrupted.
+       (events_init): Initialize module information needed by interruptible().
+       (sigdelayed): Don't call sig_dispatch_pending since it could screw up
+       * init.cc (dll_entry): Record module handle of main for use by
+       interruptible().
+       (proc_subproc): Reorganize handling of terminated child so that the
+       bulk of the processing comes from the signal thread.
+       (wait_sig): Force processing of waiting threads if SIGCHLD is not
+       processed.
+       * sync.cc (muto::release): Set tid == 0 after lock is released or
+       signal processor will be confused.
+
 Tue Feb 22 23:06:01 2000  Christopher Faylor <cgf@cygnus.com>
 
        Respond to more g++ warnings relating to initializing structures.
index 262eaa0..71a51c2 100644 (file)
@@ -1,6 +1,6 @@
 /* autoload.h: Define functions for auto-loading symbols from a DLL.
 
-   Copyright 1999 Cygnus Solutions.
+   Copyright 1999, 2000 Cygnus Solutions.
 
    Written by Christopher Faylor <cgf@cygnus.com>
 
index 40e1616..02c86cb 100644 (file)
@@ -1,6 +1,6 @@
 /* errno.cc: errno-related functions
 
-   Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
+   Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
 
 This file is part of Cygwin.
 
index a1ab267..4f2aa15 100644 (file)
@@ -31,12 +31,15 @@ extern DWORD __sigfirst, __siglast;
 
 static BOOL WINAPI ctrl_c_handler (DWORD);
 static void really_exit (int);
+static char windows_system_directory[1024];
+static size_t windows_system_directory_length;
 
 /* This is set to indicate that we have already exited.  */
 
 static NO_COPY int exit_already = 0;
 static NO_COPY muto *mask_sync = NULL;
 
+HMODULE cygwin_hmodule;
 HANDLE NO_COPY console_handler_thread_waiter = NULL;
 
 static const struct
@@ -611,12 +614,31 @@ handle_sigsuspend (sigset_t tempmask)
 extern DWORD exec_exit;                // Possible exit value for exec
 extern int pending_signals;
 
-extern __inline int
+int
 interruptible (DWORD pc)
 {
+#if 0
   DWORD pchigh = pc & 0xf0000000;
   return ((pc >= (DWORD) &__sigfirst) && (pc <= (DWORD) &__siglast)) ||
         !(pchigh == 0xb0000000 || pchigh == 0x70000000 || pchigh == 0x60000000);
+#else
+  if ((pc >= (DWORD) &__sigfirst) && (pc <= (DWORD) &__siglast))
+    return 1;
+
+  MEMORY_BASIC_INFORMATION m;
+  memset (&m, 0, sizeof m);
+  if (!VirtualQuery ((LPCVOID) pc, &m, sizeof m))
+    sigproc_printf ("couldn't get memory info, %E");
+
+# define h ((HMODULE) m.AllocationBase)
+  if (h == cygwin_hmodule)
+    return 0;
+  char *checkdir = (char *) alloca (windows_system_directory_length);
+  if (!GetModuleFileName (h, checkdir, windows_system_directory_length))
+    return 0;
+  return !strncasematch (windows_system_directory, checkdir, windows_system_directory_length);
+# undef h
+#endif
 }
 
 void
@@ -689,7 +711,9 @@ static int
 call_handler (int sig, struct sigaction& siga, void *handler)
 {
   CONTEXT *cx, orig;
+  int interrupted = 1;
   int res;
+  extern muto *sync_proc_subproc;
 
   if (hExeced != NULL && hExeced != INVALID_HANDLE_VALUE)
     {
@@ -706,7 +730,24 @@ call_handler (int sig, struct sigaction& siga, void *handler)
 
   sigproc_printf ("Suspending %p (mainthread)", myself->getthread2signal());
   HANDLE hth = myself->getthread2signal ();
-  res = SuspendThread (hth);
+  /* Suspend the thread which will receive the signal.  But first ensure that
+     this thread doesn't have the sync_proc_subproc and mask_sync mutos, since
+     we need those (hack alert).  If the thread-to-be-suspended has either of
+     these mutos, enter a busy loop until it is released.  If the thread is
+     already suspended (which should never occur) then just queue the signal. */
+  for (;;)
+    {
+      res = SuspendThread (hth);
+      /* FIXME: Make multi-thread aware */
+      if (sync_proc_subproc->owner () != maintid && mask_sync->owner () != maintid)
+       break;
+
+      if (res)
+       goto set_pending;
+      ResumeThread (hth);
+      Sleep (0);
+    }
+      
   sigproc_printf ("suspend said %d, %E", res);
 
   /* Clear any waiting threads prior to dispatching to handler function */
@@ -734,17 +775,20 @@ call_handler (int sig, struct sigaction& siga, void *handler)
     interrupt_now (cx, sig, siga, handler);
   else if (!interrupt_on_return (cx, sig, siga, handler))
     {
+    set_pending:
       pending_signals = 1;     /* FIXME: Probably need to be more tricky here */
       sig_set_pending (sig);
+      interrupted = 0;
     }
 
   (void) ResumeThread (hth);
-  (void) SetEvent (signal_arrived);    // For an EINTR case
+  if (interrupted)
+    (void) SetEvent (signal_arrived);  // For an EINTR case
   sigproc_printf ("armed signal_arrived %p, res %d", signal_arrived, res);
 
 out:
   sigproc_printf ("returning");
-  return 1;
+  return interrupted;
 }
 #endif /* i386 */
 
@@ -983,6 +1027,17 @@ events_init (void)
 
   ProtectHandle (title_mutex);
   mask_sync = new_muto (FALSE, NULL);
+  windows_system_directory[0] = '\0';
+  (void) GetSystemDirectory (windows_system_directory, sizeof (windows_system_directory) - 2);
+  char *end = strchr (windows_system_directory, '\0');
+  if (end == windows_system_directory)
+    api_fatal ("can't find windows system directory");
+  if (end[-1] != '\\')
+    {
+      *end++ = '\\';
+      *end = '\0';
+    }
+  windows_system_directory_length = end - windows_system_directory;
 }
 
 void
@@ -1035,12 +1090,7 @@ _sigreturn:
        ret
 
 _sigdelayed:
-       # addl  4,%%esp
-       cmpl    $0,_pending_signals
-       je      2f
-       pushl   $0
-       call    _sig_dispatch_pending@4
-2:     pushl   %2      # original return address
+       pushl   %2      # original return address
        pushf
        pushl   %%esi
        pushl   %%edi
@@ -1053,9 +1103,16 @@ _sigdelayed:
        pushl   %4      # signal argument
        pushl   $_sigreturn
        movl    $0,%0
-       pushl   $_signal_arrived
-       call    _ResetEvent@4
-       jmp     *%5
+
+       pushl   _signal_arrived # Everybody waiting for this should
+       call    _ResetEvent@4   # have woken up by now.
+
+       cmpl    $0,_pending_signals
+       je      2f
+       pushl   $0
+       call    _sig_dispatch_pending@4
+
+2:     jmp     *%5
 
 ___siglast:
 " : "=m" (sigsave.sig) : "m" (&_impure_ptr->_errno),
index 539e0ba..ccbcb77 100644 (file)
@@ -1,6 +1,6 @@
 /* external.cc: Interface to Cygwin internals from external programs.
 
-   Copyright 1997, 1998, 1999 Cygnus Solutions.
+   Copyright 1997, 1998, 1999, 2000 Cygnus Solutions.
 
    Written by Christopher Faylor <cgf@cygnus.com>
 
index ed1c7b6..93e8435 100644 (file)
@@ -1,7 +1,7 @@
 /* fhandler_floppy.cc.  See fhandler.h for a description of the
    fhandler classes.
 
-   Copyright 1999 Cygnus Solutions.
+   Copyright 1999, 2000 Cygnus Solutions.
 
 This file is part of Cygwin.
 
index 9f50f08..44fc49d 100644 (file)
@@ -1,6 +1,6 @@
 /* fork.cc
 
-   Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
+   Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
 
 This file is part of Cygwin.
 
index 6c8ddae..ce1cab5 100644 (file)
@@ -1,6 +1,6 @@
 /* heap.cc: Cygwin heap manager.
 
-   Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
+   Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
 
 This file is part of Cygwin.
 
index 3a33bd1..2df5067 100644 (file)
@@ -1,6 +1,6 @@
 /* init.cc for WIN32.
 
-   Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
+   Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
 
 This file is part of Cygwin.
 
@@ -12,26 +12,17 @@ details. */
 #include <ctype.h>
 #include "winsup.h"
 
-extern "C"
-{
-  int WINAPI dll_entry (HANDLE h, DWORD reason, void *ptr);
-};
-
-extern "C" void *export_malloc (unsigned int);
-extern "C" void *export_realloc (void *,unsigned int);
-extern "C" void *export_calloc (unsigned int,unsigned int);
-extern "C" void export_free (void *);
-
-extern void do_global_ctors (void (**in_pfunc)(), int force);
+extern HMODULE cygwin_hmodule;
 
 int NO_COPY dynamically_loaded;
 
-int
-WINAPI dll_entry (HANDLE, DWORD reason, void *static_load)
+extern "C" int
+WINAPI dll_entry (HANDLE h, DWORD reason, void *static_load)
 {
   switch (reason)
     {
     case DLL_PROCESS_ATTACH:
+      cygwin_hmodule = (HMODULE) h;
       dynamically_loaded = (static_load == NULL);
       break;
     case DLL_THREAD_ATTACH:
index 2ba99cd..fc1db5e 100644 (file)
@@ -1,6 +1,6 @@
-/* pipe.cc: pipe for WIN32.
+/* pipe.cc: pipe for Cygwin.
 
-   Copyright 1996, 1998, 1999 Cygnus Solutions.
+   Copyright 1996, 1998, 1999, 2000 Cygnus Solutions.
 
 This file is part of Cygwin.
 
index 321b13f..f0c11ca 100644 (file)
@@ -1,6 +1,6 @@
 /* registry.cc: registry interface
 
-   Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
+   Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
 
 This file is part of Cygwin.
 
index f924a4c..5efd067 100644 (file)
@@ -85,8 +85,6 @@ Static HANDLE hwait_subproc = NULL;   // Handle of sig_subproc thread
 
 Static HANDLE wait_sig_inited = NULL;  // Control synchronization of
                                        //  message queue startup
-Static muto *sync_proc_subproc = NULL; // Control access to
-                                       //  subproc stuff
 
 /* Used by WaitForMultipleObjects.  These are handles to child processes.
  */
@@ -100,6 +98,9 @@ Static int nzombies = 0;             // Number of deceased children
 Static waitq waitq_head = {0, 0, 0, 0, 0, 0, 0};// Start of queue for wait'ing threads
 Static waitq waitq_main;               // Storage for main thread
 
+muto NO_COPY *sync_proc_subproc = NULL;        // Control access to
+                                       //  subproc stuff
+
 DWORD NO_COPY maintid = 0;             // ID of the main thread
 Static DWORD sigtid = 0;               // ID of the signal thread
 
@@ -244,7 +245,7 @@ proc_subproc (DWORD what, DWORD val)
   int potential_match;
   DWORD exitcode;
   pinfo *child;
-  int send_sigchld = 0;
+  int clearing = 0;
   waitq *w;
 
 #define wval    ((waitq *) val)
@@ -284,14 +285,6 @@ proc_subproc (DWORD what, DWORD val)
       wake_wait_subproc ();
       break;
 
-    /* A child is in the stopped state.  Scan wait() queue to see if anyone
-     * should be notified.  (Called from wait_sig thread)
-     */
-    case PROC_CHILDSTOPPED:
-      child = myself;          // Just to avoid accidental NULL dereference
-      sip_printf ("Received stopped notification");
-      goto scan_wait;
-
     /* A child process had terminated.
      * Possibly this is just due to an exec().  Cygwin implements an exec()
      * as a "handoff" from one windows process to another.  If child->hProcess
@@ -310,7 +303,6 @@ proc_subproc (DWORD what, DWORD val)
          ForceCloseHandle1 (hchildren[val], childhProc);
          hchildren[val] = child->hProcess; /* Filled out by child */
          ProtectHandle1 (child->hProcess, childhProc);
-         wake_wait_subproc ();
          break;                        // This was an exec()
        }
 
@@ -318,14 +310,32 @@ proc_subproc (DWORD what, DWORD val)
                  child->pid, val, hchildren[val], nchildren, nzombies);
       remove_child (val);              // Remove from children arrays
       zombies[nzombies++] = child;     // Add to zombie array
-      wake_wait_subproc ();            // Notify wait_subproc thread that
-                                       //  nchildren has changed.
       child->process_state = PID_ZOMBIE;// Walking dead
       if (!proc_loop_wait)             // Don't bother if wait_subproc is
        break;                          //  exiting
 
-      send_sigchld = 1;
+      /* Send a SIGCHLD to myself. */
+      rc = sig_send (myself_nowait, SIGCHLD);  // Send a SIGCHLD
+      break;   // Don't try to unlock.  We don't have a lock.
+
+    /* A child is in the stopped state.  Scan wait() queue to see if anyone
+     * should be notified.  (Called from wait_sig thread)
+     */
+    case PROC_CHILDSTOPPED:
+      child = myself;          // Just to avoid accidental NULL dereference
+      sip_printf ("Received stopped notification");
+      goto scan_wait;
 
+    /* Clear all waiting threads.  Called from exceptions.cc prior to
+     * the main thread's dispatch to a signal handler function.
+     * (called from wait_sig thread)
+     */
+    case PROC_CLEARWAIT:
+      /* Clear all "wait"ing threads. */
+      sip_printf ("clear waiting threads");
+      clearing = 1;
+
+    case PROC_SIGCHLD:
     scan_wait:
       /* Scan the linked list of wait()ing threads.  If a wait's parameters
        * match this pid, then activate it.
@@ -334,13 +344,15 @@ proc_subproc (DWORD what, DWORD val)
        {
          if ((potential_match = checkstate (w)) > 0)
            sip_printf ("released waiting thread");
-         else if (potential_match < 0)
+         else if (!clearing && potential_match < 0)
            sip_printf ("only found non-terminated children");
-         else if (potential_match == 0)                // nothing matched
+         else if (potential_match <= 0)                // nothing matched
            {
              sip_printf ("waiting thread found no children");
              HANDLE oldw = w->next->ev;
              w->next->ev = NULL;
+             if (clearing)
+               w->next->status = -1;           /* flag that a signal was received */
              if (!SetEvent (oldw))
                system_printf ("couldn't wake up wait event %p, %E", oldw);
              w->next = w->next->next;
@@ -349,32 +361,13 @@ proc_subproc (DWORD what, DWORD val)
            break;
        }
 
-      sip_printf ("finished processing terminated/stopped child");
-      if (!send_sigchld)
-       break;          // No need to send a SIGCHLD
-
-      /* Send a SIGCHLD to myself. */
-      sync_proc_subproc->release ();   // Avoid a potential deadlock
-      rc = sig_send (NULL, SIGCHLD);   // Send a SIGCHLD
-      goto out1;       // Don't try to unlock.  We don't have a lock.
-
-
-    /* Clear all waiting threads.  Called from exceptions.cc prior to
-     * the main thread's dispatch to a signal handler function.
-     * (called from wait_sig thread)
-     */
-    case PROC_CLEARWAIT:
-      /* Clear all "wait"ing threads. */
-      sip_printf ("clear waiting threads");
-      for (w = &waitq_head; w->next != NULL; w = w->next)
+      if (!clearing)
+       sip_printf ("finished processing terminated/stopped child");
+      else
        {
-         sip_printf ("clearing waiting thread, pid %d", w->next->pid);
-         w->next->status = -1;         /* flag that a signal was received */
-         if (!SetEvent (w->next->ev))
-           system_printf ("Couldn't wake up wait event, %E");
+         waitq_head.next = NULL;
+         sip_printf ("finished clearing");
        }
-      waitq_head.next = NULL;
-      sip_printf ("finished clearing");
       break;
 
     /* Handle a wait4() operation.  Allocates an event for the calling
@@ -1252,6 +1245,10 @@ wait_sig (VOID *)
                /* A normal UNIX signal */
                default:
                  sip_printf ("Got signal %d", sig);
+                 int wasdispatched = sig_handle (sig);
+                 dispatched |= wasdispatched;
+                 if (sig == SIGCHLD && !wasdispatched)
+                   proc_subproc (PROC_SIGCHLD, 0);
                  dispatched |= sig_handle (sig);
                  goto nextsig;
                }
index b1b4eaf..7f237a9 100644 (file)
@@ -18,7 +18,8 @@ enum procstuff
   PROC_CHILDSTOPPED    = 2,    // a child stopped
   PROC_CHILDTERMINATED = 3,    // a child died
   PROC_CLEARWAIT       = 4,    // clear all waits - signal arrived
-  PROC_WAIT            = 5     // setup for wait() for subproc
+  PROC_WAIT            = 5,    // setup for wait() for subproc
+  PROC_SIGCHLD         = 6     // saw a non-trapped SIGCHLD
 };
 
 typedef struct struct_waitq
index 89d92ce..9610282 100644 (file)
@@ -4,7 +4,7 @@
    which is intended to operate similarly to a mutex but attempts to
    avoid making expensive calls to the kernel.
 
-   Copyright 1999 Cygnus Solutions.
+   Copyright 2000 Cygnus Solutions.
 
    Written by Christopher Faylor <cgf@cygnus.com>
 
@@ -43,7 +43,11 @@ muto::~muto ()
 
 /* Acquire the lock.  Argument is the number of milliseconds to wait for
    the lock.  Multiple visits from the same thread are allowed and should
-   be handled correctly.  */
+   be handled correctly.
+
+   Note: The goal here is to minimize, as much as possible, calls to the
+   OS.  Hence the use of InterlockedIncrement, etc., rather than (much) more
+   expensive OS mutexes.  */
 int
 muto::acquire (DWORD ms)
 {
@@ -59,7 +63,7 @@ muto::acquire (DWORD ms)
         lock the same muto to succeed without attempting to manipulate sync.
         If the muto is already locked then this thread will wait for ms until
         it is signalled by muto::release.  Then it will attempt to grab the
-        sync field.  If it succeeds, then this thread owns the mutex.
+        sync field.  If it succeeds, then this thread owns the muto.
 
         There is a pathological condition where a thread times out waiting for
         bruteforce but the release code triggers the bruteforce event.  In this
@@ -99,11 +103,11 @@ muto::release ()
   /* FIXME: Need to check that other thread has not exited, too. */
   if (!--visits)
     {
-      tid = 0;         /* We were the last unlocker. */
       InterlockedExchange (&sync, 0); /* Reset trigger. */
       /* This thread had incremented waiters but had never decremented it.
         Decrement it now.  If it is >= 0 then there are possibly other
         threads waiting for the lock, so trigger bruteforce. */
+      tid = 0;         /* We were the last unlocker. */
       if (InterlockedDecrement (&waiters) >= 0)
        (void) SetEvent (bruteforce); /* Wake up one of the waiting threads */
     }
index 37efbe5..7189ae9 100644 (file)
@@ -1,6 +1,6 @@
 /* sync.h: Header file for cygwin synchronization primitives.
 
-   Copyright 1999 Cygnus Solutions.
+   Copyright 1999, 2000 Cygnus Solutions.
 
    Written by Christopher Faylor <cgf@cygnus.com>
 
@@ -36,6 +36,7 @@ public:
 
   /* Return true if caller thread owns the lock. */
   int ismine () {return tid == GetCurrentThreadId ();}
+  DWORD owner () {return tid;}
 };
 
 /* Use a statically allocated buffer as the storage for a muto */
index 9aca0c6..e9e0c82 100644 (file)
@@ -1,6 +1,6 @@
 /* thread.h: Locking and threading module definitions
 
-   Copyright 1998, 1999 Cygnus Solutions.
+   Copyright 1998, 1999, 2000 Cygnus Solutions.
 
    Written by Marco Fuykschot <marco@ddi.nl>
 
index 1822400..30b8ef8 100644 (file)
@@ -1,6 +1,6 @@
 /* wait.cc: Posix wait routines.
 
-   Copyright 1996, 1997, 1998, 1999 Cygnus Solutions.
+   Copyright 1996, 1997, 1998, 1999, 2000 Cygnus Solutions.
 
 This file is part of Cygwin.