Adapted from alarm.c by Tim Fleehart
*/
+#include <mingw_time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
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;
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
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;
}
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
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;
/* 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)
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)
{