1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-07-24 01:15:29 +02:00

Update the starter/spawner to use named pipes.

Patch from alex.
This commit is contained in:
Alain Magloire 2004-02-12 21:12:51 +00:00
parent 385ac1b870
commit c2ba759a8c
13 changed files with 482 additions and 203 deletions

View file

@ -1,3 +1,8 @@
2004-02-12 Alex Chapiro
Update starter and spawner to use named pipes.
Update the binaries.
2003-08-29 Alex Chapiro
This patch just increase command line buffer up to OS limit (2K). It also

View file

@ -1,3 +1,17 @@
/**********************************************************************
* Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*
* Spawner.h
*
* This is a part of JNI implementation of spawner
***********************************************************************/
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class org_eclipse_cdt_utils_spawner_Spawner */
@ -40,9 +54,15 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_raise
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor
(JNIEnv *, jobject, jint);
// #define DEBUG_MONITOR
int interruptProcess(int pid);
#ifdef __cplusplus
}
#endif
// #define DEBUG_MONITOR
#endif

View file

@ -1,3 +1,18 @@
/**********************************************************************
* Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*
* SpawnerInputStream.h
*
* This is a part of JNI implementation of spawner
***********************************************************************/
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_qnx_tools_utils_spawner_SpawnerInputStream */

View file

@ -1,3 +1,17 @@
/**********************************************************************
* Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*
* SpawnerOutputStream.h
*
* This is a part of JNI implementation of spawner
***********************************************************************/
/* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h>
/* Header for class com_qnx_tools_utils_spawner_SpawnerOutputStream */

View file

@ -1,12 +1,16 @@
/**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others.
* Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*
* StdAfx.c
*
* This is a part of JNI implementation of spawner
***********************************************************************/
// stdafx.cpp : source file that includes just the standard includes
// spawner.pch will be the pre-compiled header

View file

@ -1,13 +1,18 @@
/**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others.
* Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*
* StdAfx.h
*
* This is a part of JNI implementation of spawner
***********************************************************************/
// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently

View file

