X-Recipient: archive-cygwin AT delorie DOT com X-SWARE-Spam-Status: No, hits=-2.0 required=5.0 tests=AWL,BAYES_00,DKIM_SIGNED,DKIM_VALID,RCVD_IN_DNSWL_LOW X-Spam-Check-By: sourceware.org Message-ID: <4DD4AEB4.2090008@cwilson.fastmail.fm> Date: Thu, 19 May 2011 01:46:28 -0400 From: Charles Wilson User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.8.1.23) Gecko/20090812 Thunderbird/2.0.0.23 Mnenhy/0.7.6.666 MIME-Version: 1.0 To: Cygwin Mailing List Subject: Re: Process Execution from Cygwin Shells References: In-Reply-To: Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT cygwin DOT com Mail-Followup-To: cygwin AT cygwin DOT com Delivered-To: mailing list cygwin AT cygwin DOT com 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' model: 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" _exit(127); // *really* not reached! case -1: // parent, but fork call failed // handle error... break; default: // parent...do stuff. Usually want to wait() on the // child, or otherwise allow it to detach. Otherwise it // will become a zombie. etc...etc... } // 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. -- Chuck -- Problem reports: http://cygwin.com/problems.html FAQ: http://cygwin.com/faq/ Documentation: http://cygwin.com/docs.html Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple