-/* Process support for GNU Emacs on the Microsoft W32 API.
- Copyright (C) 1992, 1995, 1999-2012 Free Software Foundation, Inc.
+/* Process support for GNU Emacs on the Microsoft Windows API.
+ Copyright (C) 1992, 1995, 1999-2013 Free Software Foundation, Inc.
This file is part of GNU Emacs.
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
+#include <ctype.h>
#include <io.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/file.h>
-#include <setjmp.h>
/* must include CRT headers *before* config.h */
#include <config.h>
#include "lisp.h"
#include "w32.h"
+#include "w32common.h"
#include "w32heap.h"
#include "systime.h"
#include "syswait.h"
#define RVA_TO_PTR(var,section,filedata) \
((void *)((section)->PointerToRawData \
- + ((DWORD)(var) - (section)->VirtualAddress) \
+ + ((DWORD_PTR)(var) - (section)->VirtualAddress) \
+ (filedata).file_base))
Lisp_Object Qhigh, Qlow;
-#ifdef EMACSDEBUG
-void
-_DebPrint (const char *fmt, ...)
-{
- char buf[1024];
- va_list args;
-
- va_start (args, fmt);
- vsprintf (buf, fmt, args);
- va_end (args);
- OutputDebugString (buf);
-}
-#endif
-
-typedef void (_CALLBACK_ *signal_handler) (int);
-
/* Signal handlers...SIG_DFL == 0 so this is initialized correctly. */
static signal_handler sig_handlers[NSIG];
-/* Fake signal implementation to record the SIGCHLD handler. */
+static sigset_t sig_mask;
+
+static CRITICAL_SECTION crit_sig;
+
+/* Improve on the CRT 'signal' implementation so that we could record
+ the SIGCHLD handler and fake interval timers. */
signal_handler
sys_signal (int sig, signal_handler handler)
{
signal_handler old;
- if (sig != SIGCHLD)
+ /* SIGCHLD is needed for supporting subprocesses, see sys_kill
+ below. SIGALRM and SIGPROF are used by setitimer. All the
+ others are the only ones supported by the MS runtime. */
+ if (!(sig == SIGCHLD || sig == SIGSEGV || sig == SIGILL
+ || sig == SIGFPE || sig == SIGABRT || sig == SIGTERM
+ || sig == SIGALRM || sig == SIGPROF))
{
errno = EINVAL;
return SIG_ERR;
}
old = sig_handlers[sig];
- sig_handlers[sig] = handler;
+ /* SIGABRT is treated specially because w32.c installs term_ntproc
+ as its handler, so we don't want to override that afterwards.
+ Aborting Emacs works specially anyway: either by calling
+ emacs_abort directly or through terminate_due_to_signal, which
+ calls emacs_abort through emacs_raise. */
+ if (!(sig == SIGABRT && old == term_ntproc))
+ {
+ sig_handlers[sig] = handler;
+ if (!(sig == SIGCHLD || sig == SIGALRM || sig == SIGPROF))
+ signal (sig, handler);
+ }
return old;
}
+/* Emulate sigaction. */
+int
+sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
+{
+ signal_handler old = SIG_DFL;
+ int retval = 0;
+
+ if (act)
+ old = sys_signal (sig, act->sa_handler);
+ else if (oact)
+ old = sig_handlers[sig];
+
+ if (old == SIG_ERR)
+ {
+ errno = EINVAL;
+ retval = -1;
+ }
+ if (oact)
+ {
+ oact->sa_handler = old;
+ oact->sa_flags = 0;
+ oact->sa_mask = empty_mask;
+ }
+ return retval;
+}
+
+/* Emulate signal sets and blocking of signals used by timers. */
+
+int
+sigemptyset (sigset_t *set)
+{
+ *set = 0;
+ return 0;
+}
+
+int
+sigaddset (sigset_t *set, int signo)
+{
+ if (!set)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (signo < 0 || signo >= NSIG)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *set |= (1U << signo);
+
+ return 0;
+}
+
+int
+sigfillset (sigset_t *set)
+{
+ if (!set)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ *set = 0xFFFFFFFF;
+ return 0;
+}
+
+int
+sigprocmask (int how, const sigset_t *set, sigset_t *oset)
+{
+ if (!(how == SIG_BLOCK || how == SIG_UNBLOCK || how == SIG_SETMASK))
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (oset)
+ *oset = sig_mask;
+
+ if (!set)
+ return 0;
+
+ switch (how)
+ {
+ case SIG_BLOCK:
+ sig_mask |= *set;
+ break;
+ case SIG_SETMASK:
+ sig_mask = *set;
+ break;
+ case SIG_UNBLOCK:
+ /* FIXME: Catch signals that are blocked and reissue them when
+ they are unblocked. Important for SIGALRM and SIGPROF only. */
+ sig_mask &= ~(*set);
+ break;
+ }
+
+ return 0;
+}
+
+int
+pthread_sigmask (int how, const sigset_t *set, sigset_t *oset)
+{
+ if (sigprocmask (how, set, oset) == -1)
+ return EINVAL;
+ return 0;
+}
+
+int
+sigismember (const sigset_t *set, int signo)
+{
+ if (signo < 0 || signo >= NSIG)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (signo > sizeof (*set) * BITS_PER_CHAR)
+ emacs_abort ();
+
+ return (*set & (1U << signo)) != 0;
+}
+
+int
+setpgrp (int pid, int gid)
+{
+ return 0;
+}
+
+pid_t
+getpgrp (void)
+{
+ return getpid ();
+}
+
+int
+setpgid (pid_t pid, pid_t pgid)
+{
+ return 0;
+}
+
+/* Emulations of interval timers.
+
+ Limitations: only ITIMER_REAL and ITIMER_PROF are supported.
+
+ Implementation: a separate thread is started for each timer type,
+ the thread calls the appropriate signal handler when the timer
+ expires, after stopping the thread which installed the timer. */
+
+struct itimer_data {
+ volatile ULONGLONG expire;
+ volatile ULONGLONG reload;
+ volatile int terminate;
+ int type;
+ HANDLE caller_thread;
+ HANDLE timer_thread;
+};
+
+static ULONGLONG ticks_now;
+static struct itimer_data real_itimer, prof_itimer;
+static ULONGLONG clocks_min;
+/* If non-zero, itimers are disabled. Used during shutdown, when we
+ delete the critical sections used by the timer threads. */
+static int disable_itimers;
+
+static CRITICAL_SECTION crit_real, crit_prof;
+
+/* GetThreadTimes is not available on Windows 9X and possibly also on 2K. */
+typedef BOOL (WINAPI *GetThreadTimes_Proc) (
+ HANDLE hThread,
+ LPFILETIME lpCreationTime,
+ LPFILETIME lpExitTime,
+ LPFILETIME lpKernelTime,
+ LPFILETIME lpUserTime);
+
+static GetThreadTimes_Proc s_pfn_Get_Thread_Times;
+
+#define MAX_SINGLE_SLEEP 30
+#define TIMER_TICKS_PER_SEC 1000
+
+/* Return a suitable time value, in 1-ms units, for THREAD, a handle
+ to a thread. If THREAD is NULL or an invalid handle, return the
+ current wall-clock time since January 1, 1601 (UTC). Otherwise,
+ return the sum of kernel and user times used by THREAD since it was
+ created, plus its creation time. */
+static ULONGLONG
+w32_get_timer_time (HANDLE thread)
+{
+ ULONGLONG retval;
+ int use_system_time = 1;
+ /* The functions below return times in 100-ns units. */
+ const int tscale = 10 * TIMER_TICKS_PER_SEC;
+
+ if (thread && thread != INVALID_HANDLE_VALUE
+ && s_pfn_Get_Thread_Times != NULL)
+ {
+ FILETIME creation_ftime, exit_ftime, kernel_ftime, user_ftime;
+ ULARGE_INTEGER temp_creation, temp_kernel, temp_user;
+
+ if (s_pfn_Get_Thread_Times (thread, &creation_ftime, &exit_ftime,
+ &kernel_ftime, &user_ftime))
+ {
+ use_system_time = 0;
+ temp_creation.LowPart = creation_ftime.dwLowDateTime;
+ temp_creation.HighPart = creation_ftime.dwHighDateTime;
+ temp_kernel.LowPart = kernel_ftime.dwLowDateTime;
+ temp_kernel.HighPart = kernel_ftime.dwHighDateTime;
+ temp_user.LowPart = user_ftime.dwLowDateTime;
+ temp_user.HighPart = user_ftime.dwHighDateTime;
+ retval =
+ temp_creation.QuadPart / tscale + temp_kernel.QuadPart / tscale
+ + temp_user.QuadPart / tscale;
+ }
+ else
+ DebPrint (("GetThreadTimes failed with error code %lu\n",
+ GetLastError ()));
+ }
+
+ if (use_system_time)
+ {
+ FILETIME current_ftime;
+ ULARGE_INTEGER temp;
+
+ GetSystemTimeAsFileTime (¤t_ftime);
+
+ temp.LowPart = current_ftime.dwLowDateTime;
+ temp.HighPart = current_ftime.dwHighDateTime;
+
+ retval = temp.QuadPart / tscale;
+ }
+
+ return retval;
+}
+
+/* Thread function for a timer thread. */
+static DWORD WINAPI
+timer_loop (LPVOID arg)
+{
+ struct itimer_data *itimer = (struct itimer_data *)arg;
+ int which = itimer->type;
+ int sig = (which == ITIMER_REAL) ? SIGALRM : SIGPROF;
+ CRITICAL_SECTION *crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof;
+ const DWORD max_sleep = MAX_SINGLE_SLEEP * 1000 / TIMER_TICKS_PER_SEC;
+ HANDLE hth = (which == ITIMER_REAL) ? NULL : itimer->caller_thread;
+
+ while (1)
+ {
+ DWORD sleep_time;
+ signal_handler handler;
+ ULONGLONG now, expire, reload;
+
+ /* Load new values if requested by setitimer. */
+ EnterCriticalSection (crit);
+ expire = itimer->expire;
+ reload = itimer->reload;
+ LeaveCriticalSection (crit);
+ if (itimer->terminate)
+ return 0;
+
+ if (expire == 0)
+ {
+ /* We are idle. */
+ Sleep (max_sleep);
+ continue;
+ }
+
+ if (expire > (now = w32_get_timer_time (hth)))
+ sleep_time = expire - now;
+ else
+ sleep_time = 0;
+ /* Don't sleep too long at a time, to be able to see the
+ termination flag without too long a delay. */
+ while (sleep_time > max_sleep)
+ {
+ if (itimer->terminate)
+ return 0;
+ Sleep (max_sleep);
+ EnterCriticalSection (crit);
+ expire = itimer->expire;
+ LeaveCriticalSection (crit);
+ sleep_time =
+ (expire > (now = w32_get_timer_time (hth))) ? expire - now : 0;
+ }
+ if (itimer->terminate)
+ return 0;
+ if (sleep_time > 0)
+ {
+ Sleep (sleep_time * 1000 / TIMER_TICKS_PER_SEC);
+ /* Always sleep past the expiration time, to make sure we
+ never call the handler _before_ the expiration time,
+ always slightly after it. Sleep(5) makes sure we don't
+ hog the CPU by calling 'w32_get_timer_time' with high
+ frequency, and also let other threads work. */
+ while (w32_get_timer_time (hth) < expire)
+ Sleep (5);
+ }
+
+ EnterCriticalSection (crit);
+ expire = itimer->expire;
+ LeaveCriticalSection (crit);
+ if (expire == 0)
+ continue;
+
+ /* Time's up. */
+ handler = sig_handlers[sig];
+ if (!(handler == SIG_DFL || handler == SIG_IGN || handler == SIG_ERR)
+ /* FIXME: Don't ignore masked signals. Instead, record that
+ they happened and reissue them when the signal is
+ unblocked. */
+ && !sigismember (&sig_mask, sig)
+ /* Simulate masking of SIGALRM and SIGPROF when processing
+ fatal signals. */
+ && !fatal_error_in_progress
+ && itimer->caller_thread)
+ {
+ /* Simulate a signal delivered to the thread which installed
+ the timer, by suspending that thread while the handler
+ runs. */
+ HANDLE th = itimer->caller_thread;
+ DWORD result = SuspendThread (th);
+
+ if (result == (DWORD)-1)
+ return 2;
+
+ handler (sig);
+ ResumeThread (th);
+ }
+
+ /* Update expiration time and loop. */
+ EnterCriticalSection (crit);
+ expire = itimer->expire;
+ if (expire == 0)
+ {
+ LeaveCriticalSection (crit);
+ continue;
+ }
+ reload = itimer->reload;
+ if (reload > 0)
+ {
+ now = w32_get_timer_time (hth);
+ if (expire <= now)
+ {
+ ULONGLONG lag = now - expire;
+
+ /* If we missed some opportunities (presumably while
+ sleeping or while the signal handler ran), skip
+ them. */
+ if (lag > reload)
+ expire = now - (lag % reload);
+
+ expire += reload;
+ }
+ }
+ else
+ expire = 0; /* become idle */
+ itimer->expire = expire;
+ LeaveCriticalSection (crit);
+ }
+ return 0;
+}
+
+static void
+stop_timer_thread (int which)
+{
+ struct itimer_data *itimer =
+ (which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
+ int i;
+ DWORD err, exit_code = 255;
+ BOOL status;
+
+ /* Signal the thread that it should terminate. */
+ itimer->terminate = 1;
+
+ if (itimer->timer_thread == NULL)
+ return;
+
+ /* Wait for the timer thread to terminate voluntarily, then kill it
+ if it doesn't. This loop waits twice more than the maximum
+ amount of time a timer thread sleeps, see above. */
+ for (i = 0; i < MAX_SINGLE_SLEEP / 5; i++)
+ {
+ if (!((status = GetExitCodeThread (itimer->timer_thread, &exit_code))
+ && exit_code == STILL_ACTIVE))
+ break;
+ Sleep (10);
+ }
+ if ((status == FALSE && (err = GetLastError ()) == ERROR_INVALID_HANDLE)
+ || exit_code == STILL_ACTIVE)
+ {
+ if (!(status == FALSE && err == ERROR_INVALID_HANDLE))
+ TerminateThread (itimer->timer_thread, 0);
+ }
+
+ /* Clean up. */
+ CloseHandle (itimer->timer_thread);
+ itimer->timer_thread = NULL;
+ if (itimer->caller_thread)
+ {
+ CloseHandle (itimer->caller_thread);
+ itimer->caller_thread = NULL;
+ }
+}
+
+/* This is called at shutdown time from term_ntproc. */
+void
+term_timers (void)
+{
+ if (real_itimer.timer_thread)
+ stop_timer_thread (ITIMER_REAL);
+ if (prof_itimer.timer_thread)
+ stop_timer_thread (ITIMER_PROF);
+
+ /* We are going to delete the critical sections, so timers cannot
+ work after this. */
+ disable_itimers = 1;
+
+ DeleteCriticalSection (&crit_real);
+ DeleteCriticalSection (&crit_prof);
+ DeleteCriticalSection (&crit_sig);
+}
+
+/* This is called at initialization time from init_ntproc. */
+void
+init_timers (void)
+{
+ /* GetThreadTimes is not available on all versions of Windows, so
+ need to probe for its availability dynamically, and call it
+ through a pointer. */
+ s_pfn_Get_Thread_Times = NULL; /* in case dumped Emacs comes with a value */
+ if (os_subtype != OS_9X)
+ s_pfn_Get_Thread_Times =
+ (GetThreadTimes_Proc)GetProcAddress (GetModuleHandle ("kernel32.dll"),
+ "GetThreadTimes");
+
+ /* Make sure we start with zeroed out itimer structures, since
+ dumping may have left there traces of threads long dead. */
+ memset (&real_itimer, 0, sizeof real_itimer);
+ memset (&prof_itimer, 0, sizeof prof_itimer);
+
+ InitializeCriticalSection (&crit_real);
+ InitializeCriticalSection (&crit_prof);
+ InitializeCriticalSection (&crit_sig);
+
+ disable_itimers = 0;
+}
+
+static int
+start_timer_thread (int which)
+{
+ DWORD exit_code;
+ HANDLE th;
+ struct itimer_data *itimer =
+ (which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
+
+ if (itimer->timer_thread
+ && GetExitCodeThread (itimer->timer_thread, &exit_code)
+ && exit_code == STILL_ACTIVE)
+ return 0;
+
+ /* Clean up after possibly exited thread. */
+ if (itimer->timer_thread)
+ {
+ CloseHandle (itimer->timer_thread);
+ itimer->timer_thread = NULL;
+ }
+ if (itimer->caller_thread)
+ {
+ CloseHandle (itimer->caller_thread);
+ itimer->caller_thread = NULL;
+ }
+
+ /* Start a new thread. */
+ if (!DuplicateHandle (GetCurrentProcess (), GetCurrentThread (),
+ GetCurrentProcess (), &th, 0, FALSE,
+ DUPLICATE_SAME_ACCESS))
+ {
+ errno = ESRCH;
+ return -1;
+ }
+ itimer->terminate = 0;
+ itimer->type = which;
+ itimer->caller_thread = th;
+ /* Request that no more than 64KB of stack be reserved for this
+ thread, to avoid reserving too much memory, which would get in
+ 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);
+
+ if (!itimer->timer_thread)
+ {
+ CloseHandle (itimer->caller_thread);
+ itimer->caller_thread = NULL;
+ errno = EAGAIN;
+ return -1;
+ }
+
+ /* This is needed to make sure that the timer thread running for
+ profiling gets CPU as soon as the Sleep call terminates. */
+ if (which == ITIMER_PROF)
+ SetThreadPriority (itimer->timer_thread, THREAD_PRIORITY_TIME_CRITICAL);
+
+ return 0;
+}
+
+/* Most of the code of getitimer and setitimer (but not of their
+ subroutines) was shamelessly stolen from itimer.c in the DJGPP
+ library, see www.delorie.com/djgpp. */
+int
+getitimer (int which, struct itimerval *value)
+{
+ volatile ULONGLONG *t_expire;
+ volatile ULONGLONG *t_reload;
+ ULONGLONG expire, reload;
+ __int64 usecs;
+ CRITICAL_SECTION *crit;
+ struct itimer_data *itimer;
+
+ if (disable_itimers)
+ return -1;
+
+ if (!value)
+ {
+ errno = EFAULT;
+ return -1;
+ }
+
+ if (which != ITIMER_REAL && which != ITIMER_PROF)
+ {
+ errno = EINVAL;
+ return -1;
+ }
+
+ itimer = (which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
+
+ ticks_now = w32_get_timer_time ((which == ITIMER_REAL)
+ ? NULL
+ : GetCurrentThread ());
+
+ t_expire = &itimer->expire;
+ t_reload = &itimer->reload;
+ crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof;
+
+ EnterCriticalSection (crit);
+ reload = *t_reload;
+ expire = *t_expire;
+ LeaveCriticalSection (crit);
+
+ if (expire)
+ expire -= ticks_now;
+
+ value->it_value.tv_sec = expire / TIMER_TICKS_PER_SEC;
+ usecs =
+ (expire % TIMER_TICKS_PER_SEC) * (__int64)1000000 / TIMER_TICKS_PER_SEC;
+ value->it_value.tv_usec = usecs;
+ value->it_interval.tv_sec = reload / TIMER_TICKS_PER_SEC;
+ usecs =
+ (reload % TIMER_TICKS_PER_SEC) * (__int64)1000000 / TIMER_TICKS_PER_SEC;
+ value->it_interval.tv_usec= usecs;
+
+ return 0;
+}
+
+int
+setitimer(int which, struct itimerval *value, struct itimerval *ovalue)
+{
+ volatile ULONGLONG *t_expire, *t_reload;
+ ULONGLONG expire, reload, expire_old, reload_old;
+ __int64 usecs;
+ CRITICAL_SECTION *crit;
+ struct itimerval tem, *ptem;
+
+ if (disable_itimers)
+ return -1;
+
+ /* Posix systems expect timer values smaller than the resolution of
+ the system clock be rounded up to the clock resolution. First
+ time we are called, measure the clock tick resolution. */
+ if (!clocks_min)
+ {
+ ULONGLONG t1, t2;
+
+ for (t1 = w32_get_timer_time (NULL);
+ (t2 = w32_get_timer_time (NULL)) == t1; )
+ ;
+ clocks_min = t2 - t1;
+ }
+
+ if (ovalue)
+ ptem = ovalue;
+ else
+ ptem = &tem;
+
+ if (getitimer (which, ptem)) /* also sets ticks_now */
+ return -1; /* errno already set */
+
+ t_expire =
+ (which == ITIMER_REAL) ? &real_itimer.expire : &prof_itimer.expire;
+ t_reload =
+ (which == ITIMER_REAL) ? &real_itimer.reload : &prof_itimer.reload;
+
+ crit = (which == ITIMER_REAL) ? &crit_real : &crit_prof;
+
+ if (!value
+ || (value->it_value.tv_sec == 0 && value->it_value.tv_usec == 0))
+ {
+ EnterCriticalSection (crit);
+ /* Disable the timer. */
+ *t_expire = 0;
+ *t_reload = 0;
+ LeaveCriticalSection (crit);
+ return 0;
+ }
+
+ reload = value->it_interval.tv_sec * TIMER_TICKS_PER_SEC;
+
+ usecs = value->it_interval.tv_usec;
+ if (value->it_interval.tv_sec == 0
+ && usecs && usecs * TIMER_TICKS_PER_SEC < clocks_min * 1000000)
+ reload = clocks_min;
+ else
+ {
+ usecs *= TIMER_TICKS_PER_SEC;
+ reload += usecs / 1000000;
+ }
+
+ expire = value->it_value.tv_sec * TIMER_TICKS_PER_SEC;
+ usecs = value->it_value.tv_usec;
+ if (value->it_value.tv_sec == 0
+ && usecs * TIMER_TICKS_PER_SEC < clocks_min * 1000000)
+ expire = clocks_min;
+ else
+ {
+ usecs *= TIMER_TICKS_PER_SEC;
+ expire += usecs / 1000000;
+ }
+
+ expire += ticks_now;
+
+ EnterCriticalSection (crit);
+ expire_old = *t_expire;
+ reload_old = *t_reload;
+ if (!(expire == expire_old && reload == reload_old))
+ {
+ *t_reload = reload;
+ *t_expire = expire;
+ }
+ LeaveCriticalSection (crit);
+
+ return start_timer_thread (which);
+}
+
+int
+alarm (int seconds)
+{
+#ifdef HAVE_SETITIMER
+ struct itimerval new_values, old_values;
+
+ new_values.it_value.tv_sec = seconds;
+ new_values.it_value.tv_usec = 0;
+ new_values.it_interval.tv_sec = new_values.it_interval.tv_usec = 0;
+
+ if (setitimer (ITIMER_REAL, &new_values, &old_values) < 0)
+ return 0;
+ return old_values.it_value.tv_sec;
+#else
+ return seconds;
+#endif
+}
+
/* Defined in <process.h> which conflicts with the local copy */
#define _P_NOWAIT 1
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;
/* Should not be deleting a child that is still needed. */
for (i = 0; i < MAXDESC; i++)
if (fd_info[i].cp == cp)
- abort ();
+ emacs_abort ();
if (!CHILD_ACTIVE (cp))
return;
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;
}
DWORD flags;
char dir[ MAXPATHLEN ];
- if (cp == NULL) abort ();
+ if (cp == NULL) emacs_abort ();
memset (&start, 0, sizeof (start));
start.cb = sizeof (start);
if (fd_info[fd].cp != NULL)
{
DebPrint (("register_child: fd_info[%d] apparently in use!\n", fd));
- abort ();
+ emacs_abort ();
}
fd_info[fd].cp = cp;
/* We want to wait for a specific child */
wait_hnd[nh] = dead_child->procinfo.hProcess;
cps[nh] = dead_child;
- if (!wait_hnd[nh]) abort ();
+ if (!wait_hnd[nh]) emacs_abort ();
nh++;
active = 0;
goto get_result;
active -= WAIT_ABANDONED_0;
}
else
- abort ();
+ emacs_abort ();
get_result:
if (!GetExitCodeProcess (wait_hnd[active], &retval))
/* Report the status of the synchronous process. */
if (WIFEXITED (retval))
- synch_process_retcode = WRETCODE (retval);
+ synch_process_retcode = WEXITSTATUS (retval);
else if (WIFSIGNALED (retval))
{
int code = WTERMSIG (retval);
- char *signame;
+ const char *signame;
synchronize_system_messages_locale ();
signame = strsignal (code);
if (dos_header->e_magic != IMAGE_DOS_SIGNATURE)
goto unwind;
- nt_header = (PIMAGE_NT_HEADERS) ((char *) dos_header + dos_header->e_lfanew);
+ nt_header = (PIMAGE_NT_HEADERS) ((unsigned char *) dos_header + dos_header->e_lfanew);
if ((char *) nt_header > (char *) dos_header + executable.size)
{
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 = '\\';
/* We don't care about the other modes */
if (mode != _P_NOWAIT)
unixtodos_filename (cmdname);
argv[0] = cmdname;
- /* Determine whether program is a 16-bit DOS executable, or a w32
+ /* Determine whether program is a 16-bit DOS executable, or a 32-bit Windows
executable that is implicitly linked to the Cygnus dll (implying it
was compiled with the Cygnus GNU toolchain and hence relies on
cygwin.dll to parse the command line - we use this to decide how to
numenv++;
}
/* extra env vars... */
- sprintf (ppid_env_var_buffer, "EM_PARENT_PROCESS_ID=%d",
+ sprintf (ppid_env_var_buffer, "EM_PARENT_PROCESS_ID=%lu",
GetCurrentProcessId ());
arglen += strlen (ppid_env_var_buffer) + 1;
numenv++;
int
sys_select (int nfds, SELECT_TYPE *rfds, SELECT_TYPE *wfds, SELECT_TYPE *efds,
- EMACS_TIME *timeout)
+ EMACS_TIME *timeout, void *ignored)
{
SELECT_TYPE orfds;
DWORD timeout_ms, start_time;
#endif
wait_hnd[nh] = cp->char_avail;
fdindex[nh] = i;
- if (!wait_hnd[nh]) abort ();
+ if (!wait_hnd[nh]) emacs_abort ();
nh++;
#ifdef FULL_DEBUG
DebPrint (("select waiting on child %d fd %d\n",
active -= WAIT_ABANDONED_0;
}
else
- abort ();
+ emacs_abort ();
/* Loop over all handles after active (now officially documented as
being the first signaled handle in the array). We do this to
GetClassName (hwnd, window_class, sizeof (window_class));
if (strcmp (window_class,
- (os_subtype == OS_WIN95)
+ (os_subtype == OS_9X)
? "tty"
: "ConsoleWindowClass") == 0)
{
return TRUE;
}
+/* Emulate 'kill', but only for other processes. */
int
sys_kill (int pid, int sig)
{
cp = find_child_pid (pid);
if (cp == NULL)
{
+ /* We were passed a PID of something other than our subprocess.
+ If that is our own PID, we will send to ourself a message to
+ close the selected frame, which does not necessarily
+ terminates Emacs. But then we are not supposed to call
+ sys_kill with our own PID. */
proc_hand = OpenProcess (PROCESS_TERMINATE, 0, pid);
if (proc_hand == NULL)
{
if (NILP (Vw32_start_process_share_console) && cp && cp->hwnd)
{
#if 1
- if (os_subtype == OS_WIN95)
+ if (os_subtype == OS_9X)
{
/*
Another possibility is to try terminating the VDM out-right by
*/
#if 0
- /* On Win95, posting WM_QUIT causes the 16-bit subsystem
+ /* On Windows 95, posting WM_QUIT causes the 16-bit subsystem
to hang when cmdproxy is used in conjunction with
command.com for an interactive shell. Posting
WM_CLOSE pops up a dialog that, when Yes is selected,
CHECK_NUMBER (process);
/* Allow pid to be an internally generated one, or one obtained
- externally. This is necessary because real pids on Win95 are
+ externally. This is necessary because real pids on Windows 95 are
negative. */
pid = XINT (process);