From c3b7d57d0785dfe48ec7f31c34571fc7c3d39a0a Mon Sep 17 00:00:00 2001 From: sof Date: Fri, 22 Apr 2005 17:15:51 +0000 Subject: [PATCH] [project @ 2005-04-22 17:15:51 by sof] Switch away from using _spawnv() to CreateProcess(); the former has the annoying 'feature' that it quits upon Ctrl-C, leaving its child in the background. Use CreateProcess() instead and avoid the Ctrl-C issue by having the wrapper let go of its console before waiting for the sub-process running GHCi to exit. This still doesn't fix the issue of Ctrl-C handling when the 'ghci' wrapper is invoked from a cygwin-based bash. cmd.exe users will hopefully see an improvement in behaviour though. Merge to STABLE. --- ghc/driver/ghci/ghci.c | 152 +++++++++++++++++++++++++----------------------- 1 file changed, 80 insertions(+), 72 deletions(-) diff --git a/ghc/driver/ghci/ghci.c b/ghc/driver/ghci/ghci.c index c0e3991..a41723a 100644 --- a/ghc/driver/ghci/ghci.c +++ b/ghc/driver/ghci/ghci.c @@ -1,6 +1,6 @@ /* * - * $Id: ghci.c,v 1.8 2003/06/12 09:48:17 simonpj Exp $ + * $Id: ghci.c,v 1.9 2005/04/22 17:15:51 sof Exp $ * * ghci wrapper for Win32 only * @@ -44,11 +44,14 @@ #include #include #include +#include +#include #define BINARY_NAME "ghc.exe" #define IACTIVE_OPTION "--interactive" #define errmsg(msg) fprintf(stderr, msg "\n"); fflush(stderr) +#define errmsg1(msg,val) fprintf(stderr, msg "\n",val); fflush(stderr) int main(int argc, char** argv) @@ -56,21 +59,28 @@ main(int argc, char** argv) TCHAR binPath[FILENAME_MAX+1]; TCHAR binPathShort[MAX_PATH+1]; DWORD dwSize = FILENAME_MAX; - DWORD dwRes; TCHAR* szEnd; - char** new_argv; int i; + char* new_cmdline; + char *ptr, *src; + unsigned int cmdline_len = 0; + char **pp; + LPTSTR pp1; + + STARTUPINFO si; + PROCESS_INFORMATION pi; + ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); + ZeroMemory(&si, sizeof(STARTUPINFO)); + si.cb = sizeof(STARTUPINFO); + /* Locate the binary we want to start up */ - dwRes = - SearchPath(NULL, - BINARY_NAME, - NULL, - dwSize, - (char*)binPath, - &szEnd); - - if (dwRes == 0) { + if ( !SearchPath(NULL, + BINARY_NAME, + NULL, + dwSize, + (char*)binPath, + &szEnd) ) { errmsg("Unable to locate ghc.exe"); return 1; } @@ -83,72 +93,70 @@ main(int argc, char** argv) return 1; } - new_argv = (char**)malloc(sizeof(char*) * (argc + 1 + 1)); - if (new_argv == NULL) { - errmsg("failed to start up ghc.exe"); - return 1; + /* Compute length of the flattened 'argv', including extra IACTIVE_OPTION (and spaces!) */ + cmdline_len += 1 + strlen(IACTIVE_OPTION); + for(i=1;i Just use spawnv(), which is provided by msvcrt.dll, the - Microsoft C runtime to which mingw delegates almost all - system calls - - [Sigbjorn adds 12 Jun 03] - We probably ought to use CreateProcess() in ghci.c -- or better still an exec()-like - that didn't have to create a separate process from the wrapper (which is what that - code comment in there is driving at.) - - CreateProcess() is a more wieldy function to invoke, which is probably why - I opted for spawnv(). spawnv() performs the equivalent of Prelude.unwords - (to look at the code itself, or at least an older version, see dospawn.c in the - vc98/crt/src/ directory of an MSVC6 installation.) - - CreateProcess() is a native Win32 API though, which has the merit that it is - guaranteed to work the same with both the mingw and cygwin ports. + Irrespective of this issue, using CreateProcess() is preferable, + as it makes this wrapper work on both mingw and cygwin. */ #if 0 - fprintf(stderr, "Invoking ghc: "); - i=0; - while (new_argv[i] != NULL) { - fprintf(stderr, "%s ", new_argv[i++]); - } - fprintf(stderr, "\n"); fflush(stderr); + fprintf(stderr, "Invoking ghc: %s %s\n", binPathShort, new_cmdline); fflush(stderr); #endif - return _spawnv(_P_WAIT, binPath, new_argv); + if (!CreateProcess(binPathShort, + new_cmdline, + NULL, + NULL, + TRUE, + 0, /* dwCreationFlags */ + NULL, /* lpEnvironment */ + NULL, /* lpCurrentDirectory */ + &si, /* lpStartupInfo */ + &pi) ) { + errmsg1("Unable to start ghc.exe (error code: %lu)", GetLastError()); + return 1; + } + /* Disable handling of console events in the parent by dropping its + * connection to the console. This has the (minor) downside of not being + * able to subsequently emit any error messages to the console. + */ + FreeConsole(); + + switch (WaitForSingleObject(pi.hProcess, INFINITE) ) { + case WAIT_OBJECT_0: + return 0; + case WAIT_ABANDONED: + case WAIT_FAILED: + /* in the event we get any hard errors, bring the child to a halt. */ + TerminateProcess(pi.hProcess,1); + return 1; + default: + return 1; + } } -- 1.7.10.4