Process Execution from Cygwin Shells

Charles Wilson
Thu May 19 05:47:00 GMT 2011

On 5/19/2011 12:58 AM, Sravan Bhamidipati wrote:
> Steps to reproduce:
> 1. Open "Process Monitor" and filter for events of type "Operation"
> and value "Process Create".
> 2. Open a Cygwin shell (using cygwin.bat or mintty or rxvt): bash or ksh, e.g.
> 3. Type any command that is not a shell built-in, say "clear" or "cmd".
> 4. Notice that "Process Monitor" captured two process creation events
> related to the invoked command: a new child shell and another of the
> invoked command.
> 5. Open the command prompt, cd to $CYGWIN\bin, and type the same
> command (a Cygwin command that can be executed directly from cmd will
> also do).
> 6. Notice that "Process Monitor" captured only one process creation
> event: of the invoked command.
> This seems very strange to me. The behavior applies even when
> executing a Shell script. I noticed identical behavior when using
> MinGW Shell as well. Shells in Unix-based OSs don't behave this way.
> Why is this happening? Can something be done about it?

Process creation on unix is different than on Windows.  However, cygwin
has to emulate the unix behavior using the Windows mechanisms.

On unix, the typical way to execute another program is the 'fork/exec'

fork() is a system call that on unix, creates a new process that is a
CLONE of the process that called it.  The only difference is, fork()
returns 0 in the copy (the 'child'), and returns the process ID of the
child, in the original (the 'parent').

Typically, then the child will call 'exec()', which "replaces" the
current program running in the (child) process with the designated
program in the exec call.

That is:

   int pid = fork();
   switch (pid)
   case 0:
      // this is the child
      // do some prep work, and then...
      exec("/some/other/program", ...);

      // not reached, but by convention error code 127
      // means "couldn't exec a child program"

      // *really* not reached!

   case -1:
      // parent, but fork call failed
      // handle error...
      // stuff.  Usually want to wait() on the
      // child, or otherwise allow it to detach. Otherwise it
      // will become a zombie.
   // more parent code continues here.

Now, how does cygwin emulate this behavior, using CreateProcess -- for
instance, if the current process is /bin/bash.exe?  Schematically, it
looks like:

fork() == CreateProcess("C:\cygwin\bin\bash.exe", ...)
   but with lots of special care taken to make it work "just right".
Handles have to be duplicated, the memory map needs to be adjusted so it
is *IDENTICAL* in both the parent and child copies, there's lots of
synchronization going on.  This is one of the hairiest, scariest parts
of the cygwin1.dll.

So, at this point, you have TWO bash processes...but one is just about
to call 'exec' -- and the other will go back to whatever the parent is
supposed to be doing.

exec() == another CreateProcess, only this time as
CreateProcess("C:\cygwin\bin\other-prog.exe", ...).  But once again,
there's lots of gory stuff that needs to happen.  The Process ID of THIS
one needs to be the same as the "child" copy of bash, but that's tricky
because you've got to manage the 'handoff' of that $pid or you'll have
two processes with the same id.  Also, all the inheritable handles,
stdout, stdin, etc, need to be handed over.

Eventually, THIS process, the "real" child, will notify the "original"
child that everything is ok, and then the "original" child can exit --
but the "original" child does so in a special way because we don't want
the "parent" to think the child actually died, since the "real" child is
going to take over the role.

Now, if that sounds complicated -- it isn't.  That is a HIGHLY
simplified view of the process, and I've skipped over a lot of really
tricky bits and corner cases/exceptions/errorhandling that goes on.
Like the wait() issue, and handling the SIGCLD / SIGCHLD signals which
is a whole 'nother scary minefield.

Now, if you just call a cygwin program from inside a DOS cmd.exe prompt,
obviously none of this happens.  cmd.exe calls
CreateProcess("C:\cygwin\bin\cygwin-prog.exe", ...) and that's pretty
much it.


Problem reports:
Unsubscribe info:

More information about the Cygwin mailing list