diff options
Diffstat (limited to 'funtools/util/winprocess.c')
-rw-r--r-- | funtools/util/winprocess.c | 317 |
1 files changed, 317 insertions, 0 deletions
diff --git a/funtools/util/winprocess.c b/funtools/util/winprocess.c new file mode 100644 index 0000000..70839dc --- /dev/null +++ b/funtools/util/winprocess.c @@ -0,0 +1,317 @@ +/* + * Copyright (c) 2009 Smithsonian Astrophysical Observatory + */ + +/* + * + * winprocess.c -- routines to start up and communicate with a slave process + * + * this is the windows version, see zprocess.c for original code + * + */ + +#include <winprocess.h> + +#if defined(HAVE_CYGWIN) || defined(WIN32) + +#include <windows.h> + +#ifndef min +#define min(a,b) (((a)<(b))?(a):(b)) +#endif + +/* + * + * Private Routines + * + * + */ + +#define MAXPROCS 512 + +typedef struct wproctable { + HANDLE hIchan; + HANDLE hOchan; + HANDLE hProcess; +} WPROC; + + +static WPROC wprtable[MAXPROCS]; + +/* WPR_FINDPROCESS -- Search the process table for a process */ +static WPROC *wpr_findprocess(HANDLE process) +{ + register int wpr; + for(wpr=0; wpr<MAXPROCS; wpr++){ + if(wprtable[wpr].hProcess == process){ + return (&wprtable[wpr]); + } + } + return (NULL); +} + +/* WPR_ENTER -- Make a new entry in the process table. */ +static int wpr_enter(HANDLE process, HANDLE ichan, HANDLE ochan) +{ + register int wpr; + + for(wpr=0; wpr<MAXPROCS; wpr++){ + if(wprtable[wpr].hProcess == 0){ + wprtable[wpr].hProcess = process; + wprtable[wpr].hIchan = ichan; + wprtable[wpr].hOchan = ochan; + return(1); + } + } + return(0); +} + +/* WPR_GETCHAN -- Get the codes for the IPC channels assigned to a process */ +static HANDLE wpr_getchan (HANDLE process, HANDLE *ichan, HANDLE *ochan) +{ + register WPROC *wpr; + + /* Lookup process in table. Return an error if there is no entry */ + if ((wpr = wpr_findprocess(process)) == NULL){ + return(NULL); + } + else{ + *ichan = wpr->hIchan; + *ochan = wpr->hOchan; + return (process); + } +} + +/* WPR_RELEASE -- Release the table entry for the process. Used when a process + * is killed and we do not wish to wait for process termination */ +static void wpr_release (HANDLE process) +{ + register WPROC *wpr; + + if ((wpr = wpr_findprocess (process)) != NULL){ + wpr->hProcess = 0; + wpr->hIchan = 0; + wpr->hOchan = 0; + } +} + +/* + * + * Public Routines + * + * + */ + +int WinProcessOpen(char *cmd, HANDLE *ichan, HANDLE *ochan, HANDLE *process) +{ + HANDLE g_hChildStd_IN_Rd = NULL; + HANDLE g_hChildStd_IN_Wr = NULL; + HANDLE g_hChildStd_OUT_Rd = NULL; + HANDLE g_hChildStd_OUT_Wr = NULL; + + SECURITY_ATTRIBUTES saAttr; + PROCESS_INFORMATION piProcInfo; + STARTUPINFO siStartInfo; + BOOL bSuccess = FALSE; + + // Set the bInheritHandle flag so pipe handles are inherited. + saAttr.nLength = sizeof(SECURITY_ATTRIBUTES); + saAttr.bInheritHandle = TRUE; + saAttr.lpSecurityDescriptor = NULL; + + // Create a pipe for the child process's STDOUT. + if ( !CreatePipe(&g_hChildStd_OUT_Rd, &g_hChildStd_OUT_Wr, &saAttr, 0) ) + return 0; + + // Ensure the read handle to the pipe for STDOUT is not inherited. + if ( !SetHandleInformation(g_hChildStd_OUT_Rd, HANDLE_FLAG_INHERIT, 0) ) + return 0; + + // Create a pipe for the child process's STDIN. + if (!CreatePipe(&g_hChildStd_IN_Rd, &g_hChildStd_IN_Wr, &saAttr, 0)) + return 0; + + // Ensure the write handle to the pipe for STDIN is not inherited. + if ( !SetHandleInformation(g_hChildStd_IN_Wr, HANDLE_FLAG_INHERIT, 0) ) + return 0; + + // Set up members of the PROCESS_INFORMATION structure. + ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) ); + + // Set up members of the STARTUPINFO structure. + // This structure specifies the STDIN and STDOUT handles for redirection. + ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) ); + siStartInfo.cb = sizeof(STARTUPINFO); + siStartInfo.hStdError = g_hChildStd_OUT_Wr; + siStartInfo.hStdOutput = g_hChildStd_OUT_Wr; + siStartInfo.hStdInput = g_hChildStd_IN_Rd; + siStartInfo.dwFlags |= STARTF_USESTDHANDLES; + + // Create the child process. + bSuccess = CreateProcess(NULL, + cmd, // command line + NULL, // process security attributes + NULL, // primary thread security attributes + TRUE, // handles are inherited + 0, // creation flags + NULL, // use parent's environment + NULL, // use parent's current directory + &siStartInfo, // STARTUPINFO pointer + &piProcInfo); // receives PROCESS_INFORMATION + + // check for errors and configure return values + if( bSuccess ) { + /* save process info for later */ + wpr_enter (piProcInfo.hProcess, g_hChildStd_OUT_Rd, g_hChildStd_OUT_Rd); + // Close handles to the child process and its primary thread. + // Some applications might keep these handles to monitor the status + // of the child process, for example. + // CloseHandle(piProcInfo.hProcess); + CloseHandle(piProcInfo.hThread); + // close unused sides of the pipe + CloseHandle(g_hChildStd_OUT_Wr); + CloseHandle(g_hChildStd_IN_Rd); + /* package up process info for return */ + *ichan = (void *)g_hChildStd_OUT_Rd; + *ochan = (void *)g_hChildStd_IN_Wr; + *process = (void *)piProcInfo.hProcess; + /* success */ + return 1; + } else { + /* failure */ + *ichan = NULL; + *ochan = NULL; + *process = NULL; + return 0; + } +} + +/* + * + * WinProcessClose -- Close a connected subprocess + * + */ +int WinProcessClose(void *vprocess, int *exit_status) +{ + HANDLE ichan, ochan; + HANDLE process = (HANDLE)vprocess; + + + *exit_status = 0; + if( wpr_getchan(process, &ichan, &ochan) != NULL ){ + CloseHandle(ochan); + CloseHandle(ichan); + CloseHandle(process); + wpr_release(process); + } + return(*exit_status); +} + + +/* + * + * WinProcessRead -- Read next record from an IPC channel. + * + * Since UNIX pipes are byte streams we must take special measures to + * transmit data through a pipe in records. + * Each block of data is preceded by a header of sizeof(int) consisting + * containing the number of bytes in the block. + * To read a block we must read the count and then issue successive read + * requests until the entire block has been read. + * +*/ +void *WinProcessRead(void *vfd, void *buf, int maxbytes, int *got) +{ + register char *op; + register int nbytes; + char *obuf; + int record_length; + int temp; + DWORD tgot; + HANDLE fd = (HANDLE)vfd; + + /* no data read as yet */ + *got = 0; + + /* Get byte count of record. + */ + if((ReadFile(fd, &temp, sizeof(int), &tgot, NULL) == FALSE) || + (tgot != sizeof(int))) + return NULL; + record_length = temp; + if( maxbytes >= 0 ) + nbytes = min(record_length, maxbytes); + else + nbytes = record_length; + + /* allocate output buffer, if necessary */ + if( buf ) + obuf = buf; + else{ + obuf = (char *)malloc(nbytes); + if( !obuf ) return NULL; + } + op = (char *)obuf; + + /* Now read exactly nbytes of data from channel into user buffer. + * Return actual byte count if EOF is seen. If an error is seen, return. + * If necessary multiple read requests are issued to read the + * entire record. + */ + while (nbytes > 0){ + if( ReadFile(fd, op, nbytes, &tgot, NULL) == FALSE ){ + if( !buf ) free(obuf); + *got = 0; + return NULL; + } else if( tgot == 0 ){ + return(obuf); + } else { + nbytes -= tgot; + *got += tgot; + op += tgot; + } + } + + /* If the record is larger than maxbytes, we must read and discard + * the additional bytes. The method used is inefficient but it is + * unlikely that we will be called to read less than a full record. + */ + if( maxbytes >= 0 ){ + for (nbytes = maxbytes; nbytes < record_length; nbytes++){ + if( (ReadFile(fd, &temp, 1, &tgot, NULL) == FALSE) || (tgot == 0) ){ + break; + } + } + } + return(obuf); +} + +/* + * + * ProcessWrite -- Write to an IPC channel. + * Write the IPC block header followed by the data block. + * +*/ +int WinProcessWrite(void *vfd, void *buf, int nbytes) +{ + DWORD tgot; + BOOL got; + HANDLE fd = (HANDLE)vfd; + + /* write byte count */ + WriteFile(fd, &nbytes, sizeof(int), &tgot, NULL); + + /* write data block */ + got = WriteFile(fd, buf, nbytes, &tgot, NULL); + if( got == FALSE ){ + return(-1); + } else { + return((int)tgot); + } +} + +#else + +int have_winprocess=0; + +#endif |