Fix minor problems found by static checking.
[bpt/emacs.git] / src / w32proc.c
index 1693b2a..ea16f26 100644 (file)
@@ -1,5 +1,5 @@
 /* Process support for GNU Emacs on the Microsoft Windows API.
-   Copyright (C) 1992, 1995, 1999-201 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1995, 1999-2013 Free Software Foundation, Inc.
 
 This file is part of GNU Emacs.
 
@@ -21,6 +21,7 @@ along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
      Adapted from alarm.c by Tim Fleehart
 */
 
+#include <mingw_time.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -802,11 +803,59 @@ new_child (void)
   for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
     if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess == NULL)
       goto Initialize;
+  if (child_proc_count == MAX_CHILDREN)
+    {
+      int i = 0;
+      child_process *dead_cp = NULL;
+
+      DebPrint (("new_child: No vacant slots, looking for dead processes\n"));
+      for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
+       if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess)
+         {
+           DWORD status = 0;
+
+           if (!GetExitCodeProcess (cp->procinfo.hProcess, &status))
+             {
+               DebPrint (("new_child.GetExitCodeProcess: error %lu for PID %lu\n",
+                          GetLastError (), cp->procinfo.dwProcessId));
+               status = STILL_ACTIVE;
+             }
+           if (status != STILL_ACTIVE
+               || WaitForSingleObject (cp->procinfo.hProcess, 0) == WAIT_OBJECT_0)
+             {
+               DebPrint (("new_child: Freeing slot of dead process %d, fd %d\n",
+                          cp->procinfo.dwProcessId, cp->fd));
+               CloseHandle (cp->procinfo.hProcess);
+               cp->procinfo.hProcess = NULL;
+               CloseHandle (cp->procinfo.hThread);
+               cp->procinfo.hThread = NULL;
+               /* Free up to 2 dead slots at a time, so that if we
+                  have a lot of them, they will eventually all be
+                  freed when the tornado ends.  */
+               if (i == 0)
+                 dead_cp = cp;
+               else
+                 break;
+               i++;
+             }
+         }
+      if (dead_cp)
+       {
+         cp = dead_cp;
+         goto Initialize;
+       }
+    }
   if (child_proc_count == MAX_CHILDREN)
     return NULL;
   cp = &child_procs[child_proc_count++];
 
  Initialize:
+  /* Last opportunity to avoid leaking handles before we forget them
+     for good.  */
+  if (cp->procinfo.hProcess)
+    CloseHandle (cp->procinfo.hProcess);
+  if (cp->procinfo.hThread)
+    CloseHandle (cp->procinfo.hThread);
   memset (cp, 0, sizeof (*cp));
   cp->fd = -1;
   cp->pid = -1;
@@ -942,6 +991,18 @@ find_child_pid (DWORD pid)
   return NULL;
 }
 
+void
+release_listen_threads (void)
+{
+  int i;
+
+  for (i = child_proc_count - 1; i >= 0; i--)
+    {
+      if (CHILD_ACTIVE (&child_procs[i])
+         && (fd_info[child_procs[i].fd].flags & FILE_LISTEN))
+       child_procs[i].status = STATUS_READ_ERROR;
+    }
+}
 
 /* Thread proc for child process and socket reader threads. Each thread
    is normally blocked until woken by select() to check for input by
@@ -965,17 +1026,23 @@ reader_thread (void *arg)
     {
       int rc;
 
-      if (fd_info[cp->fd].flags & FILE_LISTEN)
+      if (cp->fd >= 0 && fd_info[cp->fd].flags & FILE_LISTEN)
        rc = _sys_wait_accept (cp->fd);
       else
        rc = _sys_read_ahead (cp->fd);
 
+      /* Don't bother waiting for the event if we already have been
+        told to exit by delete_child.  */
+      if (cp->status == STATUS_READ_ERROR || !cp->char_avail)
+       break;
+
       /* The name char_avail is a misnomer - it really just means the
         read-ahead has completed, whether successfully or not. */
       if (!SetEvent (cp->char_avail))
         {
-         DebPrint (("reader_thread.SetEvent failed with %lu for fd %ld\n",
-                    GetLastError (), cp->fd));
+         DebPrint (("reader_thread.SetEvent(0x%x) failed with %lu for fd %ld (PID %d)\n",
+                    (DWORD_PTR)cp->char_avail, GetLastError (),
+                    cp->fd, cp->pid));
          return 1;
        }
 
@@ -986,6 +1053,11 @@ reader_thread (void *arg)
       if (rc == STATUS_READ_FAILED)
        break;
 
+      /* Don't bother waiting for the acknowledge if we already have
+        been told to exit by delete_child.  */
+      if (cp->status == STATUS_READ_ERROR || !cp->char_consumed)
+       break;
+
       /* Wait until our input is acknowledged before reading again */
       if (WaitForSingleObject (cp->char_consumed, INFINITE) != WAIT_OBJECT_0)
         {
@@ -993,6 +1065,10 @@ reader_thread (void *arg)
                     "%lu for fd %ld\n", GetLastError (), cp->fd));
          break;
         }
