/*******************************************************************************
* Copyright (c) 2002, 2006 QNX Software Systems and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* QNX Software Systems - initial API and implementation
* Wind River Systems, Inc.
*
* 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 // Initial 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.
#define MAX_PROCS (100) // Maximum number of simultaneiously runnig processes
// Process description block. Should be created for each launched process
typedef struct _procInfo {
int pid; // 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; // Number of running processes
// This is a VM helper
JNIEXPORT void JNICALL ThrowByName(JNIEnv *env, const char *name, const char *msg);
// 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(_TCHAR * target, const _TCHAR * 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,
SIG_INT,
SIG_KILL = 9,
SIG_TERM = 15,
} signals;
extern CRITICAL_SECTION cs;
extern _TCHAR path[MAX_PATH]; // Directory where spawner.dll is located
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_exec2
(JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir, jintArray channels, jstring slaveName, jint fdm)
{
return -1;
}
void ensureSize(_TCHAR** ptr, int* psize, int requiredLength)
{
int size= *psize;
if (requiredLength > size) {
size= 2*size;
if (size < requiredLength) {
size= requiredLength;
}
*ptr= (_TCHAR *)realloc(*ptr, size * sizeof(_TCHAR));
if (NULL == *ptr) {
*psize= 0;
}
else {
*psize= size;
}
}
}
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
(JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir, jintArray channels)
{
HANDLE stdHandles[3];
PROCESS_INFORMATION pi = {0};
STARTUPINFOW si;
DWORD flags = 0;
const _TCHAR * cwd = NULL;
LPVOID envBlk = NULL;
int ret = 0;
int nCmdLineLength= 0;
_TCHAR * szCmdLine= 0;
int nBlkSize = MAX_ENV_SIZE;
_TCHAR * szEnvBlock = NULL;
jsize nCmdTokens = 0;
jsize nEnvVars = 0;
int i;
DWORD pid = GetCurrentProcessId();
int nPos;
pProcInfo_t pCurProcInfo;
DWORD dwThreadId;
_TCHAR eventBreakName[20];
_TCHAR eventWaitName[20];
_TCHAR eventTerminateName[20];
#ifdef DEBUG_MONITOR
_TCHAR buffer[1000];
#endif
int nLocalCounter;
_TCHAR inPipeName[PIPE_NAME_LENGTH];
_TCHAR outPipeName[PIPE_NAME_LENGTH];
_TCHAR errPipeName[PIPE_NAME_LENGTH];
nCmdLineLength= MAX_CMD_SIZE;
szCmdLine= (_TCHAR *)malloc(nCmdLineLength * sizeof(_TCHAR));
szCmdLine[0]= _T('\0');
if((HIBYTE(LOWORD(GetVersion()))) & 0x80)
{
ThrowByName(env, "java/io/IOException", "Does not support Windows 3.1/95/98/Me");
return 0;
}
if (cmdarray == 0)
{
ThrowByName(env, "java/lang/NullPointerException", "No command line specified");
return 0;
}
ZeroMemory(stdHandles, sizeof(stdHandles));
// Create pipe names
EnterCriticalSection(&cs);
_stprintf(inPipeName, L"\\\\.\\pipe\\stdin%08i%010i", pid, nCounter);
_stprintf(outPipeName, L"\\\\.\\pipe\\stdout%08i%010i", pid, nCounter);
_stprintf(errPipeName, L"\\\\.\\pipe\\stderr%08i%010i", pid, nCounter);
nLocalCounter = nCounter;
++nCounter;
LeaveCriticalSection(&cs);
if ((INVALID_HANDLE_VALUE == (stdHandles[0] = CreateNamedPipeW(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] = CreateNamedPipeW(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] = CreateNamedPipeW(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
_stprintf(buffer, _T("Opened pipes: %s, %s, %s\n"), inPipeName, outPipeName, errPipeName);
OutputDebugStringW(buffer);
#endif
nCmdTokens = (*env) -> GetArrayLength(env, cmdarray);
nEnvVars = (*env) -> GetArrayLength(env, envp);
pCurProcInfo = createProcInfo();
if(NULL == pCurProcInfo)
{
ThrowByName(env, "java/io/IOException", "Too many processes");
return 0;
}
// Construct starter's command line
_stprintf(eventBreakName, L"SABreak%p", pCurProcInfo);
_stprintf(eventWaitName, L"SAWait%p", pCurProcInfo);
_stprintf(eventTerminateName, L"SATerm%p", pCurProcInfo);
pCurProcInfo -> eventBreak = CreateEventW(NULL, TRUE, FALSE, eventBreakName);
ResetEvent(pCurProcInfo -> eventBreak);
pCurProcInfo -> eventWait = CreateEventW(NULL, TRUE, FALSE, eventWaitName);
ResetEvent(pCurProcInfo -> eventWait);
pCurProcInfo -> eventTerminate = CreateEventW(NULL, TRUE, FALSE, eventTerminateName);
ResetEvent(pCurProcInfo -> eventTerminate);
nPos = _stprintf(szCmdLine, L"%sstarter.exe %i %i %s %s %s ", path, pid, nLocalCounter, eventBreakName, eventWaitName, eventTerminateName);
// Prepare command line
for(i = 0; i < nCmdTokens; ++i)
{
jobject item = (*env) -> GetObjectArrayElement(env
- 1
- 2
- 3
前往页