@ -1,59 +1,76 @@
/**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others.
* Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
***********************************************************************/
/*
*
* Win32ProcessEx.c
*
* This is a JNI implementation of spawner
*/
***********************************************************************/
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#include <process.h>
#include "Spawner.h"
#include "jni.h"
#include "io.h"
#define PIPE_SIZE 512 // Size of pipe buffer
#define MAX_CMD_SIZE 2049 // Maximum size of command line
#define MAX_ENV_SIZE 4096 // Initial size of environment block
#define PIPE_NAME_LENGTH 100 // Size of pipe name buffer
#define PIPE_TIMEOUT 10000 // Default time-out value, in milliseconds.
#include "jni.h"
#include "io.h"
// #define DEBUG_MONITOR
#define PIPE_SIZE 512
#define MAX_CMD_SIZE 2049
#define MAX_ENV_SIZE 4096
#define MAX_PROCS (100)
#define MAX_PROCS (100) // Maximum number of simultaneiously runnig processes
// Theses are VM helpers
typedef JNIEXPORT void * (JNICALL * JVM_GetThreadInterruptEvent)();
typedef JNIEXPORT char * (JNICALL * JVM_NativePath)(const char *);
// Process description block. Should be created for each launched process
typedef struct _procInfo {
int pid; // Process ID
int uid; // quasi-unique process ID
int uid; // quasi-unique process ID; we have to create it to avoid duplicated pid
// (actually this impossible from OS point of view but it is still possible
// a clash of new created and already finished process with one and the same PID.
// 3 events connected to this process (see starter)
HANDLE eventBreak;
HANDLE eventWait;
HANDLE eventTerminate;
} procInfo_t, * pProcInfo_t;
static int procCounter = 0;
static int procCounter = 0; // Number of running processes
// This is a VM helper
JNIEXPORT void JNICALL ThrowByName(JNIEnv *env, const char *name, const char *msg);
pProcInfo_t createProcInfo();
pProcInfo_t findProcInfo(int pid);
// Creates _procInfo block for every launched procss
pProcInfo_t createProcInfo();
// Find process description for this pid
pProcInfo_t findProcInfo(int pid);
// We launch separate thread for each project to trap it termination
unsigned int _stdcall waitProcTermination(void* pv) ;
// This is a helper function to prevent losing of quotatin marks
static int copyTo(char * target, const char * source, int cpyLenght, int availSpace);
// Use this function to clean project descriptor and return it to the pool of available blocks.
static void cleanUpProcBlock(pProcInfo_t pCurProcInfo);
// Signal codes
typedef enum {
SIG_NOOP,
SIG_HUP,
@ -65,20 +82,27 @@ typedef enum {
extern CRITICAL_SECTION cs;
extern TCHAR path[MAX_PATH];
extern TCHAR path[MAX_PATH]; // Directory where spawner.dll is located
static HMODULE hVM = NULL;
static HMODULE hVM = NULL; // VM handler
static pProcInfo_t pInfo = NULL;
static int nCounter = 0; // We use it to build unique synchronisation object names
/////////////////////////////////////////////////////////////////////////////////////
// Launcher; launchess process and traps its termination
// Arguments: (see Spawner.java)
// [in] cmdarray - array of command line elements
// [in] envp - array of environment variables
// [in] dir - working directory
// [out] channels - streams handlers
/////////////////////////////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
(JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir, jintArray channels)
{
HANDLE hread[3], hwrite[3];
SECURITY_ATTRIBUTES sa;
HANDLE stdHandles[3];
PROCESS_INFORMATION pi = {0};
STARTUPINFO si;
DWORD flags = 0;
@ -91,6 +115,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
jsize nCmdTokens = 0;
jsize nEnvVars = 0;
int i;
DWORD pid = GetCurrentProcessId();
int nPos;
pProcInfo_t pCurProcInfo;
DWORD dwThreadId;
@ -100,6 +125,10 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
#ifdef DEBUG_MONITOR
char buffer[1000];
#endif
int nLocalCounter;
char inPipeName[PIPE_NAME_LENGTH];
char outPipeName[PIPE_NAME_LENGTH];
char errPipeName[PIPE_NAME_LENGTH];
if((HIBYTE(LOWORD(GetVersion()))) & 0x80)
{
@ -113,25 +142,39 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
return 0;
}
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = 0;
sa.bInheritHandle = TRUE;
ZeroMemory(stdHandles, sizeof(stdHandles));
memset(hread, 0, sizeof(hread));
memset(hwrite, 0, sizeof(hwrite));
if (!(CreatePipe(&hread[0], &hwrite[0], &sa, PIPE_SIZE) &&
CreatePipe(&hread[1], &hwrite[1], &sa, PIPE_SIZE) &&
CreatePipe(&hread[2], &hwrite[2], &sa, PIPE_SIZE)))
{
CloseHandle(hread[0]);
CloseHandle(hread[1]);
CloseHandle(hread[2]);
CloseHandle(hwrite[0]);
CloseHandle(hwrite[1]);
CloseHandle(hwrite[2]);
// Create pipe names
EnterCriticalSection(&cs);
sprintf(inPipeName, "\\\\.\\pipe\\stdin%08i%010i", pid, nCounter);
sprintf(outPipeName, "\\\\.\\pipe\\stdout%08i%010i", pid, nCounter);
sprintf(errPipeName, "\\\\.\\pipe\\stderr%08i%010i", pid, nCounter);
nLocalCounter = nCounter;
++nCounter;
LeaveCriticalSection(&cs);
if ((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateNamedPipe(inPipeName, PIPE_ACCESS_OUTBOUND,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL))) ||
(INVALID_HANDLE_VALUE == (stdHandles[1] = CreateNamedPipe(outPipeName, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL))) ||
(INVALID_HANDLE_VALUE == (stdHandles[2] = CreateNamedPipe(errPipeName, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED,
PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
PIPE_UNLIMITED_INSTANCES, PIPE_SIZE, PIPE_SIZE, PIPE_TIMEOUT, NULL)))) {
CloseHandle(stdHandles[0]);
CloseHandle(stdHandles[1]);
CloseHandle(stdHandles[2]);
ThrowByName(env, "java/io/IOException", "CreatePipe");
return 0;
}
}
#ifdef DEBUG_MONITOR
sprintf(buffer, "Opened pipes: %s, %s, %s\n", inPipeName, outPipeName, errPipeName);
OutputDebugString(buffer);
#endif
nCmdTokens = (*env) -> GetArrayLength(env, cmdarray);
nEnvVars = (*env) -> GetArrayLength(env, envp);
@ -144,17 +187,18 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
return 0;
}
// Construct starter's command line
sprintf(eventBreakName, "SABreak%p", pCurProcInfo);
sprintf(eventWaitName, "SAWait%p", pCurProcInfo);
sprintf(eventTerminateName, "SATerm%p", pCurProcInfo);
pCurProcInfo -> eventBreak = CreateEvent(NULL, TRUE, FALSE, eventBreakName);
ResetEvent(pCurProcInfo -> eventBreak);
pCurProcInfo -> eventWait = CreateEvent(NULL, TRUE, FALSE, eventWaitName);
ResetEvent(pCurProcInfo -> eventWait);
pCurProcInfo -> eventTerminate = CreateEvent(NULL, TRUE, FALSE, eventTerminateName);
ResetEvent(pCurProcInfo -> eventTerminate);
nPos = sprintf(szCmdLine, "%sstarter.exe %s %s %s ", path, eventBreakName, eventWaitName, eventTerminateName);
nPos = sprintf(szCmdLine, "%sstarter.exe %i %i %s %s %s ", path, pid, nLocalCounter, eventBreakName, eventWaitName, eventTerminateName);
// Prepare command line
for(i = 0; i < nCmdTokens; ++i)
@ -229,21 +273,16 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
}
memset(&si, 0, sizeof(si));
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
si.dwFlags |= STARTF_USESTDHANDLES;
si.dwFlags |= STARTF_USESHOWWINDOW;
si.wShowWindow = SW_HIDE; // Processes in the Process Group are hidden
si.hStdInput = hread[0];
si.hStdOutput = hwrite[1];
si.hStdError = hwrite[2];
SetHandleInformation(hwrite[0], HANDLE_FLAG_INHERIT, FALSE);
SetHandleInformation(hread[1], HANDLE_FLAG_INHERIT, FALSE);
SetHandleInformation(hread[2], HANDLE_FLAG_INHERIT, FALSE);
SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, FALSE);
SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, FALSE);
SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, FALSE);
flags = CREATE_NEW_CONSOLE;
flags |= CREATE_NO_WINDOW;
@ -251,14 +290,15 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
#ifdef DEBUG_MONITOR
OutputDebugString(szCmdLine);
#endif
// launches starter; we need it to create another console group to correctly process
// emulation of SYSint signal (Ctrl-C)
ret = CreateProcess(0, /* executable name */
szCmdLine, /* command line */
szCmdLine, /* command line */
0, /* process security attribute */
0, /* thread security attribute */
TRUE, /* inherits system handles */
FALSE, /* inherits system handles */
flags, /* normal attached process */
envBlk, /* environment block */
envBlk, /* environment block */
cwd, /* change to the new current directory */
&si, /* (in) startup information */
&pi); /* (out) process information */
@ -270,18 +310,13 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
free(szEnvBlock);
CloseHandle(hread[0]);
CloseHandle(hwrite[1]);
CloseHandle(hwrite[2]);
if (!ret)
if (!ret) // Launching error
{
LPTSTR lpMsgBuf;
CloseHandle(hwrite[0]);
CloseHandle(hread[1]);
CloseHandle(hread[2]);
CloseHandle(stdHandles[0]);
CloseHandle(stdHandles[1]);
CloseHandle(stdHandles[2]);
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
@ -327,18 +362,19 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
}
else
{
#ifdef DEBUG_MONITOR
sprintf(buffer, "Process %i created\n", pi.dwProcessId);
OutputDebugString(buffer);
#endif
ret = (long)(pCurProcInfo -> uid);
file_handles[0] = (int)hwrite[0];
file_handles[1] = (int)hread[1];
file_handles[2] = (int)hread[2];
// Prepare stream handlers to return to java program
file_handles[0] = (int)stdHandles[0];
file_handles[1] = (int)stdHandles[1];
file_handles[2] = (int)stdHandles[2];
(*env) -> SetIntArrayRegion(env, channels, 0, 3, file_handles);
}
CloseHandle(h[1]);
LeaveCriticalSection(&cs);
#ifdef DEBUG_MONITOR
OutputDebugString("Process started\n");
#endif
}
@ -348,6 +384,13 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
}
/////////////////////////////////////////////////////////////////////////////////////
// Launcher; just launches process and don't care about it any more
// Arguments: (see Spawner.java)
// [in] cmdarray - array of command line elements
// [in] envp - array of environment variables
// [in] dir - working directory
/////////////////////////////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
(JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir)
{
@ -389,7 +432,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
{
if(0 > (nCpyLen = copyTo(szCmdLine + nPos, str, len, MAX_CMD_SIZE - nPos)))
{
ThrowByName(env, "java/io/IOException", "Too long command line");
ThrowByName(env, "java/io/Exception", "Too long command line");
return 0;
}
nPos += nCpyLen;
@ -418,7 +461,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
szEnvBlock = (char *)realloc(szEnvBlock, nBlkSize);
if(NULL == szEnvBlock)
{
ThrowByName(env, "java/io/IOException", "Not enough memory");
ThrowByName(env, "java/io/Exception", "Not enough memory");
return 0;
}
}
@ -446,7 +489,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
}
memset(&si, 0, sizeof(si));
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
@ -472,7 +515,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
free(cwd);
free(szEnvBlock);
if (!ret)
if (!ret) // error
{
LPTSTR lpMsgBuf;
@ -494,6 +537,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
}
else
{
// Clean-up
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
ret = (long)pi.dwProcessId; //hProcess;
@ -505,6 +549,12 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
}
/////////////////////////////////////////////////////////////////////////////////////
// Emulation of the signal raising
// Arguments: (see Spawner.java)
// [in] uid - unique process ID
// [in] signal - signal to raise
/////////////////////////////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_raise
(JNIEnv * env, jobject process, jint uid, jint signal)
{
@ -570,13 +620,18 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_raise
}
/////////////////////////////////////////////////////////////////////////////////////
// Wait for process termination
// Arguments: (see Spawner.java)
// [in] uid - unique process ID
/////////////////////////////////////////////////////////////////////////////////////
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor
(JNIEnv * env, jobject process, jint uid)
{
long exit_code;
int what=0;
{
long exit_code;
int what=0;
HANDLE hProc;
pProcInfo_t pCurProcInfo = findProcInfo(uid);
@ -590,25 +645,31 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor
what = WaitForSingleObject(hProc, INFINITE);
if (what == WAIT_OBJECT_0)
{
GetExitCodeProcess(hProc, &exit_code);
{
GetExitCodeProcess(hProc, &exit_code);
}
if(hProc)
CloseHandle(hProc);
return exit_code;
}
return exit_code;
}
// Utilities
/////////////////////////////////////////////////////////////////////////////////////
// Throws Java exception (will be trapped by VM).
// Arguments:
// [in] name - name of exception class
// [in] message to assign thi event
/////////////////////////////////////////////////////////////////////////////////////
JNIEXPORT void JNICALL
ThrowByName(JNIEnv *env, const char *name, const char *msg)
{
@ -624,6 +685,11 @@ ThrowByName(JNIEnv *env, const char *name, const char *msg)
/////////////////////////////////////////////////////////////////////////////////////
// Create process description block.
// Arguments: no
// Return : pointer to the process descriptor
/////////////////////////////////////////////////////////////////////////////////////
pProcInfo_t createProcInfo()
{
int i;
@ -634,7 +700,7 @@ pProcInfo_t createProcInfo()
if(NULL == pInfo)
{
pInfo = malloc(sizeof(procInfo_t) * MAX_PROCS);
memset(pInfo, 0, sizeof(procInfo_t) * MAX_PROCS);
ZeroMemory(pInfo, sizeof(procInfo_t) * MAX_PROCS);
}
for(i = 0; i < MAX_PROCS; ++i)
@ -653,6 +719,11 @@ pProcInfo_t createProcInfo()
return p;
}
/////////////////////////////////////////////////////////////////////////////////////
// Using unique process ID finds process descriptor
// Arguments: no
// Return : pointer to the process descriptor
/////////////////////////////////////////////////////////////////////////////////////
pProcInfo_t findProcInfo(int uid)
{
int i;
@ -672,6 +743,11 @@ pProcInfo_t findProcInfo(int uid)
return p;
}
/////////////////////////////////////////////////////////////////////////////////////
// Cleans up vacant process descriptor
// Arguments:
// pCurProcInfo - pointer to descriptor to clean up
// Return : no
void cleanUpProcBlock(pProcInfo_t pCurProcInfo)
{
if(0 != pCurProcInfo -> eventBreak)
@ -693,11 +769,16 @@ void cleanUpProcBlock(pProcInfo_t pCurProcInfo)
pCurProcInfo -> pid = 0;
}
/////////////////////////////////////////////////////////////////////////////////////
// Running in separae thread and waiting for the process termination
// Arguments:
// pv - (int)pv is a pid
// Return : always 0
/////////////////////////////////////////////////////////////////////////////////////
unsigned int _stdcall waitProcTermination(void* pv)
{
int i;
int pid = (int)pv;
DWORD rc = 0;
#ifdef DEBUG_MONITOR
char buffer[1000];
#endif
@ -742,7 +823,15 @@ unsigned int _stdcall waitProcTermination(void* pv)
return 0;
}
// Return number of bytes in target or -1 in case of error
/////////////////////////////////////////////////////////////////////////////////////
// Use this utility program to process correctly quotation marks in the command line
// Arguments:
// target - string to copy to
// source - string to copy from
// cpyLength - copy length
// availSpace - size of the target buffer
// Return :number of bytes used in target, or -1 in case of error
/////////////////////////////////////////////////////////////////////////////////////
int copyTo(char * target, const char * source, int cpyLength, int availSpace)
{
BOOL bSlash = FALSE;

View file

@ -1,23 +1,25 @@
/**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others.
* Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*
* raise.c
*
* This is a part of JNI implementation of spawner
* Includes implementation of JNI methods (see Spawner.java)
***********************************************************************/
/*
* This is a JNI implementation of access to standard i/o streams
*/
#include "stdafx.h"
#include <string.h>
#include <stdlib.h>
#include "spawner.h"
#include "SpawnerInputStream.h"
#include "SpawnerOutputStream.h"
#include "jni.h"
#include "io.h"
@ -37,35 +39,87 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_rea
{
BYTE tmpBuf[BUFF_SIZE];
int nBuffOffset = 0;
#ifdef DEBUG_MONITOR
char buffer[1000];
#endif
OVERLAPPED overlapped;
overlapped.Offset = 0;
overlapped.OffsetHigh = 0;
overlapped.hEvent = CreateEvent(NULL, // no security attribute
TRUE, // manual-reset event
TRUE, // initial state = signaled
NULL); // unnamed event object
if(NULL == overlapped.hEvent) {
LPTSTR lpMsgBuf;
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
ThrowByName(env, "java/io/IOException", lpMsgBuf);
}
#ifdef DEBUG_MONITOR
sprintf(buffer, "Start read %i\n", fd);
OutputDebugString(buffer);
#endif
while(len > nBuffOffset)
{
int nNumberOfBytesToRead = min(len - nBuffOffset, BUFF_SIZE);
int nNumberOfBytesRead;
if(0 == ReadFile((HANDLE)fd, tmpBuf, nNumberOfBytesToRead, &nNumberOfBytesRead, NULL ))
if(0 == ReadFile((HANDLE)fd, tmpBuf, nNumberOfBytesToRead, &nNumberOfBytesRead, &overlapped ))
{
LPTSTR lpMsgBuf;
int err = GetLastError();
if(err == ERROR_IO_PENDING)
{
// asynchronous i/o is still in progress
// check on the results of the asynchronous read
if(GetOverlappedResult((HANDLE)fd, &overlapped,
&nNumberOfBytesRead, TRUE))
err = 0;
// if there was a problem ...
else
err = GetLastError();
}
if(err == ERROR_BROKEN_PIPE) // Pipe was closed
return 0;
if(err != ERROR_MORE_DATA) // Otherwise error means just that there are more data
{ // than buffer can accept
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
break;
if(err != 0)
{
LPTSTR lpMsgBuf;
#ifdef DEBUG_MONITOR
char buffer[200];
sprintf(buffer, "Read failed - %i, error %i\n", fd, err);
OutputDebugString(buffer);
#endif
if(err != ERROR_MORE_DATA) // Otherwise error means just that there are more data
{ // than buffer can accept
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
err,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(LPTSTR) &lpMsgBuf,
0,
NULL
);
ThrowByName(env, "java/io/IOException", lpMsgBuf);
LocalFree( lpMsgBuf );
return 0;
ThrowByName(env, "java/io/IOException", lpMsgBuf);
LocalFree( lpMsgBuf );
nBuffOffset = 0;
break;
}
}
}
if(nNumberOfBytesRead > 0)
@ -76,6 +130,11 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_rea
if(nNumberOfBytesRead != nNumberOfBytesToRead)
break;
}
CloseHandle(overlapped.hEvent);
#ifdef DEBUG_MONITOR
sprintf(buffer, "End read %i\n", fd);
OutputDebugString(buffer);
#endif
return nBuffOffset; // This is a real full readed length
}
@ -88,7 +147,19 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_rea
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0
(JNIEnv * env, jobject proc, jint fd)
{
return (CloseHandle((HANDLE)fd) ? 0 : -1);
int rc;
#ifdef DEBUG_MONITOR
char buffer[1000];
sprintf(buffer, "Close %i\n", fd);
OutputDebugString(buffer);
#endif
DisconnectNamedPipe((HANDLE)fd);
rc = (CloseHandle((HANDLE)fd) ? 0 : -1);
#ifdef DEBUG_MONITOR
sprintf(buffer, "Closed %i\n", fd);
OutputDebugString(buffer);
#endif
return (rc ? GetLastError() : 0);
}
/*
@ -102,6 +173,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_wr
BYTE tmpBuf[BUFF_SIZE];
int nBuffOffset = 0;
while(len > nBuffOffset)
{
int nNumberOfBytesToWrite = min(len - nBuffOffset, BUFF_SIZE);
@ -139,5 +211,17 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_wr
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0
(JNIEnv * env, jobject proc, jint fd)
{
return (CloseHandle((HANDLE)fd) ? 0 : -1);
int rc;
#ifdef DEBUG_MONITOR
char buffer[1000];
sprintf(buffer, "Close %i\n", fd);
OutputDebugString(buffer);
#endif
DisconnectNamedPipe((HANDLE)fd);
rc = (CloseHandle((HANDLE)fd) ? 0 : -1);
#ifdef DEBUG_MONITOR
sprintf(buffer, "Closed %i\n", fd);
OutputDebugString(buffer);
#endif
return (rc ? GetLastError() : 0);
}

View file

@ -1,16 +1,17 @@
/**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others.
* Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*
* raise.c
*
* This is a part of JNI implementation of spawner
***********************************************************************/
/*
* This is a JNI implementation of spawner
*/
#include "stdafx.h"
#include "Spawner.h"
@ -19,10 +20,17 @@
extern void JNICALL ThrowByName(JNIEnv *env, const char *name, const char *msg);
// #define DEBUG_MONITOR
static HWND consoleHWND;
/////////////////////////////////////////////////////////////////////////////////////
// Check if window is a console of process with pid
// Arguments:
// hwnd - window handler
// arg - process PID
// Return : TRUE if yes
/////////////////////////////////////////////////////////////////////////////////////
static BOOL CALLBACK
find_child_console (HWND hwnd, LPARAM arg)
{
@ -46,35 +54,13 @@ find_child_console (HWND hwnd, LPARAM arg)
return TRUE;
}
/*
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_raise__Ljava_lang_Object_2
(JNIEnv * env, jobject process, jobject jpid)
{
jint pid;
jclass integerClass = (*env) -> FindClass(env, "java/lang/Integer");
jmethodID intValue;
if(NULL == integerClass) {
ThrowByName(env, "java/lang/IOException", "Cannot find Integer class");
return -1;
}
if(!((*env) -> IsInstanceOf(env, jpid, integerClass))) {
ThrowByName(env, "java/lang/IOException", "Wrong argument");
return -1;
}
intValue = (*env) -> GetMethodID(env, integerClass, "intValue", "()I");
if(NULL == intValue) {
ThrowByName(env, "java/lang/IOException", "Cannot find intValue method in Integer class");
return -1;
}
pid = (*env) -> CallIntMethod(env, jpid, intValue);
return interruptProcess(pid);
}
*/
/////////////////////////////////////////////////////////////////////////////////////
// Function implements interrupt process (Ctrl-C emulation)
// Arguments:
// pid - process' pid
// Return : 0 if OK or error code
/////////////////////////////////////////////////////////////////////////////////////
int interruptProcess(int pid)
{
#ifdef DEBUG_MONITOR
@ -89,10 +75,13 @@ int interruptProcess(int pid)
sprintf(buffer, "Try to interrupt process %i\n", pid);
OutputDebugString(buffer);
#endif
// Find console
EnumWindows (find_child_console, (LPARAM) pid);
if(NULL != consoleHWND)
if(NULL != consoleHWND) // Yes, we found out it
{
// We are going to switch focus to console,
// send Ctrl-C and then restore focus
BYTE control_scan_code = (BYTE) MapVirtualKey (VK_CONTROL, 0);
/* Fake Ctrl-C for SIGINT, and Ctrl-Break for SIGQUIT. */
BYTE vk_c_code = 'C';
@ -100,7 +89,7 @@ int interruptProcess(int pid)
BYTE c_scan_code = (BYTE) MapVirtualKey (vk_c_code, 0);
BYTE break_scan_code = (BYTE) MapVirtualKey (vk_break_code, 0);
HWND foreground_window;
foreground_window = GetForegroundWindow ();
if (foreground_window)
@ -128,17 +117,6 @@ int interruptProcess(int pid)
/* Set the foreground window to the child. */
if (SetForegroundWindow (consoleHWND))
{
/*
if(0 != c_scan_code) {
// Generate keystrokes as if user had typed Ctrl-C.
keybd_event (VK_CONTROL, control_scan_code, 0, 0);
keybd_event (vk_c_code, c_scan_code, 0, 0);
keybd_event (vk_c_code, c_scan_code, KEYEVENTF_KEYUP, 0);
keybd_event (VK_CONTROL, control_scan_code, KEYEVENTF_KEYUP, 0);
}
*/
/* Sleep for a bit to give time for respond */
Sleep (100);
if(0 != break_scan_code) {
/* Generate keystrokes as if user had typed Ctrl-Break */
keybd_event (VK_CONTROL, control_scan_code, 0, 0);

View file

@ -1,22 +1,26 @@
/**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others.
* Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
*
* spawner.c
*
* This is a part of JNI implementation of spawner
***********************************************************************/
// spawner.cpp : Defines the entry point for the DLL application.
//
#include "stdafx.h"
#include "spawner.h"
CRITICAL_SECTION cs;
TCHAR path[MAX_PATH + 1] = {_T('\0') };
TCHAR path[MAX_PATH + 1] = {_T('\0') }; // Directory where spawner.dll is located
BOOL APIENTRY DllMain( HANDLE hModule,
@ -48,4 +52,3 @@ BOOL APIENTRY DllMain( HANDLE hModule,
return TRUE;
}

View file

@ -1,22 +1,19 @@
/**********************************************************************
* Copyright (c) 2002,2003 QNX Software Systems and others.
* Copyright (c) 2002-2004 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v0.5
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v05.html
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* QNX Software Systems - Initial API and implementation
***********************************************************************/
/*
* starter.c
*
* starter.cpp
*
* This is a small utility for windows spawner
*/
***********************************************************************/
//#define UNICODE
//#define _UNICODE
#define STRICT
#include <Windows.h>
@ -24,8 +21,9 @@
#include <tchar.h>
#include <stdio.h>
// #define DEBUG_MONITOR
//#define DEBUG_MONITOR
#define MAX_CMD_LINE_LENGTH (2049)
#define PIPE_NAME_LENGTH 100
int copyTo(char * target, const char * source, int cpyLength, int availSpace);
@ -58,8 +56,8 @@ BOOL WINAPI HandlerRoutine( DWORD dwCtrlType) // control signal type
extern "C" int _tmain(int argc, TCHAR* argv[]) {
// Make sure that we've been passed the right number of arguments
if (argc < 5) {
// Make sure that we've been passed the right number of arguments
if (argc < 7) {
_tprintf(__TEXT("Usage: %s (Three InheritableEventHandles) (CommandLineToSpawn)\n"),
argv[0]);
return(0);
@ -69,7 +67,7 @@ extern "C" int _tmain(int argc, TCHAR* argv[]) {
TCHAR szCmdLine[MAX_CMD_LINE_LENGTH] = { 0 };
int nPos = 0;
for(int i = 4; i < argc; ++i)
for(int i = 6; i < argc; ++i)
{
int nCpyLen;
if(0 > (nCpyLen = copyTo(szCmdLine + nPos, argv[i], _tcslen(argv[i]), MAX_CMD_LINE_LENGTH - nPos)))
@ -94,28 +92,81 @@ extern "C" int _tmain(int argc, TCHAR* argv[]) {
#endif
BOOL exitProc = FALSE;
HANDLE waitEvent = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[2]);
HANDLE waitEvent = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[4]);
HANDLE h[3];
h[0] = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[1]);
h[2] = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[3]); // This is a terminate event
h[0] = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[3]);
h[2] = OpenEvent(EVENT_ALL_ACCESS, TRUE, argv[5]); // This is a terminate event
SetConsoleCtrlHandler(HandlerRoutine, TRUE);
int parentPid = strtol(argv[1], NULL, 10);
int nCounter = strtol(argv[2], NULL, 10);
char inPipeName[PIPE_NAME_LENGTH];
char outPipeName[PIPE_NAME_LENGTH];
char errPipeName[PIPE_NAME_LENGTH];
sprintf(inPipeName, "\\\\.\\pipe\\stdin%08i%010i", parentPid, nCounter);
sprintf(outPipeName, "\\\\.\\pipe\\stdout%08i%010i", parentPid, nCounter);
sprintf(errPipeName, "\\\\.\\pipe\\stderr%08i%010i", parentPid, nCounter);
#ifdef DEBUG_MONITOR
sprintf(buffer, "starter start command: %s\n", szCmdLine);
sprintf(buffer, "Pipes: %s, %s, %s\n", inPipeName, outPipeName, errPipeName);
OutputDebugString(buffer);
#endif
HANDLE stdHandles[3];
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);
sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
if((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateFile(inPipeName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, &sa))) ||
(INVALID_HANDLE_VALUE == (stdHandles[1] = CreateFile(outPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))) ||
(INVALID_HANDLE_VALUE == (stdHandles[2] = CreateFile(errPipeName, GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, &sa))))
{
#ifdef DEBUG_MONITOR
sprintf(buffer, "Failed to open pipe %i, %i, %i: %i\n", stdHandles[0], stdHandles[1], stdHandles[2], GetLastError());
OutputDebugString(buffer);
#endif
CloseHandle(stdHandles[0]);
CloseHandle(stdHandles[1]);
CloseHandle(stdHandles[2]);
return -1;;
}
SetHandleInformation(stdHandles[0], HANDLE_FLAG_INHERIT, TRUE);
SetHandleInformation(stdHandles[1], HANDLE_FLAG_INHERIT, TRUE);
SetHandleInformation(stdHandles[2], HANDLE_FLAG_INHERIT, TRUE);
if(!SetStdHandle(STD_INPUT_HANDLE, stdHandles[0]) ||
!SetStdHandle(STD_OUTPUT_HANDLE, stdHandles[1]) ||
!SetStdHandle(STD_ERROR_HANDLE, stdHandles[2])) {
#ifdef DEBUG_MONITOR
sprintf(buffer, "Failed to reassign standard streams: %i\n", GetLastError());
OutputDebugString(buffer);
#endif
CloseHandle(stdHandles[0]);
CloseHandle(stdHandles[1]);
CloseHandle(stdHandles[2]);
return -1;;
}
// OutputDebugString(szCmdLine);
// Spawn the other processes as part of this Process Group
BOOL f = CreateProcess(NULL, szCmdLine, NULL, NULL, TRUE,
0, NULL, NULL, &si, &pi);
// We don't need them any more
CloseHandle(stdHandles[0]);
CloseHandle(stdHandles[1]);
CloseHandle(stdHandles[2]);
if (f)
{
#ifdef DEBUG_MONITOR
sprintf(buffer, "Process %i started\n", pi.dwProcessId);
OutputDebugString(buffer);
#endif
SetEvent(waitEvent); // Means thar process has been spawned
CloseHandle(pi.hThread);
h[1] = pi.hProcess;
while(!exitProc)
{
// Wait for the spawned-process to die or for the event
@ -151,6 +202,7 @@ extern "C" int _tmain(int argc, TCHAR* argv[]) {
break;
default:
// Unexpected code
#ifdef DEBUG_MONITOR
LPTSTR lpMsgBuf;
FormatMessage(
@ -167,6 +219,7 @@ extern "C" int _tmain(int argc, TCHAR* argv[]) {
OutputDebugString(lpMsgBuf);
// Free the buffer.
LocalFree( lpMsgBuf );
#endif
exitProc = TRUE;
break;
}
@ -177,12 +230,21 @@ extern "C" int _tmain(int argc, TCHAR* argv[]) {
CloseHandle(waitEvent);
CloseHandle(h[0]);
CloseHandle(h[1]);
CloseHandle(h[2]);
return(dwExitCode);
}
// Return number of bytes in target or -1 in case of error
/////////////////////////////////////////////////////////////////////////////////////
// Use this utility program to process correctly quotation marks in the command line
// Arguments:
// target - string to copy to
// source - string to copy from
// cpyLength - copy length
// availSpace - size of the target buffer
// Return :number of bytes used in target, or -1 in case of error
/////////////////////////////////////////////////////////////////////////////////////
int copyTo(LPTSTR target, LPCTSTR source, int cpyLength, int availSpace)
{
BOOL bSlash = FALSE;