Mailing-List: contact cygwin-help AT cygwin DOT com; run by ezmlm 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 X-Injected-Via-Gmane: http://gmane.org/ To: cygwin AT cygwin DOT com From: Sam Steingold Subject: subprocess i/o interaction with shell (bash&cmd): shells compete for input with user program! Date: 22 Jul 2003 10:30:52 -0400 Organization: disorganization Lines: 210 Message-ID: Reply-To: sds AT gnu DOT org Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Complaints-To: usenet AT main DOT gmane DOT org X-Attribution: Sam X-Disclaimer: You should not expect anyone to agree with me. User-Agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.3.50 Cc: mingw-users AT lists DOT sourceforge DOT net I have a driver.exe program which calls runtime.exe. runtime.exe is an interactive console application, i.e., it will be doing i/o via the stdio. If I make driver.exe exit before runtime.exe, the console interaction is severely broken (both under bash and cmd, both when compiled with and without cygwin) E.g.: =================== start driver.c ============================== #include #include #include #include int main (int argc, char *argv[]) { PROCESS_INFORMATION pi; STARTUPINFO si; si.cb = sizeof(STARTUPINFO); si.lpReserved = NULL; si.lpDesktop = NULL; si.lpTitle = NULL; si.cbReserved2 = 0; si.lpReserved2 = NULL; si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = GetStdHandle(STD_INPUT_HANDLE); if (si.hStdInput == INVALID_HANDLE_VALUE) goto w32err; si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); if (si.hStdOutput == INVALID_HANDLE_VALUE) goto w32err; si.hStdError = GetStdHandle(STD_ERROR_HANDLE); if (si.hStdError == INVALID_HANDLE_VALUE) goto w32err; printf(" * start (%d) %s\n",argc,argv[0]); if (!CreateProcess("runtime.exe","runtime.exe",NULL,NULL,1,0, NULL,NULL,&si,&pi)) goto w32err; if (argc>1) WaitForSingleObject(pi.hProcess,INFINITE); printf(" * finish %s\n",argv[0]); return 0; w32err: fprintf(stderr," * error %s: %s\n",argv[0],strerror(GetLastError())); return 1; } =================== end driver.c ============================== =================== start runtime.c ============================== #include #include #include int main (int argc, char *argv[]) { char buf[BUFSIZ]; printf(" * start (%d) %s\n",argc,argv[0]); gets(buf); printf(" * you entered: [%s]\n",buf); printf(" * finish %s\n",argv[0]); return 0; } =================== end runtime.c ============================== I compile them with gcc -mno-cygwin -g -W -Wall -Wstrict-prototypes -Wshadow driver.c -o driver gcc -mno-cygwin -g -W -Wall -Wstrict-prototypes -Wshadow runtime.c -o runtime When I give the driver an argument so that it will wait for runtime to finish, I get what one would expect, both under bash and cmd: ================================ start bash interaction =========== bash$ ./driver.exe wait * start (2) d:\sds\c\driver.exe * start (1) runtime.exe qwert * you entered: [qwert] * finish runtime.exe * finish d:\sds\c\driver.exe bash$ ================================ end bash interaction =========== ================================ start cmd interaction =========== D:\sds\c>driver wait * start (2) driver * start (1) runtime.exe qwert * you entered: [qwert] * finish runtime.exe * finish driver D:\sds\c> ================================ end cmd interaction =========== now, if I do not give the `wait' argument to the driver, I get something quite unexpected under cmd: ================================ start cmd interaction =========== D:\sds\c>driver * start (1) driver * finish driver D:\sds\c> * start (1) runtime.exe qwer 'qwer' is not recognized as an internal or external command, operable program or batch file. D:\sds\c>asdf * you entered: [asdf] * finish runtime.exe ================================ end cmd interaction =========== i.e., I get the cmd prompt right after driver exits and the first thing I input is caught by cmd (and the second line goes to runtime). ================================ start bash interaction =========== bash$ ./driver.exe * start (1) d:\sds\c\driver.exe * finish d:\sds\c\driver.exe bash$ * start (1) runtime.exe defxctutirfefe bash: defxctutirfefe: command not found bash$ 3sssssd bash: 3sssssd: command not found bash$ bash$ p4khdsf bash: p4khdsf: command not found bash$ ^C bash$ ================================ end bash interaction =========== i.e., I get the bash prompt right after driver exits, BUT the input becomes weird: only about a quarter of the characters I type are echoed to the screen (the `3sssssd' string was generated by me repeatedly typing "asdasdfasdfadfasdfadsf") and the only way out is Ctrl-C (then everything is restored to normal, but I never see the finishing messages from runtime.exe). Ironically, if I compile them with cygwin: gcc -g -W -Wall -Wstrict-prototypes -Wshadow driver.c -o driver gcc -g -W -Wall -Wstrict-prototypes -Wshadow runtime.c -o runtime the results are identical on bash and cmd and somewhat in between the mingw behavior (i.e., bash is better and cmd is worse): ================================ start bash interaction =========== bash$ ./driver.exe * start (1) ./driver * finish ./driver bash$ * start (1) runtime sfgggdfrg bash: sfggdrg: command not found bash$ rwr bash: rwr: command not found bash$ bash$ bash$ bash$ bash$ bash$ bash$ bash$ bash$ bash$ bash$ 54 bash: 5: command not found bash$ 5676 * you entered: [gf4676] * finish runtime bash: 5: command not found bash$ bash$ ================================ end bash interaction =========== ================================ start cmd interaction =========== D:\sds\c>driver * start (1) driver * finish driver D:\sds\c> * start (1) runtime qdf 'qdf' is not recognized as an internal or external command, operable program or batch file. D:\sds\c>er 'r' is not recognized as an internal or external command, operable program or batch file. D:\sds\c>qerq4 'erq4' is not recognized as an internal or external command, operable program or batch file. D:\sds\c> * you entered: [eq] * finish runtime D:\sds\c> D:\sds\c> ================================ end cmd interaction =========== i.e., as you can see, the shells compete with runtime for input! using cygwin exec() family does not change much (I still get the bash/cmd prompt before runtime starts). So, how can I exit driver and have the shell notice that its child (driver) left a heir (runtime) and that the shell (bash & cmd) should wait for runtime to finish. -- Sam Steingold (http://www.podval.org/~sds) running w2k The difference between theory and practice is that in theory there isn't any. -- Unsubscribe info: http://cygwin.com/ml/#unsubscribe-simple Problem reports: http://cygwin.com/problems.html Documentation: http://cygwin.com/docs.html FAQ: http://cygwin.com/faq/