#endif
}
+\f
+
+/* Here's an overview of how support for subprocesses and
+ network/serial streams is implemented on MS-Windows.
+
+ The management of both subprocesses and network/serial streams
+ circles around the child_procs[] array, which can record up to the
+ grand total of MAX_CHILDREN (= 32) of these. (The reasons for the
+ 32 limitation will become clear below.) Each member of
+ child_procs[] is a child_process structure, defined on w32.h.
+
+ A related data structure is the fd_info[] array, which holds twice
+ as many members, 64, and records the information about file
+ descriptors used for communicating with subprocesses and
+ network/serial devices. Each member of the array is the filedesc
+ structure, which records the Windows handle for communications,
+ such as the read end of the pipe to a subprocess, a socket handle,
+ etc.
+
+ Both these arrays reference each other: there's a member of
+ child_process structure that records the corresponding file
+ descriptor, and there's a member of filedesc structure that holds a
+ pointer to the corresponding child_process.
+
+ Whenever Emacs starts a subprocess or opens a network/serial
+ stream, the function new_child is called to prepare a new
+ child_process structure. new_child looks for the first vacant slot
+ in the child_procs[] array, initializes it, and starts a "reader
+ thread" that will watch the output of the subprocess/stream and its
+ status. (If no vacant slot can be found, new_child returns a
+ failure indication to its caller, and the higher-level Emacs
+ primitive that called it will then fail with EMFILE or EAGAIN.)
+
+ The reader thread started by new_child communicates with the main
+ (a.k.a. "Lisp") thread via two event objects and a status, all of
+ them recorded by the members of the child_process structure in
+ child_procs[]. The event objects serve as semaphores between the
+ reader thread and the 'pselect' emulation in sys_select, as follows:
+
+ . Initially, the reader thread is waiting for the char_consumed
+ event to become signaled by sys_select, which is an indication
+ for the reader thread to go ahead and try reading more stuff
+ from the subprocess/stream.
+
+ . The reader thread then attempts to read by calling a
+ blocking-read function. When the read call returns, either
+ successfully or with some failure indication, the reader thread
+ updates the status of the read accordingly, and signals the 2nd
+ event object, char_avail, on whose handle sys_select is
+ waiting. This tells sys_select that the file descriptor
+ allocated for the subprocess or the the stream is ready to be
+ read from.
+
+ When the subprocess exits or the network/serial stream is closed,
+ the reader thread sets the status accordingly and exits. It also
+ exits when the main thread sets the status to STATUS_READ_ERROR
+ and/or the char_avail and char_consumed event handles become NULL;
+ this is how delete_child, called by Emacs when a subprocess or a
+ stream is terminated, terminates the reader thread as part of
+ deleting the child_process object.
+
+ The sys_select function emulates the Posix 'pselect' function; it
+ is needed because the Windows 'select' function supports only
+ network sockets, while Emacs expects 'pselect' to work for any file
+ descriptor, including pipes and serial streams.
+
+ When sys_select is called, it uses the information in fd_info[]
+ array to convert the file descriptors which it was asked to watch
+ into Windows handles. In general, the handle to watch is the
+ handle of the char_avail event of the child_process structure that
+ corresponds to the file descriptor. In addition, for subprocesses,
+ sys_select watches one more handle: the handle for the subprocess,
+ so that it could emulate the SIGCHLD signal when the subprocess
+ exits.
+
+ If file descriptor zero (stdin) doesn't have its bit set in the
+ 'rfds' argument to sys_select, the function always watches for
+ keyboard interrupts, to be able to interrupt the wait and return
+ when the user presses C-g.
+
+ Having collected the handles to watch, sys_select calls
+ WaitForMultipleObjects to wait for any one of them to become
+ signaled. Since WaitForMultipleObjects can only watch up to 64
+ handles, Emacs on Windows is limited to maximum 32 child_process
+ objects (since a subprocess consumes 2 handles to be watched, see
+ above).
+
+ When any of the handles become signaled, sys_select does whatever
+ is appropriate for the corresponding child_process object:
+
+ . If it's a handle to the char_avail event, sys_select marks the
+ corresponding bit in 'rfds', and Emacs will then read from that
+ file descriptor.
+
+ . If it's a handle to the process, sys_select calls the SIGCHLD
+ handler, to inform Emacs of the fact that the subprocess
+ exited.
+
+ The waitpid emulation works very similar to sys_select, except that
+ it only watches handles of subprocesses, and doesn't synchronize
+ with the reader thread.
+
+ Because socket descriptors on Windows are handles, while Emacs
+ expects them to be file descriptors, all low-level I/O functions,
+ such as 'read' and 'write', and all socket operations, like
+ 'connect', 'recvfrom', 'accept', etc., are redirected to the
+ corresponding 'sys_*' functions, which must convert a file
+ descriptor to a handle using the fd_info[] array, and then invoke
+ the corresponding Windows API on the handle. Most of these
+ redirected 'sys_*' functions are implemented on w32.c.
+
+ When the file descriptor was produced by functions such as 'open',
+ the corresponding handle is obtained by calling _get_osfhandle. To
+ produce a file descriptor for a socket handle, which has no file
+ descriptor as far as Windows is concerned, the function
+ socket_to_fd opens the null device; the resulting file descriptor
+ will never be used directly in any I/O API, but serves as an index
+ into the fd_info[] array, where the socket handle is stored. The
+ SOCK_HANDLE macro retrieves the handle when given the file
+ descriptor.
+
+ The function sys_kill emulates the Posix 'kill' functionality to
+ terminate other processes. It does that by attaching to the
+ foreground window of the process and sending a Ctrl-C or Ctrl-BREAK
+ signal to the process; if that doesn't work, then it calls
+ TerminateProcess to forcibly terminate the process. Note that this
+ only terminates the immediate process whose PID was passed to
+ sys_kill; it doesn't terminate the child processes of that process.
+ This means, for example, that an Emacs subprocess run through a
+ shell might not be killed, because sys_kill will only terminate the
+ shell. (In practice, however, such problems are very rare.) */
+
/* Defined in <process.h> which conflicts with the local copy */
#define _P_NOWAIT 1
{
int rc;
- if (cp->fd >= 0 && fd_info[cp->fd].flags & FILE_LISTEN)
+ if (cp->fd >= 0 && (fd_info[cp->fd].flags & FILE_CONNECT) != 0)
+ rc = _sys_wait_connect (cp->fd);
+ else if (cp->fd >= 0 && (fd_info[cp->fd].flags & FILE_LISTEN) != 0)
rc = _sys_wait_accept (cp->fd);
else
rc = _sys_read_ahead (cp->fd);
return 1;
}
- if (rc == STATUS_READ_ERROR)
- return 1;
+ if (rc == STATUS_READ_ERROR || rc == STATUS_CONNECT_FAILED)
+ return 2;
/* If the read died, the child has died so let the thread die */
if (rc == STATUS_READ_FAILED)
#endif
if (data_dir)
{
- /* Look for cygwin.dll in DLL import list. */
+ /* Look for Cygwin DLL in the DLL import list. */
IMAGE_DATA_DIRECTORY import_dir =
data_dir[IMAGE_DIRECTORY_ENTRY_IMPORT];
- IMAGE_IMPORT_DESCRIPTOR * imports;
- IMAGE_SECTION_HEADER * section;
-
- section = rva_to_section (import_dir.VirtualAddress, nt_header);
- imports = RVA_TO_PTR (import_dir.VirtualAddress, section,
- executable);
+ IMAGE_IMPORT_DESCRIPTOR * imports =
+ RVA_TO_PTR (import_dir.VirtualAddress,
+ rva_to_section (import_dir.VirtualAddress,
+ nt_header),
+ executable);
for ( ; imports->Name; imports++)
{
+ IMAGE_SECTION_HEADER * section =
+ rva_to_section (imports->Name, nt_header);
char * dllname = RVA_TO_PTR (imports->Name, section,
executable);
- /* The exact name of the cygwin dll has changed with
- various releases, but hopefully this will be reasonably
- future proof. */
+ /* The exact name of the Cygwin DLL has changed with
+ various releases, but hopefully this will be
+ reasonably future-proof. */
if (strncmp (dllname, "cygwin", 6) == 0)
{
*is_cygnus_app = TRUE;
sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
struct timespec *timeout, void *ignored)
{
- SELECT_TYPE orfds;
+ SELECT_TYPE orfds, owfds;
DWORD timeout_ms, start_time;
int i, nh, nc, nr;
DWORD active;
return 0;
}
- /* Otherwise, we only handle rfds, so fail otherwise. */
- if (rfds == NULL || wfds != NULL || efds != NULL)
+ /* Otherwise, we only handle rfds and wfds, so fail otherwise. */
+ if ((rfds == NULL && wfds == NULL) || efds != NULL)
{
errno = EINVAL;
return -1;
}
- orfds = *rfds;
- FD_ZERO (rfds);
+ if (rfds)
+ {
+ orfds = *rfds;
+ FD_ZERO (rfds);
+ }
+ else
+ FD_ZERO (&orfds);
+ if (wfds)
+ {
+ owfds = *wfds;
+ FD_ZERO (wfds);
+ }
+ else
+ FD_ZERO (&owfds);
nr = 0;
/* If interrupt_handle is available and valid, always wait on it, to
/* Build a list of pipe handles to wait on. */
for (i = 0; i < nfds; i++)
- if (FD_ISSET (i, &orfds))
+ if (FD_ISSET (i, &orfds) || FD_ISSET (i, &owfds))
{
if (i == 0)
{
/* Check for any emacs-generated input in the queue since
it won't be detected in the wait */
- if (detect_input_pending ())
+ if (rfds && detect_input_pending ())
{
FD_SET (i, rfds);
return 1;
{
/* Child process and socket/comm port input. */
cp = fd_info[i].cp;
+ if (FD_ISSET (i, &owfds)
+ && cp
+ && (fd_info[i].flags && FILE_CONNECT) == 0)
+ {
+ DebPrint (("sys_select: fd %d is in wfds, but FILE_CONNECT is reset!\n", i));
+ cp = NULL;
+ }
if (cp)
{
int current_status = cp->status;
{
/* Tell reader thread which file handle to use. */
cp->fd = i;
+ /* Zero out the error code. */
+ cp->errcode = 0;
/* Wake up the reader thread for this process */
cp->status = STATUS_READ_READY;
if (!SetEvent (cp->char_consumed))
if (cp->fd >= 0 && (fd_info[cp->fd].flags & FILE_AT_EOF) == 0)
fd_info[cp->fd].flags |= FILE_SEND_SIGCHLD;
- /* SIG_DFL for SIGCHLD is ignore */
+ /* SIG_DFL for SIGCHLD is ignored */
else if (sig_handlers[SIGCHLD] != SIG_DFL &&
sig_handlers[SIGCHLD] != SIG_IGN)
{
errno = EINTR;
return -1;
}
- else if (fdindex[active] == 0)
+ else if (rfds && fdindex[active] == 0)
{
/* Keyboard input available */
FD_SET (0, rfds);
}
else
{
- /* must be a socket or pipe - read ahead should have
- completed, either succeeding or failing. */
- FD_SET (fdindex[active], rfds);
+ /* Must be a socket or pipe - read ahead should have
+ completed, either succeeding or failing. If this handle
+ was waiting for an async 'connect', reset the connect
+ flag, so it could read from now on. */
+ if (wfds && (fd_info[fdindex[active]].flags & FILE_CONNECT) != 0)
+ {
+ cp = fd_info[fdindex[active]].cp;
+ if (cp)
+ {
+ /* Don't reset the FILE_CONNECT bit and don't
+ acknowledge the read if the status is
+ STATUS_CONNECT_FAILED or some other
+ failure. That's because the thread exits in those
+ cases, so it doesn't need the ACK, and we want to
+ keep the FILE_CONNECT bit as evidence that the
+ connect failed, to be checked in sys_read. */
+ if (cp->status == STATUS_READ_SUCCEEDED)
+ {
+ fd_info[cp->fd].flags &= ~FILE_CONNECT;
+ cp->status = STATUS_READ_ACKNOWLEDGED;
+ }
+ ResetEvent (cp->char_avail);
+ }
+ FD_SET (fdindex[active], wfds);
+ }
+ else if (rfds)
+ FD_SET (fdindex[active], rfds);
nr++;
}