+      /* delete_child sets status to STATUS_READ_ERROR when it wants
+        us to exit.  */
+      if (cp->status == STATUS_READ_ERROR)
+       break;
     }
   return 0;
 }
@@ -1069,7 +1145,7 @@ create_child (char *exe, char *cmdline, char *env, int is_gui_app,
   return FALSE;
 }
 
-/* create_child doesn't know what emacs' file handle will be for waiting
+/* create_child doesn't know what emacs's file handle will be for waiting
    on output from the child, so we need to make this additional call
    to register the handle with the process
    This way the select emulator knows how to match file handles with
@@ -1163,11 +1239,11 @@ reap_subprocess (child_process *cp)
       cp->procinfo.hThread = NULL;
     }
 
-  /* For asynchronous children, the child_proc resources will be freed
-     when the last pipe read descriptor is closed; for synchronous
-     children, we must explicitly free the resources now because
-     register_child has not been called. */
-  if (cp->fd == -1)
+  /* If cp->fd was not closed yet, we might be still reading the
+     process output, so don't free its resources just yet.  The call
+     to delete_child on behalf of this subprocess will be made by
+     sys_read when the subprocess output is fully read.  */
+  if (cp->fd < 0)
     delete_child (cp);
 }
 
@@ -1527,7 +1603,6 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
   child_process *cp;
   int is_dos_app, is_cygnus_app, is_gui_app;
   int do_quoting = 0;
-  char escape_char;
   /* We pass our process ID to our children by setting up an environment
      variable in their environment.  */
   char ppid_env_var_buffer[64];
@@ -1540,6 +1615,8 @@ sys_spawnve (int mode, char *cmdname, char **argv, char **envp)
      Some extra whitespace characters need quoting in Cygwin programs,
      so this list is conditionally modified below.  */
   char *sepchars = " \t*?";
+  /* This is for native w32 apps; modified below for Cygwin apps.  */
+  char escape_char = '\\';
 
   /* We don't care about the other modes */
   if (mode != _P_NOWAIT)
@@ -1852,7 +1929,7 @@ extern int proc_buffered_char[];
 
 int
 sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
-           EMACS_TIME *timeout, void *ignored)
+           struct timespec *timeout, void *ignored)
 {
   SELECT_TYPE orfds;
   DWORD timeout_ms, start_time;
@@ -1993,7 +2070,7 @@ count_children:
     /* Some child_procs might be sockets; ignore them.  Also some
        children may have died already, but we haven't finished reading
        the process output; ignore them too.  */
-    if (CHILD_ACTIVE (cp) && cp->procinfo.hProcess
+    if ((CHILD_ACTIVE (cp) && cp->procinfo.hProcess)
        && (cp->fd < 0
            || (fd_info[cp->fd].flags & FILE_SEND_SIGCHLD) == 0
            || (fd_info[cp->fd].flags & FILE_AT_EOF) != 0)
@@ -2199,12 +2276,42 @@ sys_kill (pid_t pid, int sig)
     pid = -pid;
 
   /* Only handle signals that will result in the process dying */
-  if (sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP)
+  if (sig != 0
+      && sig != SIGINT && sig != SIGKILL && sig != SIGQUIT && sig != SIGHUP)
     {
       errno = EINVAL;
       return -1;
     }
 
+  if (sig == 0)
+    {
+      /* It will take _some_ time before PID 4 or less on Windows will
+        be Emacs...  */
+      if (pid <= 4)
+       {
+         errno = EPERM;
+         return -1;
+       }
+      proc_hand = OpenProcess (PROCESS_QUERY_INFORMATION, 0, pid);
+      if (proc_hand == NULL)
+        {
+         DWORD err = GetLastError ();
+
+         switch (err)
+           {
+           case ERROR_ACCESS_DENIED: /* existing process, but access denied */
+             errno = EPERM;
+             return -1;
+           case ERROR_INVALID_PARAMETER: /* process PID does not exist */
+             errno = ESRCH;
+             return -1;
+           }
+       }
+      else
+       CloseHandle (proc_hand);
+      return 0;
+    }
+
   cp = find_child_pid (pid);
   if (cp == NULL)
     {
@@ -2543,8 +2650,9 @@ All path elements in FILENAME are converted to their short names.  */)
   if (GetShortPathName (SDATA (ENCODE_FILE (filename)), shortname, MAX_PATH) == 0)
     return Qnil;
 
-  dostounix_filename (shortname);
+  dostounix_filename (shortname, 0);
 
+  /* No need to DECODE_FILE, because 8.3 names are pure ASCII.   */
   return build_string (shortname);
 }
 
@@ -2571,7 +2679,7 @@ All path elements in FILENAME are converted to their long names.  */)
   if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname, MAX_PATH))
     return Qnil;
 
-  dostounix_filename (longname);
+  dostounix_filename (longname, 0);
 
   /* If we were passed only a drive, make sure that a slash is not appended
      for consistency with directories.  Allow for drive mapping via SUBST