>>>>> "Craig" == Craig Lanning <CraigL(a)DyCon.com> writes:
Craig> The individual calls to call-process worked just fine so I
Craig> decided to give it your stress test. I started the
Craig> (dotimes ...) and things seemed to be working fine. You
Craig> had asked that I do things while this is running so I
Craig> started iconifying and deiconifying programs, when suddenly
Craig> the blue screen of death appeared. It complained that
Craig> Window's resources were low and asked me if I wanted to
Craig> kill a particular program. The BSoD appeared several more
Craig> times, each time asking about a different program. The
Craig> first program was Explorer. Others were XEmacs, grep, and
Craig> one of the items in the System Tray.
Craig> This sounds like something is not being returned to the OS.
Right on, Craig!
After some heavy (call-process ...) testing I saw some 500 handled
being taken by XEmacs. On NT, however, you don't notice this too much.
So I analyzed and went back to cook up another patch which I'm quite
happy with.
I fixed the bugs where
o a process handle would not be closed for
(call-process "prog" nil 0 ...)
o the STDERR handle opened for
(call-process "prog" nil '(... nil) ...)
(call-process "prog" nil '(... "filename") ...)
would not be closed in the parent on NT.
Also, I took out all the tests for
if (os_subtype == OS_WIN95) {
since the MINGWIN32 build cannot detect it and you're still OK on Win98.
Even under vigorous testing only 0 to 4 handles may remain after
running a couple hundred processes on Windows NT.
But even when doing other things in XEmacs on NT native, unrelated to
call-process, like M-x shell and quiting it again, a few handles seem
to leak.
What it boils down to:
Please try following patch once more and give it a tough test if
things look good. This patch was created against lastest 21.2 CVS.
Cheers,
Adrian
PS: Dan, do you have a compiler yet? This baby needs some testing.
cd d:\tmp\21.2\xemacs\src\
cvs diff
Compilation started at Mon Oct 25 02:50:40 1999 +0200 (W. Europe Daylight Time)
? call-process-notes
? call-process.patch
? call-process.txt
? cvs-diff
? depend-of-make-src-depend
? Installation
? it
? runxemacs.pdb
? sysdep.c.good
? temacs.bsc
? temacs.ilk
? temacs.map
? temacs.pdb
? waitpid.txt
? xemacs.opt
cvs server: Diffing .
Index: callproc.c
===================================================================
RCS file: /usr/CVSroot/XEmacs/xemacs/src/callproc.c,v
retrieving revision 1.29.2.6
diff -u -r1.29.2.6 callproc.c
--- callproc.c 1999/05/01 05:13:23 1.29.2.6
+++ callproc.c 1999/10/25 01:00:09
@@ -104,6 +104,9 @@
{
int fd = XINT (Fcar (fdpid));
int pid = XINT (Fcdr (fdpid));
+#ifdef WINDOWSNT
+ HANDLE pHandle;
+#endif
if (!call_process_exited &&
EMACS_KILLPG (pid, SIGINT) == 0)
@@ -114,7 +117,16 @@
/* #### "c-G" -- need non-consing Single-key-description */
message ("Waiting for process to die...(type C-g again to kill it instantly)");
+#ifdef WINDOWSNT
+ pHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
+ if (pHandle == NULL)
+ {
+ stderr_out ("call_process_cleanup.OpenProcess: pHandle == NULL, GetLastError () = %d, (int)pHandle = %d\n", GetLastError (), (int)pHandle);
+ }
+ wait_for_termination (pHandle);
+#else
wait_for_termination (pid);
+#endif
/* "Discard" the unwind protect. */
XCAR (fdpid) = Qnil;
@@ -170,6 +182,9 @@
Lisp_Object infile, buffer, current_dir, display, path;
int fd[2];
int filefd;
+#ifdef WINDOWSNT
+ HANDLE pHandle;
+#endif
int pid;
char buf[16384];
char *bufptr = buf;
@@ -359,6 +374,19 @@
#ifdef WINDOWSNT
pid = child_setup (filefd, fd1, fd_error, new_argv,
(char *) XSTRING_DATA (current_dir));
+ if (!INTP (buffer))
+ {
+ /* OpenProcess() as soon after child_setup as possible. It's too
+ late once the process terminated. */
+ pHandle = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
+ if (pHandle == NULL)
+ {
+ stderr_out ("Fcall_process_internal: pHandle == NULL, GetLastError () = %d, (int)pHandle = %d\n", GetLastError (), (int)pHandle);
+ }
+ }
+ /* Close STDERR into the parent process. We no longer need it. */
+ if (fd_error >= 0)
+ close (fd_error);
#else /* not WINDOWSNT */
pid = fork ();
@@ -394,12 +422,14 @@
if (!NILP (fork_error))
signal_error (Qfile_error, fork_error);
+#ifndef WINDOWSNT
if (pid < 0)
{
if (fd[0] >= 0)
close (fd[0]);
report_file_error ("Doing fork", Qnil);
}
+#endif
if (INTP (buffer))
{
@@ -507,7 +537,11 @@
QUIT;
/* Wait for it to terminate, unless it already has. */
+#ifdef WINDOWSNT
+ wait_for_termination (pHandle);
+#else
wait_for_termination (pid);
+#endif
/* Don't kill any children that the subprocess may have left behind
when exiting. */
Index: ntproc.c
===================================================================
RCS file: /usr/CVSroot/XEmacs/xemacs/src/ntproc.c,v
retrieving revision 1.14.2.10
diff -u -r1.14.2.10 ntproc.c
--- ntproc.c 1999/10/10 12:40:13 1.14.2.10
+++ ntproc.c 1999/10/25 01:00:20
@@ -445,16 +445,12 @@
cp->procinfo.hThread=NULL;
cp->procinfo.hProcess=NULL;
- /* Hack for Windows 95, which assigns large (ie negative) pids */
- if (cp->pid < 0)
- cp->pid = -cp->pid;
-
/* pid must fit in a Lisp_Int */
-#ifdef USE_UNION_TYPE
- cp->pid = (cp->pid & ((1U << VALBITS) - 1));
-#else
- cp->pid = (cp->pid & VALMASK);
-#endif
+
+ if (cp->pid > EMACS_INT_MAX) {
+ stderr_out ("create_child.CreateProcess abs(PID) %d > EMACS_INT_MAX (%d)\n",
+ cp->pid, EMACS_INT_MAX);
+ }
*pPid = cp->pid;
Index: sysdep.c
===================================================================
RCS file: /usr/CVSroot/XEmacs/xemacs/src/sysdep.c,v
retrieving revision 1.32.2.7
diff -u -r1.32.2.7 sysdep.c
--- sysdep.c 1999/07/05 05:56:44 1.32.2.7
+++ sysdep.c 1999/10/25 01:00:33
@@ -234,8 +234,11 @@
#endif /* NO_SUBPROCESSES */
-void
-wait_for_termination (int pid)
+#ifdef WINDOWSNT
+void wait_for_termination (HANDLE pHandle)
+#else
+void wait_for_termination (int pid)
+#endif
{
/* #### With the new improved SIGCHLD handling stuff, there is much
less danger of race conditions and some of the comments below
@@ -345,6 +348,47 @@
Since implementations may add their own error indicators on top,
we ignore it by default. */
+#elif defined (WINDOWSNT)
+ int ret = 0, status = 0;
+ if (pHandle == NULL)
+ {
+ stderr_out ("wait_for_termination: pHandle == NULL, GetLastError () = %d, (int)pHandle = %d\n", GetLastError (), (int)pHandle);
+ return;
+ }
+ do
+ {
+ QUIT;
+ ret = WaitForSingleObject(pHandle, 100);
+ }
+ while (ret == WAIT_TIMEOUT);
+ if (ret == WAIT_FAILED)
+ {
+ stderr_out ("wait_for_termination.WaitForSingleObject returns %d (WAIT_FAILED) GetLastError () %d for (int)pHandle %d\n", ret, GetLastError (), (int)pHandle);
+ }
+ if (ret == WAIT_ABANDONED)
+ {
+ stderr_out ("wait_for_termination.WaitForSingleObject returns %d (WAIT_ABANDONED) GetLastError () %d for (int)pHandle %d\n", ret, GetLastError (), (int)pHandle);
+ }
+ if (ret == WAIT_OBJECT_0)
+ {
+ ret = GetExitCodeProcess(pHandle, &status);
+ if (ret)
+ {
+ synch_process_alive = 0;
+ synch_process_retcode = status;
+ }
+ else
+ {
+ /* GetExitCodeProcess() didn't return a valid exit status,
+ nothing to do. APA */
+ stderr_out ("wait_for_termination.GetExitCodeProcess status %d GetLastError () %d for (int)pHandle %d\n", status, GetLastError (), (int)pHandle);
+ }
+ }
+ if (pHandle != NULL && !CloseHandle(pHandle))
+ {
+ stderr_out ("wait_for_termination.CloseHandle GetLastError () %d for (int)pHandle %d\n",
+ GetLastError (), (int)pHandle);
+ }
#elif defined (EMACS_BLOCK_SIGNAL) && !defined (BROKEN_WAIT_FOR_SIGNAL) && defined (SIGCHLD)
while (1)
{
@@ -376,7 +420,7 @@
Try defining BROKEN_WAIT_FOR_SIGNAL. */
EMACS_WAIT_FOR_SIGNAL (SIGCHLD);
}
-#else /* not HAVE_WAITPID and (not EMACS_BLOCK_SIGNAL or BROKEN_WAIT_FOR_SIGNAL) */
+#else /* not HAVE_WAITPID and not WINDOWSNT and (not EMACS_BLOCK_SIGNAL or BROKEN_WAIT_FOR_SIGNAL) */
/* This approach is kind of cheesy but is guaranteed(?!) to work
for all systems. */
while (1)
@@ -578,7 +622,11 @@
static void
sys_subshell (void)
{
+#ifdef WINDOWSNT
+ HANDLE pid;
+#else
int pid;
+#endif
struct save_signal saved_handlers[5];
Lisp_Object dir;
unsigned char *str = 0;
@@ -617,7 +665,7 @@
xyzzy:
#ifdef WINDOWSNT
- pid = -1;
+ pid = NULL;
#else /* not WINDOWSNT */
pid = fork ();
@@ -651,7 +699,7 @@
#ifdef WINDOWSNT
/* Waits for process completion */
pid = _spawnlp (_P_WAIT, sh, sh, NULL);
- if (pid == -1)
+ if (pid == NULL)
write (1, "Can't execute subshell", 22);
#else /* not WINDOWSNT */
Index: sysdep.h
===================================================================
RCS file: /usr/CVSroot/XEmacs/xemacs/src/sysdep.h,v
retrieving revision 1.11.2.1
diff -u -r1.11.2.1 sysdep.h
--- sysdep.h 1998/12/05 16:56:31 1.11.2.1
+++ sysdep.h 1999/10/25 01:00:34
@@ -48,7 +48,12 @@
/* Wait for subprocess with process id `pid' to terminate and
make sure it will get eliminated (not remain forever as a zombie) */
+#ifdef WINDOWSNT
+#include <windows.h>
+void wait_for_termination (HANDLE pid);
+#else
void wait_for_termination (int pid);
+#endif
/* flush any pending output
* (may flush input as well; it does not matter the way we use it)
cvs server: Diffing m
cvs server: Diffing s
Compilation exited abnormally with code 1 at Mon Oct 25 02:51:45