Re: MinGW open-process, take N

2016-07-23 Thread Andy Wingo
On Sat 16 Jul 2016 19:02, Eli Zaretskii  writes:

>> 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

2016-07-16 Thread Eli Zaretskii
> 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

2016-07-16 Thread Eli Zaretskii
> 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

2016-07-16 Thread Eli Zaretskii
> 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

2016-07-16 Thread Andy Wingo
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.  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

2016-07-16 Thread Eli Zaretskii
> 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

2016-07-14 Thread Andy Wingo
Greets :)

On Thu 14 Jul 2016 20:41, Eli Zaretskii  writes:

>> 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

2016-07-14 Thread Eli Zaretskii
> 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

2016-07-14 Thread Andy Wingo
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?

>> 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

2016-07-14 Thread Eli Zaretskii
> 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

2016-07-14 Thread Andy Wingo
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.

>> 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

2016-07-12 Thread Eli Zaretskii
> 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

2016-07-12 Thread Andy Wingo
Greets,

On Tue 12 Jul 2016 15:02, Eli Zaretskii  writes:

> 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

2016-07-11 Thread Andy Wingo
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 Zaretskii 
Date: 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