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;
FD_ZERO (rfds);
nr = 0;
- /* Always wait on interrupt_handle, to detect C-g (quit). */
- wait_hnd[0] = interrupt_handle;
- fdindex[0] = -1;
+ /* If interrupt_handle is available and valid, always wait on it, to
+ detect C-g (quit). */
+ nh = 0;
+ if (interrupt_handle && interrupt_handle != INVALID_HANDLE_VALUE)
+ {
+ wait_hnd[0] = interrupt_handle;
+ fdindex[0] = -1;
+ nh++;
+ }
/* Build a list of pipe handles to wait on. */
- nh = 1;
for (i = 0; i < nfds; i++)
if (FD_ISSET (i, &orfds))
{
FD_SET (i, rfds);
return 1;
}
+ else if (noninteractive)
+ {
+ if (handle_file_notifications (NULL))
+ return 1;
+ }
}
else
{
/* 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)
{
if (timeout)
Sleep (timeout_ms);
+ if (noninteractive)
+ {
+ if (handle_file_notifications (NULL))
+ return 1;
+ }
return 0;
}
}
else if (active == WAIT_TIMEOUT)
{
+ if (noninteractive)
+ {
+ if (handle_file_notifications (NULL))
+ return 1;
+ }
return 0;
}
else if (active >= WAIT_OBJECT_0
break;
} while (active < nh + nc);
+ if (noninteractive)
+ {
+ if (handle_file_notifications (NULL))
+ nr++;
+ }
+
/* If no input has arrived and timeout hasn't expired, wait again. */
if (nr == 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)
{