/* Process support for GNU Emacs on the Microsoft Windows API.
- Copyright (C) 1992, 1995, 1999-2012 Free Software Foundation, Inc.
+
+Copyright (C) 1992, 1995, 1999-2014 Free Software Foundation, Inc.
This file is part of GNU Emacs.
Adapted from alarm.c by Tim Fleehart
*/
+#include <mingw_time.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/file.h>
+#include <mbstring.h>
/* must include CRT headers *before* config.h */
#include <config.h>
#undef kill
#include <windows.h>
-#ifdef __GNUC__
-/* This definition is missing from mingw32 headers. */
+#if defined(__GNUC__) && !defined(__MINGW64__)
+/* This definition is missing from mingw.org headers, but not MinGW64
+ headers. */
extern BOOL WINAPI IsValidLocale (LCID, DWORD);
#endif
static int
start_timer_thread (int which)
{
- DWORD exit_code;
+ DWORD exit_code, tid;
HANDLE th;
struct itimer_data *itimer =
(which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
the way of threads we start to wait for subprocesses. See also
new_child below. */
itimer->timer_thread = CreateThread (NULL, 64 * 1024, timer_loop,
- (void *)itimer, 0x00010000, NULL);
+ (void *)itimer, 0x00010000, &tid);
if (!itimer->timer_thread)
{
DWORD id;
for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
- if (!CHILD_ACTIVE (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;
if (fd_info[i].cp == cp)
emacs_abort ();
- if (!CHILD_ACTIVE (cp))
+ if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess == NULL)
return;
/* reap thread if necessary */
if (cp == child_procs + child_proc_count - 1)
{
for (i = child_proc_count-1; i >= 0; i--)
- if (CHILD_ACTIVE (&child_procs[i]))
+ if (CHILD_ACTIVE (&child_procs[i])
+ || child_procs[i].procinfo.hProcess != NULL)
{
child_proc_count = i + 1;
break;
child_process *cp;
for (cp = child_procs + (child_proc_count-1); cp >= child_procs; cp--)
- if (CHILD_ACTIVE (cp) && pid == cp->pid)
+ if ((CHILD_ACTIVE (cp) || cp->procinfo.hProcess != NULL)
+ && pid == cp->pid)
return cp;
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
{
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;
}
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)
{
"%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;
}
-/* To avoid Emacs changing directory, we just record here the directory
- the new process should start in. This is set just before calling
- sys_spawnve, and is not generally valid at any other time. */
+/* To avoid Emacs changing directory, we just record here the
+ directory the new process should start in. This is set just before
+ calling sys_spawnve, and is not generally valid at any other time.
+ Note that this directory's name is UTF-8 encoded. */
static char * process_dir;
static BOOL
create_child (char *exe, char *cmdline, char *env, int is_gui_app,
- int * pPid, child_process *cp)
+ pid_t * pPid, child_process *cp)
{
STARTUPINFO start;
SECURITY_ATTRIBUTES sec_attrs;
SECURITY_DESCRIPTOR sec_desc;
#endif
DWORD flags;
- char dir[ MAXPATHLEN ];
+ char dir[ MAX_PATH ];
+ char *p;
if (cp == NULL) emacs_abort ();
sec_attrs.lpSecurityDescriptor = NULL /* &sec_desc */;
sec_attrs.bInheritHandle = FALSE;
- strcpy (dir, process_dir);
- unixtodos_filename (dir);
+ filename_to_ansi (process_dir, dir);
+ /* Can't use unixtodos_filename here, since that needs its file name
+ argument encoded in UTF-8. OTOH, process_dir, which _is_ in
+ UTF-8, points, to the directory computed by our caller, and we
+ don't want to modify that, either. */
+ for (p = dir; *p; p = CharNextA (p))
+ if (*p == '/')
+ *p = '\\';
flags = (!NILP (Vw32_start_process_share_console)
? CREATE_NEW_PROCESS_GROUP
: CREATE_NEW_CONSOLE);
if (NILP (Vw32_start_process_inherit_error_mode))
flags |= CREATE_DEFAULT_ERROR_MODE;
- if (!CreateProcess (exe, cmdline, &sec_attrs, NULL, TRUE,
- flags, env, dir, &start, &cp->procinfo))
+ if (!CreateProcessA (exe, cmdline, &sec_attrs, NULL, TRUE,
+ flags, env, dir, &start, &cp->procinfo))
goto EH_Fail;
cp->pid = (int) cp->procinfo.dwProcessId;
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
entries in child_procs. */
void
-register_child (int pid, int fd)
+register_child (pid_t pid, int fd)
{
child_process *cp;
- cp = find_child_pid (pid);
+ cp = find_child_pid ((DWORD)pid);
if (cp == NULL)
{
DebPrint (("register_child unable to find pid %lu\n", pid));
fd_info[fd].cp = cp;
}
-/* When a process dies its pipe will break so the reader thread will
- signal failure to the select emulator.
- The select emulator then calls this routine to clean up.
- Since the thread signaled failure we can assume it is exiting. */
+/* Called from waitpid when a process exits. */
static void
reap_subprocess (child_process *cp)
{
#ifdef FULL_DEBUG
/* Process should have already died before we are called. */
if (WaitForSingleObject (cp->procinfo.hProcess, 0) != WAIT_OBJECT_0)
- DebPrint (("reap_subprocess: child fpr fd %d has not died yet!", cp->fd));
+ DebPrint (("reap_subprocess: child for fd %d has not died yet!", cp->fd));
#endif
CloseHandle (cp->procinfo.hProcess);
cp->procinfo.hProcess = NULL;
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);
}
# define IMAGE_OPTIONAL_HEADER32 IMAGE_OPTIONAL_HEADER
#endif
+/* Implementation note: This function works with file names encoded in
+ the current ANSI codepage. */
static void
w32_executable_type (char * filename,
int * is_dos_app,
Lisp_Object program, full;
char *cmdline, *env, *parg, **targ;
int arglen, numenv;
- int pid;
+ pid_t pid;
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];
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 = '\\';
+ char cmdname_a[MAX_PATH];
/* We don't care about the other modes */
if (mode != _P_NOWAIT)
return -1;
}
- /* Handle executable names without an executable suffix. */
- program = build_string (cmdname);
- if (NILP (Ffile_executable_p (program)))
+ /* Handle executable names without an executable suffix. The caller
+ already searched exec-path and verified the file is executable,
+ but start-process doesn't do that for file names that are already
+ absolute. So we double-check this here, just in case. */
+ if (faccessat (AT_FDCWD, cmdname, X_OK, AT_EACCESS) != 0)
{
struct gcpro gcpro1;
+ program = build_string (cmdname);
full = Qnil;
GCPRO1 (program);
- openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK));
+ openp (Vexec_path, program, Vexec_suffixes, &full, make_number (X_OK), 0);
UNGCPRO;
if (NILP (full))
{
errno = EINVAL;
return -1;
}
- program = full;
+ program = ENCODE_FILE (full);
+ cmdname = SDATA (program);
}
/* make sure argv[0] and cmdname are both in DOS format */
- cmdname = SDATA (program);
unixtodos_filename (cmdname);
+ /* argv[0] was encoded by caller using ENCODE_FILE, so it is in
+ UTF-8. All the other arguments are encoded by ENCODE_SYSTEM or
+ some such, and are in some ANSI codepage. We need to have
+ argv[0] encoded in ANSI codepage. */
+ filename_to_ansi (cmdname, cmdname_a);
+ /* We explicitly require that the command's file name be encodable
+ in the current ANSI codepage, because we will be invoking it via
+ the ANSI APIs. */
+ if (_mbspbrk (cmdname_a, "?"))
+ {
+ errno = ENOENT;
+ return -1;
+ }
+ /* From here on, CMDNAME is an ANSI-encoded string. */
+ cmdname = cmdname_a;
argv[0] = cmdname;
/* Determine whether program is a 16-bit DOS executable, or a 32-bit Windows
while leaving the real app name as argv[0]. */
if (is_dos_app)
{
- cmdname = alloca (MAXPATHLEN);
+ char *p;
+
+ cmdname = alloca (MAX_PATH);
if (egetenv ("CMDPROXY"))
strcpy (cmdname, egetenv ("CMDPROXY"));
else
strcpy (cmdname, SDATA (Vinvocation_directory));
strcat (cmdname, "cmdproxy.exe");
}
- unixtodos_filename (cmdname);
+
+ /* Can't use unixtodos_filename here, since that needs its file
+ name argument encoded in UTF-8. */
+ for (p = cmdname; *p; p = CharNextA (p))
+ if (*p == '/')
+ *p = '\\';
}
/* we have to do some conjuring here to put argv and envp into the
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
{
- /* Child process and socket input */
+ /* Child process and socket/comm port input. */
cp = fd_info[i].cp;
if (cp)
{
/* Wake up the reader thread for this process */
cp->status = STATUS_READ_READY;
if (!SetEvent (cp->char_consumed))
- DebPrint (("nt_select.SetEvent failed with "
+ DebPrint (("sys_select.SetEvent failed with "
"%lu for fd %ld\n", GetLastError (), i));
}
/* 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)
{
/* Emulate 'kill', but only for other processes. */
int
-sys_kill (int pid, int sig)
+sys_kill (pid_t pid, int sig)
{
child_process *cp;
HANDLE proc_hand;
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)
{
filename = Fexpand_file_name (filename, Qnil);
/* luckily, this returns the short version of each element in the path. */
- if (GetShortPathName (SDATA (ENCODE_FILE (filename)), shortname, MAX_PATH) == 0)
+ if (w32_get_short_filename (SDATA (ENCODE_FILE (filename)),
+ shortname, MAX_PATH) == 0)
return Qnil;
dostounix_filename (shortname);
+ /* No need to DECODE_FILE, because 8.3 names are pure ASCII. */
return build_string (shortname);
}
All path elements in FILENAME are converted to their long names. */)
(Lisp_Object filename)
{
- char longname[ MAX_PATH ];
+ char longname[ MAX_UTF8_PATH ];
int drive_only = 0;
CHECK_STRING (filename);
/* first expand it. */
filename = Fexpand_file_name (filename, Qnil);
- if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname, MAX_PATH))
+ if (!w32_get_long_filename (SDATA (ENCODE_FILE (filename)), longname,
+ MAX_UTF8_PATH))
return Qnil;
dostounix_filename (longname);
if (drive_only && longname[1] == ':' && longname[2] == '/' && !longname[3])
longname[2] = '\0';
- return DECODE_FILE (build_string (longname));
+ return DECODE_FILE (build_unibyte_string (longname));
}
DEFUN ("w32-set-process-priority", Fw32_set_process_priority,
{
while (--num_layouts >= 0)
{
- DWORD kl = (DWORD) layouts[num_layouts];
+ HKL kl = layouts[num_layouts];
- obj = Fcons (Fcons (make_number (kl & 0xffff),
- make_number ((kl >> 16) & 0xffff)),
+ obj = Fcons (Fcons (make_number (LOWORD (kl)),
+ make_number (HIWORD (kl))),
obj);
}
}
The return value is the cons of the language id and the layout id. */)
(void)
{
- DWORD kl = (DWORD) GetKeyboardLayout (dwWindowsThreadId);
+ HKL kl = GetKeyboardLayout (dwWindowsThreadId);
- return Fcons (make_number (kl & 0xffff),
- make_number ((kl >> 16) & 0xffff));
+ return Fcons (make_number (LOWORD (kl)),
+ make_number (HIWORD (kl)));
}
If successful, the new layout id is returned, otherwise nil. */)
(Lisp_Object layout)
{
- DWORD kl;
+ HKL kl;
CHECK_CONS (layout);
CHECK_NUMBER_CAR (layout);
CHECK_NUMBER_CDR (layout);
- kl = (XINT (XCAR (layout)) & 0xffff)
- | (XINT (XCDR (layout)) << 16);
+ kl = (HKL) ((XINT (XCAR (layout)) & 0xffff)
+ | (XINT (XCDR (layout)) << 16));
/* Synchronize layout with input thread. */
if (dwWindowsThreadId)
return Qnil;
}
}
- else if (!ActivateKeyboardLayout ((HKL) kl, 0))
+ else if (!ActivateKeyboardLayout (kl, 0))
return Qnil;
return Fw32_get_keyboard_layout ();