/* 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-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>
Lisp_Object Qhigh, Qlow;
-typedef void (_CALLBACK_ *signal_handler) (int);
-
/* Signal handlers...SIG_DFL == 0 so this is initialized correctly. */
static signal_handler sig_handlers[NSIG];
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.
the thread calls the appropriate signal handler when the timer
expires, after stopping the thread which installed the timer. */
-/* FIXME: clock_t counts overflow after 49 days, need to handle the
- wrap-around. */
struct itimer_data {
- clock_t expire;
- clock_t reload;
- int terminate;
+ volatile ULONGLONG expire;
+ volatile ULONGLONG reload;
+ volatile int terminate;
int type;
HANDLE caller_thread;
HANDLE timer_thread;
};
-static clock_t ticks_now;
+static ULONGLONG ticks_now;
static struct itimer_data real_itimer, prof_itimer;
-static clock_t clocks_min;
+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;
-#define MAX_SINGLE_SLEEP 30
+/* 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)
{
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 / CLOCKS_PER_SEC;
- int new_count = 0;
+ 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;
- clock_t now, expire, reload;
+ ULONGLONG now, expire, reload;
/* Load new values if requested by setitimer. */
EnterCriticalSection (crit);
if (itimer->terminate)
return 0;
- if (itimer->expire == 0)
+ if (expire == 0)
{
/* We are idle. */
Sleep (max_sleep);
continue;
}
- expire = itimer->expire;
- if (expire > (now = clock ()))
+ if (expire > (now = w32_get_timer_time (hth)))
sleep_time = expire - now;
else
sleep_time = 0;
if (itimer->terminate)
return 0;
Sleep (max_sleep);
+ EnterCriticalSection (crit);
expire = itimer->expire;
- sleep_time = (expire > (now = clock ())) ? expire - now : 0;
+ 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 / CLOCKS_PER_SEC);
+ 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 'clock' with high frequency, and
- also let other threads work. */
- while (clock () < expire)
+ 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);
}
- if (itimer->expire == 0)
+ EnterCriticalSection (crit);
+ expire = itimer->expire;
+ LeaveCriticalSection (crit);
+ if (expire == 0)
continue;
/* Time's up. */
/* Simulate a signal delivered to the thread which installed
the timer, by suspending that thread while the handler
runs. */
- DWORD result = SuspendThread (itimer->caller_thread);
+ HANDLE th = itimer->caller_thread;
+ DWORD result = SuspendThread (th);
if (result == (DWORD)-1)
return 2;
handler (sig);
- ResumeThread (itimer->caller_thread);
+ ResumeThread (th);
}
- if (itimer->expire == 0)
- continue;
-
/* Update expiration time and loop. */
EnterCriticalSection (crit);
expire = itimer->expire;
+ if (expire == 0)
+ {
+ LeaveCriticalSection (crit);
+ continue;
+ }
reload = itimer->reload;
if (reload > 0)
{
- now = clock ();
+ now = w32_get_timer_time (hth);
if (expire <= now)
{
- clock_t lag = now - expire;
+ ULONGLONG lag = now - expire;
/* If we missed some opportunities (presumably while
sleeping or while the signal handler ran), skip
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);
start_timer_thread (int which)
{
DWORD exit_code;
+ HANDLE th;
struct itimer_data *itimer =
(which == ITIMER_REAL) ? &real_itimer : &prof_itimer;
&& 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 (), &itimer->caller_thread, 0,
- FALSE, DUPLICATE_SAME_ACCESS))
+ 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
/* 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->caller_thread, THREAD_PRIORITY_TIME_CRITICAL);
+ SetThreadPriority (itimer->timer_thread, THREAD_PRIORITY_TIME_CRITICAL);
return 0;
}
int
getitimer (int which, struct itimerval *value)
{
- volatile clock_t *t_expire;
- volatile clock_t *t_reload;
- clock_t expire, reload;
+ 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;
- ticks_now = clock ();
-
if (!value)
{
errno = EFAULT;
return -1;
}
- t_expire = (which == ITIMER_REAL) ? &real_itimer.expire: &prof_itimer.expire;
- t_reload = (which == ITIMER_REAL) ? &real_itimer.reload: &prof_itimer.reload;
+ 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);
if (expire)
expire -= ticks_now;
- value->it_value.tv_sec = expire / CLOCKS_PER_SEC;
- usecs = (expire % CLOCKS_PER_SEC) * (__int64)1000000 / CLOCKS_PER_SEC;
+ 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 / CLOCKS_PER_SEC;
- usecs = (reload % CLOCKS_PER_SEC) * (__int64)1000000 / CLOCKS_PER_SEC;
+ 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 clock_t *t_expire, *t_reload;
- clock_t expire, reload, expire_old, reload_old;
+ 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;
time we are called, measure the clock tick resolution. */
if (!clocks_min)
{
- clock_t t1, t2;
+ ULONGLONG t1, t2;
- for (t1 = clock (); (t2 = clock ()) == t1; )
+ for (t1 = w32_get_timer_time (NULL);
+ (t2 = w32_get_timer_time (NULL)) == t1; )
;
clocks_min = t2 - t1;
}
if (ovalue)
- {
- if (getitimer (which, ovalue)) /* also sets ticks_now */
- return -1; /* errno already set */
- }
+ ptem = ovalue;
else
- ticks_now = clock ();
+ ptem = &tem;
- if (which != ITIMER_REAL && which != ITIMER_PROF)
- {
- errno = EINVAL;
- return -1;
- }
+ if (getitimer (which, ptem)) /* also sets ticks_now */
+ return -1; /* errno already set */
t_expire =
(which == ITIMER_REAL) ? &real_itimer.expire : &prof_itimer.expire;
return 0;
}
- reload = value->it_interval.tv_sec * CLOCKS_PER_SEC;
+ 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 * CLOCKS_PER_SEC < clocks_min * 1000000)
+ && usecs && usecs * TIMER_TICKS_PER_SEC < clocks_min * 1000000)
reload = clocks_min;
else
{
- usecs *= CLOCKS_PER_SEC;
+ usecs *= TIMER_TICKS_PER_SEC;
reload += usecs / 1000000;
}
- expire = value->it_value.tv_sec * CLOCKS_PER_SEC;
+ expire = value->it_value.tv_sec * TIMER_TICKS_PER_SEC;
usecs = value->it_value.tv_usec;
if (value->it_value.tv_sec == 0
- && usecs * CLOCKS_PER_SEC < clocks_min * 1000000)
+ && usecs * TIMER_TICKS_PER_SEC < clocks_min * 1000000)
expire = clocks_min;
else
{
- usecs *= CLOCKS_PER_SEC;
+ usecs *= TIMER_TICKS_PER_SEC;
expire += usecs / 1000000;
}
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++];
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;
}
else
rc = _sys_read_ahead (cp->fd);
+ if (!CHILD_ACTIVE (cp) && cp->procinfo.hProcess && cp->fd >= 0)
+ {
+ /* Somebody already called delete_child on this child, since
+ only delete_child zeroes out cp->char_avail. This means
+ no one will read from cp->fd and will not set the
+ FILE_AT_EOF flag, therefore preventing sys_select from
+ noticing that the process died. Set the flag here
+ instead. */
+ fd_info[cp->fd].flags |= FILE_AT_EOF;
+ }
+
/* 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;
}
register_child has not been called. */
if (cp->fd == -1)
delete_child (cp);
+ else
+ {
+ /* Reset the flag set by reader_thread. */
+ fd_info[cp->fd].flags &= ~FILE_AT_EOF;
+ }
}
/* Wait for any of our existing child processes to die
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)
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++;
/* 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)