Re: MinGW open-process, take N
On Sat 16 Jul 2016 19:02, Eli Zaretskiiwrites: >> Date: Sat, 16 Jul 2016 16:24:46 +0300 >> From: Eli Zaretskii >> Cc: m...@netris.org, l...@gnu.org, guile-devel@gnu.org >> >> Is it okay to push what I have now, and remove all the tabs from >> posix-w32.c (not just those I added) in a follow-up commit? > > Never mind, I just did that. Great, thank you. Cheers, Andy
Re: MinGW open-process, take N
> Date: Sat, 16 Jul 2016 16:24:46 +0300 > From: Eli Zaretskii> Cc: m...@netris.org, l...@gnu.org, guile-devel@gnu.org > > Is it okay to push what I have now, and remove all the tabs from > posix-w32.c (not just those I added) in a follow-up commit? Never mind, I just did that. Thanks.
Re: MinGW open-process, take N
> From: Andy Wingo> Cc: m...@netris.org, l...@gnu.org, guile-devel@gnu.org > Date: Sat, 16 Jul 2016 13:32:04 +0200 > > Patch looks good to me, feel free to push after fixing tab problems and > adding the mutex. I added the mutex. Is it okay to push what I have now, and remove all the tabs from posix-w32.c (not just those I added) in a follow-up commit?
Re: MinGW open-process, take N
> From: Andy Wingo> Cc: m...@netris.org, l...@gnu.org, guile-devel@gnu.org > Date: Sat, 16 Jul 2016 13:32:04 +0200 > > On Sat 16 Jul 2016 12:54, Eli Zaretskii writes: > > > Here's the first cut. (I will rework it into git-format-patch form, > > or commit and push myself, whatever is more convenient for you, as > > soon as it is okayed for upstream.) > > Looks good to me. Thanks. > Please configure your editor to not introduce tabs though Sorry, not going to happen. That's the default GNU indentation style. > and remove tabs introduced in this patch. The file had an enormous amount of tabs before my changes and my changes added maybe 2 or 3. Does it make sense to remove only those few? > I would just use scm_i_misc_mutex in this case though. > > scm_i_scm_pthread_mutex_lock (_i_misc_mutex); > > /* do your thing */ > > scm_i_pthread_mutex_unlock (_i_misc_mutex); OK, will do. > > . Once a subprocess is launched, its record sits in the procs[] array > >until deleted by waitpid, if it finds that the process has exited, > >or by kill. If neither waitpid nor kill are called, the process's > >record will not be deleted, even though the process might be long > >dead. This means that we leak handles, and the system gets process > >objects accumulated that it cannot recycle. (This problem was > >already present in the previous version of the code, it is not new > >with the modified version.) Can we be sure that a well-behaving > >Guile program will always call one of these 2 functions? If not, > >how to prevent that in a well-behaving Guile program? I guess at > >least close-port should try killing the process (if it doesn't > >already)? Any other ideas? > > This mirrors how POSIX works AFAIU. Until you waitpid() on a child > process, the PID isn't recycled, and the process exists in a "zombie" > state. So portable Guile programs will always waitpid() on processes > they spawn. Ah, good to know. > Patch looks good to me, feel free to push after fixing tab problems and > adding the mutex. Will do, after we figure out the tricky tabs issue ;-)
Re: MinGW open-process, take N
On Sat 16 Jul 2016 12:54, Eli Zaretskiiwrites: > Here's the first cut. (I will rework it into git-format-patch form, > or commit and push myself, whatever is more convenient for you, as > soon as it is okayed for upstream.) Looks good to me. Please configure your editor to not introduce tabs though, and remove tabs introduced in this patch. > . Access to the procs[] array should be synchronized between >threads. (Currently, MinGW builds of Guile don't work at all >unless built with --disable-threads, but AFAIR Mark wanted to have >the code thread-safe anyway.) I guess this entails taking some >mutex before accessing the array, but I never wrote any such code >in Guile, so I'd appreciate to be pointed to some example, or to >have some boilerplate for that. You can either use the scm_i_misc_mutex, or define your own. If you define your own you do: static scm_i_pthread_mutex_t process_table_lock = SCM_I_PTHREAD_MUTEX_INITIALIZER; I would just use scm_i_misc_mutex in this case though. scm_i_scm_pthread_mutex_lock (_i_misc_mutex); /* do your thing */ scm_i_pthread_mutex_unlock (_i_misc_mutex); > . Once a subprocess is launched, its record sits in the procs[] array >until deleted by waitpid, if it finds that the process has exited, >or by kill. If neither waitpid nor kill are called, the process's >record will not be deleted, even though the process might be long >dead. This means that we leak handles, and the system gets process >objects accumulated that it cannot recycle. (This problem was >already present in the previous version of the code, it is not new >with the modified version.) Can we be sure that a well-behaving >Guile program will always call one of these 2 functions? If not, >how to prevent that in a well-behaving Guile program? I guess at >least close-port should try killing the process (if it doesn't >already)? Any other ideas? This mirrors how POSIX works AFAIU. Until you waitpid() on a child process, the PID isn't recycled, and the process exists in a "zombie" state. So portable Guile programs will always waitpid() on processes they spawn. Patch looks good to me, feel free to push after fixing tab problems and adding the mutex. Andy
Re: MinGW open-process, take N
> From: Andy Wingo> Cc: m...@netris.org, l...@gnu.org, guile-devel@gnu.org > Date: Thu, 14 Jul 2016 23:31:31 +0200 > > > I see your point, and I think I can fix this, together with the pid_t > > width issue in 64-bit build, if I introduce an array private to > > posix-w32.c that will hold the PIDs of all processes known to Guile > > for which waitpid did not yet return an exit code, and their > > corresponding process handles. Then we can return an int to Scheme, > > and the w32 functions will get hold of the handle by looking up the > > PID in that array. > > > > How's that sound? If you agree, I can work on this tomorrow. > > That actually sounds really nice! That way the PID-using functions will > all see proper PIDS and we also get the waitpid() behavior. > > I would be happy to apply such a patch. Thank you :-) Here's the first cut. (I will rework it into git-format-patch form, or commit and push myself, whatever is more convenient for you, as soon as it is okayed for upstream.) There are two more issues which I need help/guidance to resolve: . Access to the procs[] array should be synchronized between threads. (Currently, MinGW builds of Guile don't work at all unless built with --disable-threads, but AFAIR Mark wanted to have the code thread-safe anyway.) I guess this entails taking some mutex before accessing the array, but I never wrote any such code in Guile, so I'd appreciate to be pointed to some example, or to have some boilerplate for that. . Once a subprocess is launched, its record sits in the procs[] array until deleted by waitpid, if it finds that the process has exited, or by kill. If neither waitpid nor kill are called, the process's record will not be deleted, even though the process might be long dead. This means that we leak handles, and the system gets process objects accumulated that it cannot recycle. (This problem was already present in the previous version of the code, it is not new with the modified version.) Can we be sure that a well-behaving Guile program will always call one of these 2 functions? If not, how to prevent that in a well-behaving Guile program? I guess at least close-port should try killing the process (if it doesn't already)? Any other ideas? Thanks. Here's the patch: 2016-07-16 Eli Zaretskii * libguile/posix-w32.c (uname): Update to modern processors (ia64 and x86_64) and OS versions (Vista to Windows 10). Delete trailing whitespace. (proc_record): New structure tag. : New static variables. (find_proc, proc_handle, record_proc, delete_proc): New utility functions. (start_child): Return value is now pid_t, as it is on Posix platforms. Record the new process and returns its PID, instead of returning a handle. (waitpid, kill, getpriority, setpriority, sched_getaffinity) (sched_setaffinity): Look up the PID in the recorded subprocesses before trying to open a process that is not our subprocess. Make sure any open handle is closed before returning, unless it's our subprocess. --- libguile/posix-w32.c~2 2016-07-16 10:22:08.27325 +0300 +++ libguile/posix-w32.c2016-07-16 13:18:51.163875000 +0300 @@ -173,6 +173,80 @@ uname (struct utsname *uts) return 0; } +/* Utility functions for maintaining the list of subprocesses launched + by Guile. */ + +struct proc_record { + DWORD pid; + HANDLE handle; +}; + +static struct proc_record *procs; +static ptrdiff_t proc_size; + +/* Find the process slot that corresponds to PID. Return the index of + the slot, or -1 if not found. */ +static ptrdiff_t +find_proc (pid_t pid) +{ + ptrdiff_t found = -1, i; + + for (i = 0; i < proc_size; i++) +{ + if (procs[i].pid == pid && procs[i].handle != INVALID_HANDLE_VALUE) + found = i; +} + + return found; +} + +/* Return the process handle corresponding to its PID. If not found, + return invalid handle value. */ +static HANDLE +proc_handle (pid_t pid) +{ + ptrdiff_t idx = find_proc (pid); + + if (idx < 0) +return INVALID_HANDLE_VALUE; + return procs[idx].handle; +} + +/* Store a process record in the procs[] array. */ +static void +record_proc (pid_t proc_pid, HANDLE proc_handle) +{ + ptrdiff_t i; + + /* Find a vacant slot. */ + for (i = 0; i < proc_size; i++) +{ + if (procs[i].handle == INVALID_HANDLE_VALUE) + break; +} + + /* If no vacant slot, enlarge the array. */ + if (i == proc_size) +{ + proc_size++; + procs = scm_realloc (procs, proc_size * sizeof(procs[0])); +} + + /* Store the process data. */ + procs[i].pid = proc_pid; + procs[i].handle = proc_handle; +} + +/* Delete a process record for process PID. */ +static void +delete_proc (pid_t pid) +{ + ptrdiff_t idx = find_proc (pid); + + if (0 <= idx && idx < proc_size)
Re: MinGW open-process, take N
Greets :) On Thu 14 Jul 2016 20:41, Eli Zaretskiiwrites: >> Just that spawn_child isn't the only way to get a PID. getpid would be >> the most obvious one, but reading a PID value over a socket or whatever >> is also possible. But then your code is now introducing not-quite-PIDs >> as well. What if an interface expects one but gets the other? > > I see your point, and I think I can fix this, together with the pid_t > width issue in 64-bit build, if I introduce an array private to > posix-w32.c that will hold the PIDs of all processes known to Guile > for which waitpid did not yet return an exit code, and their > corresponding process handles. Then we can return an int to Scheme, > and the w32 functions will get hold of the handle by looking up the > PID in that array. > > How's that sound? If you agree, I can work on this tomorrow. That actually sounds really nice! That way the PID-using functions will all see proper PIDS and we also get the waitpid() behavior. I would be happy to apply such a patch. Thank you :-) Andy
Re: MinGW open-process, take N
> From: Andy Wingo> Cc: m...@netris.org, l...@gnu.org, guile-devel@gnu.org > Date: Thu, 14 Jul 2016 20:11:28 +0200 > > On Thu 14 Jul 2016 17:34, Eli Zaretskii writes: > > >> > The process ID is indeed an int, but my code hides a process handle > >> > inside it. > >> > >> If you don't mind my asking: why? :) > > > > Because that's the only way on Windows to make sure the process object > > is kept around by the kernel. Integer PIDs are reused very quickly on > > Windows, so by the time you get to scm_waitpid or some other function > > that wants to query the process, that PID might not exist, or even > > name a different process. Having a handle open on the process > > prevents the process object from being recycled. Also, _cwait, used > > by the Windows emulation of waitpid, needs a handle. > > Are you saying that Windows doesn't wait until you waitpid() on a PID to > reap it? If there's no handle open on a process, then when it exits, its object is recycled and its PID can easily be reused (on a busy system), yes. > >> The caller effectively just returns the PID to Scheme, at which > >> point it has a not-quite-PID floating around. Sounds like trouble > >> to me. > > > > Not sure why you think it's trouble. Can you explain? > > Just that spawn_child isn't the only way to get a PID. getpid would be > the most obvious one, but reading a PID value over a socket or whatever > is also possible. But then your code is now introducing not-quite-PIDs > as well. What if an interface expects one but gets the other? I see your point, and I think I can fix this, together with the pid_t width issue in 64-bit build, if I introduce an array private to posix-w32.c that will hold the PIDs of all processes known to Guile for which waitpid did not yet return an exit code, and their corresponding process handles. Then we can return an int to Scheme, and the w32 functions will get hold of the handle by looking up the PID in that array. How's that sound? If you agree, I can work on this tomorrow.
Re: MinGW open-process, take N
On Thu 14 Jul 2016 17:34, Eli Zaretskiiwrites: >> > The process ID is indeed an int, but my code hides a process handle >> > inside it. >> >> If you don't mind my asking: why? :) > > Because that's the only way on Windows to make sure the process object > is kept around by the kernel. Integer PIDs are reused very quickly on > Windows, so by the time you get to scm_waitpid or some other function > that wants to query the process, that PID might not exist, or even > name a different process. Having a handle open on the process > prevents the process object from being recycled. Also, _cwait, used > by the Windows emulation of waitpid, needs a handle. Are you saying that Windows doesn't wait until you waitpid() on a PID to reap it? >> The caller effectively just returns the PID to Scheme, at which >> point it has a not-quite-PID floating around. Sounds like trouble >> to me. > > Not sure why you think it's trouble. Can you explain? Just that spawn_child isn't the only way to get a PID. getpid would be the most obvious one, but reading a PID value over a socket or whatever is also possible. But then your code is now introducing not-quite-PIDs as well. What if an interface expects one but gets the other? Andy
Re: MinGW open-process, take N
> From: Andy Wingo> Cc: m...@netris.org, l...@gnu.org, guile-devel@gnu.org > Date: Thu, 14 Jul 2016 12:20:09 +0200 > > On Tue 12 Jul 2016 16:46, Eli Zaretskii writes: > > >> But in reality the getuid is of this form: > >> > >> (define (load-user-init) > >> (let* ((home (or (getenv "HOME") > >> (false-if-exception (passwd:dir (getpwuid (getuid > >> file-name-separator-string)) ;; fallback for cygwin > >> etc. > >>(init-file (in-vicinity home ".guile"))) > >> (if (file-exists? init-file) > >> (primitive-load init-file > >> > >> So, no problem. > > > > Won't this fail to compile during boot, or at least produce a warning? > > It will produce a warning at compile-time, yes, but no problem at > run-time because of the false-if-exception block. Sigh. > > The process ID is indeed an int, but my code hides a process handle > > inside it. > > If you don't mind my asking: why? :) Because that's the only way on Windows to make sure the process object is kept around by the kernel. Integer PIDs are reused very quickly on Windows, so by the time you get to scm_waitpid or some other function that wants to query the process, that PID might not exist, or even name a different process. Having a handle open on the process prevents the process object from being recycled. Also, _cwait, used by the Windows emulation of waitpid, needs a handle. > The caller effectively just returns the PID to Scheme, at which > point it has a not-quite-PID floating around. Sounds like trouble > to me. Not sure why you think it's trouble. Can you explain?
Re: MinGW open-process, take N
On Tue 12 Jul 2016 16:46, Eli Zaretskiiwrites: >> But in reality the getuid is of this form: >> >> (define (load-user-init) >> (let* ((home (or (getenv "HOME") >> (false-if-exception (passwd:dir (getpwuid (getuid >> file-name-separator-string)) ;; fallback for cygwin >> etc. >>(init-file (in-vicinity home ".guile"))) >> (if (file-exists? init-file) >> (primitive-load init-file >> >> So, no problem. > > Won't this fail to compile during boot, or at least produce a warning? It will produce a warning at compile-time, yes, but no problem at run-time because of the false-if-exception block. >> Hu, I don't know, there are a number of other things in that file >> which treat PIDs as ints (scm_waitpid, scm_getppid, etc etc etc). I >> think that would need to be another patch that adds scm_from_pid_t and >> scm_to_pid_t and so on. And then what is this? >> >> http://permalink.gmane.org/gmane.comp.gnu.mingw.w64.general/12235 > > The process ID is indeed an int, but my code hides a process handle > inside it. If you don't mind my asking: why? :) The caller effectively just returns the PID to Scheme, at which point it has a not-quite-PID floating around. Sounds like trouble to me. Andy
Re: MinGW open-process, take N
> From: Andy Wingo> Cc: guile-devel@gnu.org, l...@gnu.org, m...@netris.org > Date: Tue, 12 Jul 2016 16:05:35 +0200 > > > It's hard for me to build Guile from Git, due to the additional > > prerequisites that needs. > > Understood, in that case please note that there is also an automatic > build service that runs "make" and "make dist" to make tarballs: > > https://hydra.nixos.org/job/gnu/guile-2-0/tarball > > Just click through and you can download a tarball. For example: > > > https://hydra.nixos.org/build/37557639/download/3/guile-2.0.11.238-e1cb7.tar.gz > > There is .xz too. This service exists for Guile master too: > > https://hydra.nixos.org/job/gnu/guile-master/tarball Thanks, I will try that when I have time, if Guile is not released before that. > getuid is used in boot-9.scm, so if it's unavailable, we cannot build > Guile without making changes in the Scheme code. I don't know if that > convinces you, and I have no practical way of counting their uses in > Guile programs outside Guile itself. > > But in reality the getuid is of this form: > > (define (load-user-init) > (let* ((home (or (getenv "HOME") > (false-if-exception (passwd:dir (getpwuid (getuid > file-name-separator-string)) ;; fallback for cygwin etc. >(init-file (in-vicinity home ".guile"))) > (if (file-exists? init-file) > (primitive-load init-file > > So, no problem. Won't this fail to compile during boot, or at least produce a warning? > > The only other issue I see is the type of the value returned by > > start_child, and as result by scm_open_process. On Windows, the value > > returned has the type HANDLE, which is actually a pointer in disguise. > > I used intptr_t for that, but you changed it to just int. This will > > not work in 64-bit MinGW builds, where a pointer is a 64-bit type. I > > think we should go back to intptr_t, and also change the conversion to > > the value returned by scm_open_process, since scm_from_int will AFAIK > > not support 64-bit integer types. Note that the MinGW waitpid > > implementation also expects to get a valu that is interpreted as a > > handle. > > Hu, I don't know, there are a number of other things in that file > which treat PIDs as ints (scm_waitpid, scm_getppid, etc etc etc). I > think that would need to be another patch that adds scm_from_pid_t and > scm_to_pid_t and so on. And then what is this? > > http://permalink.gmane.org/gmane.comp.gnu.mingw.w64.general/12235 The process ID is indeed an int, but my code hides a process handle inside it. > I will apply your patch though and I look forward to hearing if it works > for you :) The above is not a problem for me, since I use the 32-bit MinGW, where a handle is a 32-bit type. This is only a potential problem in 64-bit builds. Thanks.
Re: MinGW open-process, take N
Greets, On Tue 12 Jul 2016 15:02, Eli Zaretskiiwrites: > It's hard for me to build Guile from Git, due to the additional > prerequisites that needs. Understood, in that case please note that there is also an automatic build service that runs "make" and "make dist" to make tarballs: https://hydra.nixos.org/job/gnu/guile-2-0/tarball Just click through and you can download a tarball. For example: https://hydra.nixos.org/build/37557639/download/3/guile-2.0.11.238-e1cb7.tar.gz There is .xz too. This service exists for Guile master too: https://hydra.nixos.org/job/gnu/guile-master/tarball > First, I see that you also removed getuid and getgid; I believe we > only talked about removing setuid and setgid. As I said, getuid is > needed to build Guile. Hmm, I don't think getuid is needed to build Guile. Your message from Tuesday said: getuid is used in boot-9.scm, so if it's unavailable, we cannot build Guile without making changes in the Scheme code. I don't know if that convinces you, and I have no practical way of counting their uses in Guile programs outside Guile itself. But in reality the getuid is of this form: (define (load-user-init) (let* ((home (or (getenv "HOME") (false-if-exception (passwd:dir (getpwuid (getuid file-name-separator-string)) ;; fallback for cygwin etc. (init-file (in-vicinity home ".guile"))) (if (file-exists? init-file) (primitive-load init-file So, no problem. I would be happy to look at another patch that adds them if it turns out that you need them (and sets HAVE_GETUID etc). But, I don't think that leaving them out will hurt anything. > The only other issue I see is the type of the value returned by > start_child, and as result by scm_open_process. On Windows, the value > returned has the type HANDLE, which is actually a pointer in disguise. > I used intptr_t for that, but you changed it to just int. This will > not work in 64-bit MinGW builds, where a pointer is a 64-bit type. I > think we should go back to intptr_t, and also change the conversion to > the value returned by scm_open_process, since scm_from_int will AFAIK > not support 64-bit integer types. Note that the MinGW waitpid > implementation also expects to get a valu that is interpreted as a > handle. Hu, I don't know, there are a number of other things in that file which treat PIDs as ints (scm_waitpid, scm_getppid, etc etc etc). I think that would need to be another patch that adds scm_from_pid_t and scm_to_pid_t and so on. And then what is this? http://permalink.gmane.org/gmane.comp.gnu.mingw.w64.general/12235 We also have some unrelated problems on MinGW64 due to the 32-bit longs there. I will apply your patch though and I look forward to hearing if it works for you :) Andy
MinGW open-process, take N
Hi Eli, I have reworked Guile a bit in anticipation of your patch and in the end reworked your patch a bit too. Please fetch git and see how things are working for you, first -- it could be I introduced a MinGW bug. Then here attached is your patch, reworked. Let me know how it looks to you. If it looks good I'll apply and release in 2.0.12 tomorrow or so. Regards, Andy >From 0ffd406b582dea54ff080f1785eea25a1199c5df Mon Sep 17 00:00:00 2001 From: Eli ZaretskiiDate: Mon, 11 Jul 2016 22:52:17 +0200 Subject: [PATCH] Add POSIX shims for MinGW * libguile/posix-w32.h: * libguile/posix-w32.c (kill, waitpid, getpriority, setpriority) (sched_getaffinity, sched_setaffinity): Add MinGW implementations. Also, provides macros that on Posix hosts are in sys/wait.h, like WIFEXITED and WTERMSIG. (start_child): Add implementation. --- libguile/posix-w32.c | 864 ++- libguile/posix-w32.h | 48 ++- libguile/posix.c | 3 +- 3 files changed, 912 insertions(+), 3 deletions(-) diff --git a/libguile/posix-w32.c b/libguile/posix-w32.c index f1251b2..f7df180 100644 --- a/libguile/posix-w32.c +++ b/libguile/posix-w32.c @@ -1,4 +1,4 @@ -/* Copyright (C) 2001, 2006, 2008 Free Software Foundation, Inc. +/* Copyright (C) 2001, 2006, 2008, 2016 Free Software Foundation, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License @@ -22,8 +22,12 @@ #include "libguile/__scm.h" +# define WIN32_LEAN_AND_MEAN #include +#include +#include #include +#include #include #include "posix-w32.h" @@ -144,3 +148,861 @@ uname (struct utsname *uts) GetComputerName (uts->nodename, ); return 0; } + +/* Run a child process with redirected standard handles, without + redirecting standard handles of the parent. This is required in + multithreaded programs, where redirecting a standard handle affects + all threads. */ + +/* Prepare a possibly redirected file handle to be passed to a child + process. The handle is for the file/device open on file descriptor + FD; if FD is invalid, use the null device instead. + + USE_STD non-zero means we have been passed the descriptor used by + the parent. + + ACCESS is the Windows access mode for opening the null device. + + Returns the Win32 handle to be passed to CreateProcess. */ +static HANDLE +prepare_child_handle (int fd, int use_std, DWORD access) +{ + HANDLE htem, hret; + DWORD err = 0; + + /* Start with the descriptor, if specified by the caller and valid, + otherwise open the null device. */ + if (fd < 0) +htem = INVALID_HANDLE_VALUE; + else +htem = (HANDLE)_get_osfhandle (fd); + + /* Duplicate the handle and make it inheritable. */ + if (DuplicateHandle (GetCurrentProcess (), + htem, + GetCurrentProcess (), + , + 0, + TRUE, + DUPLICATE_SAME_ACCESS) == FALSE) +{ + /* If the original standard handle was invalid (happens, e.g., +in GUI programs), open the null device instead. */ + if ((err = GetLastError ()) == ERROR_INVALID_HANDLE + && use_std) + { + htem = CreateFile ("NUL", access, +FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, +OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); + if (htem != INVALID_HANDLE_VALUE + && DuplicateHandle (GetCurrentProcess (), + htem, + GetCurrentProcess (), + , + 0, + TRUE, + DUPLICATE_SAME_ACCESS) == FALSE) + { + err = GetLastError (); + CloseHandle (htem); + hret = INVALID_HANDLE_VALUE; + } + } +} + + if (hret == INVALID_HANDLE_VALUE) +{ + switch (err) + { + case ERROR_NO_MORE_FILES: + errno = EMFILE; + break; + case ERROR_INVALID_HANDLE: + default: + errno = EBADF; + break; + } +} + + return hret; +} + +/* A comparison function for sorting the environment. */ +static int +compenv (const void *a1, const void *a2) +{ + return stricmp (*((char**)a1), *((char**)a2)); +} + +/* Convert the program's 'environ' array to a block of environment + variables suitable to be passed to CreateProcess. This is needed + to ensure the child process inherits the up-to-date environment of + the parent, including any variables inserted by the parent. */ +static void +prepare_envblk (char **envp, char **envblk) +{ + char **tmp; + int size_needed; + int envcnt; + char *ptr; + + for (envcnt = 0; envp[envcnt]; envcnt++) +; + + tmp = scm_calloc ((envcnt + 1) * sizeof