1
0
Fork 0
mirror of https://github.com/eclipse-cdt/cdt synced 2025-06-07 17:56:01 +02:00

Bug 521515: Use channel object for native stream access

On Linux and mac, a simple int will do for accessing streams (file
descriptor).
On Windows, a HANDLE is used. This is in reality a pointer and on 64
bit JVM, the pointer will not fit in an int. To not force a change to
the API everytime a different platform has a different requirement
for accessing streams, use a common interface and specific classes
that is known by the native part. The java part of the function
block should just pass the object back to the native code when
needing to reference an open stream.

Change-Id: Ibc3ff5c85735dac6a0ce8e9a1f25b839d7e9aab9
Signed-off-by: Torbjörn Svensson <azoff@svenskalinuxforeningen.se>
This commit is contained in:
Torbjörn Svensson 2020-08-07 12:21:16 +02:00 committed by Jonah Graham
parent 0d50385e63
commit 49dc726dd1
17 changed files with 235 additions and 157 deletions

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2002, 2010 QNX Software Systems and others. * Copyright (c) 2002, 2020 QNX Software Systems and others.
* *
* This program and the accompanying materials * This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0 * are made available under the terms of the Eclipse Public License 2.0
@ -27,10 +27,10 @@ extern "C" {
/* /*
* Class: org_eclipse_cdt_utils_spawner_Spawner * Class: org_eclipse_cdt_utils_spawner_Spawner
* Method: exec0 * Method: exec0
* Signature: ([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[I)I * Signature: ([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Lorg/eclipse/cdt/utils/spawner/Spawner/IChannel;)I
*/ */
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
(JNIEnv *, jobject, jobjectArray, jobjectArray, jstring, jintArray); (JNIEnv *, jobject, jobjectArray, jobjectArray, jstring, jobjectArray);
/* /*
* Class: org_eclipse_cdt_utils_spawner_Spawner * Class: org_eclipse_cdt_utils_spawner_Spawner
@ -43,10 +43,10 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec1
/* /*
* Class: org_eclipse_cdt_utils_spawner_Spawner * Class: org_eclipse_cdt_utils_spawner_Spawner
* Method: exec2 * Method: exec2
* Signature: ([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[ILjava/lang/String;IZ)I * Signature: ([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[Lorg/eclipse/cdt/utils/spawner/Spawner/IChannel;Ljava/lang/String;IZ)I
*/ */
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec2 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec2
(JNIEnv *, jobject, jobjectArray, jobjectArray, jstring, jintArray, jstring, jint, jboolean); (JNIEnv *, jobject, jobjectArray, jobjectArray, jstring, jobjectArray, jstring, jint, jboolean);
/* /*
* Class: org_eclipse_cdt_utils_spawner_Spawner * Class: org_eclipse_cdt_utils_spawner_Spawner
@ -64,15 +64,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_raise
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_waitFor
(JNIEnv *, jobject, jint); (JNIEnv *, jobject, jint);
// #define DEBUG_MONITOR
int interruptProcess(int pid);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
// #define DEBUG_MONITOR
#endif #endif

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2002, 2007 QNX Software Systems and others. * Copyright (c) 2002, 2020 QNX Software Systems and others.
* *
* This program and the accompanying materials * This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0 * are made available under the terms of the Eclipse Public License 2.0
@ -15,34 +15,40 @@
* *
* This is a part of JNI implementation of spawner * This is a part of JNI implementation of spawner
*******************************************************************************/ *******************************************************************************/
/* DO NOT EDIT THIS FILE - it is machine generated */ /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h> #include <jni.h>
/* Header for class com_qnx_tools_utils_spawner_SpawnerInputStream */ /* Header for class org_eclipse_cdt_utils_spawner_SpawnerInputStream */
#ifndef _Included_com_qnx_tools_utils_spawner_SpawnerInputStream #ifndef _Included_org_eclipse_cdt_utils_spawner_SpawnerInputStream
#define _Included_com_qnx_tools_utils_spawner_SpawnerInputStream #define _Included_org_eclipse_cdt_utils_spawner_SpawnerInputStream
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
#undef com_qnx_tools_utils_spawner_SpawnerInputStream_SKIP_BUFFER_SIZE #undef org_eclipse_cdt_utils_spawner_SpawnerInputStream_MAX_SKIP_BUFFER_SIZE
#define com_qnx_tools_utils_spawner_SpawnerInputStream_SKIP_BUFFER_SIZE 2048L #define org_eclipse_cdt_utils_spawner_SpawnerInputStream_MAX_SKIP_BUFFER_SIZE 2048L
/* Inaccessible static: skipBuffer */
/* /*
* Class: org_elipse_cdt_utils_spawner_SpawnerInputStream * Class: org_eclipse_cdt_utils_spawner_SpawnerInputStream
* Method: read0 * Method: read0
* Signature: (I[BI)I * Signature: (Lorg/eclipse/cdt/utils/spawner/Spawner/IChannel;[BI)I
*/ */
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_read0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_read0
(JNIEnv *, jobject, jint, jbyteArray, jint); (JNIEnv *, jobject, jobject, jbyteArray, jint);
/* /*
* Class: org_eclipse_cdt_utils_spawner_SpawnerInputStream * Class: org_eclipse_cdt_utils_spawner_SpawnerInputStream
* Method: close0 * Method: close0
* Signature: (I)I * Signature: (Lorg/eclipse/cdt/utils/spawner/Spawner/IChannel;)I
*/ */
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0
(JNIEnv *, jobject, jint); (JNIEnv *, jobject, jobject);
/*
* Class: org_eclipse_cdt_utils_spawner_SpawnerInputStream
* Method: available0
* Signature: (Lorg/eclipse/cdt/utils/spawner/Spawner/IChannel;)I
*/
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_available0
(JNIEnv *, jobject, jobject);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -1,5 +1,5 @@
/******************************************************************************* /*******************************************************************************
* Copyright (c) 2002, 2007 QNX Software Systems and others. * Copyright (c) 2002, 2020 QNX Software Systems and others.
* *
* This program and the accompanying materials * This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0 * are made available under the terms of the Eclipse Public License 2.0
@ -17,28 +17,28 @@
*******************************************************************************/ *******************************************************************************/
/* DO NOT EDIT THIS FILE - it is machine generated */ /* DO NOT EDIT THIS FILE - it is machine generated */
#include <jni.h> #include <jni.h>
/* Header for class com_qnx_tools_utils_spawner_SpawnerOutputStream */ /* Header for class org_eclipse_cdt_utils_spawner_SpawnerOutputStream */
#ifndef _Included_com_qnx_tools_utils_spawner_SpawnerOutputStream #ifndef _Included_org_eclipse_cdt_utils_spawner_SpawnerOutputStream
#define _Included_com_qnx_tools_utils_spawner_SpawnerOutputStream #define _Included_org_eclipse_cdt_utils_spawner_SpawnerOutputStream
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
/* /*
* Class: org_eclipse_cdt_utils_spawner_SpawnerOutputStream * Class: org_eclipse_cdt_utils_spawner_SpawnerOutputStream
* Method: write0 * Method: write0
* Signature: (I[BI)I * Signature: (Lorg/eclipse/cdt/utils/spawner/Spawner/IChannel;[BI)I
*/ */
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_write0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_write0
(JNIEnv *, jobject, jint, jbyteArray, jint); (JNIEnv *, jobject, jobject, jbyteArray, jint);
/* /*
* Class: org_eclipse_cdt_utils_spawner_SpawnerOutputStream * Class: org_eclipse_cdt_utils_spawner_SpawnerOutputStream
* Method: close0 * Method: close0
* Signature: (I)I * Signature: (Lorg/eclipse/cdt/utils/spawner/Spawner/IChannel;)I
*/ */
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0
(JNIEnv *, jobject, jint); (JNIEnv *, jobject, jobject);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -21,15 +21,44 @@
/* Header for class _org_eclipse_cdt_utils_spawner_SpawnerInputStream */ /* Header for class _org_eclipse_cdt_utils_spawner_SpawnerInputStream */
/* Header for class _org_eclipse_cdt_utils_spawner_SpawnerOutputStream */ /* Header for class _org_eclipse_cdt_utils_spawner_SpawnerOutputStream */
/* static void ThrowByName(JNIEnv *env, const char *name, const char *msg)
* Class: org_eclipse_cdt_utils_spawner_SpawnerInputStream {
* Method: read0 jclass cls = (*env)->FindClass(env, name);
* Signature: (I)I
*/ if (cls != 0) /* Otherwise an exception has already been thrown */
(*env)->ThrowNew(env, cls, msg);
/* It's a good practice to clean up the local references. */
(*env)->DeleteLocalRef(env, cls);
}
static int channelToFileDesc(JNIEnv * env, jobject channel)
{
if (channel == 0) {
ThrowByName(env, "java/io/IOException", "Invalid channel object");
return -1;
}
jclass cls = (*env)->GetObjectClass(env, channel);
if (cls == 0) {
ThrowByName(env, "java/io/IOException", "Unable to get channel class");
return -1;
}
jfieldID fid = (*env)->GetFieldID(env, cls, "fd", "I");
if (fid == 0) {
ThrowByName(env, "java/io/IOException", "Unable to find fd");
return -1;
}
jint fd = (*env)->GetIntField(env, channel, fid);
return fd;
}
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_read0(JNIEnv * env, Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_read0(JNIEnv * env,
jobject jobj, jobject jobj,
jint jfd, jobject channel,
jbyteArray buf, jbyteArray buf,
jint buf_len) jint buf_len)
{ {
@ -40,7 +69,7 @@ Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_read0(JNIEnv * env,
data = (*env)->GetByteArrayElements(env, buf, 0); data = (*env)->GetByteArrayElements(env, buf, 0);
data_len = buf_len; data_len = buf_len;
fd = jfd; fd = channelToFileDesc(env, channel);
status = read( fd, data, data_len ); status = read( fd, data, data_len );
(*env)->ReleaseByteArrayElements(env, buf, data, 0); (*env)->ReleaseByteArrayElements(env, buf, data, 0);
@ -62,28 +91,19 @@ Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_read0(JNIEnv * env,
} }
/*
* Class: org_eclipse_cdt_utils_spawner_SpawnerInputStream
* Method: close0
* Signature: (I)I
*/
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0(JNIEnv * env, Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0(JNIEnv * env,
jobject jobj, jobject jobj,
jint fd) jobject channel)
{ {
int fd = channelToFileDesc(env, channel);
return close(fd); return close(fd);
} }
/*
* Class: org_eclipse_cdt_utils_spawner_SpawnerOutputStream
* Method: write0
* Signature: (II)I
*/
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_write0(JNIEnv * env, Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_write0(JNIEnv * env,
jobject jobj, jobject jobj,
jint jfd, jobject channel,
jbyteArray buf, jbyteArray buf,
jint buf_len) jint buf_len)
{ {
@ -94,7 +114,7 @@ Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_write0(JNIEnv * env,
data = (*env)->GetByteArrayElements(env, buf, 0); data = (*env)->GetByteArrayElements(env, buf, 0);
data_len = buf_len; data_len = buf_len;
fd = jfd; fd = channelToFileDesc(env, channel);
status = write(fd, data, data_len); status = write(fd, data, data_len);
(*env)->ReleaseByteArrayElements(env, buf, data, 0); (*env)->ReleaseByteArrayElements(env, buf, data, 0);
@ -103,15 +123,11 @@ Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_write0(JNIEnv * env,
} }
/*
* Class: org_eclipse_cdt_utils_spawner_SpawnerOutputStream
* Method: close0
* Signature: (I)I
*/
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0(JNIEnv * env, Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0(JNIEnv * env,
jobject jobj, jobject jobj,
jint fd) jobject channel)
{ {
int fd = channelToFileDesc(env, channel);
return close(fd); return close(fd);
} }

View file

@ -86,16 +86,10 @@ static void free_c_array(char **c_array)
} }
/*
* Class: org_eclipse_cdt_utils_spawner_Spawner
* Method: exec2
* Signature: ([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[ILorg/eclipse/cdt/utils/pty/PTY;)I
*/
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec2 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec2
(JNIEnv *env, jobject jobj, jobjectArray jcmd, jobjectArray jenv, jstring jdir, jintArray jchannels, (JNIEnv *env, jobject jobj, jobjectArray jcmd, jobjectArray jenv, jstring jdir, jobjectArray jchannels,
jstring jslaveName, jint masterFD, jboolean console) jstring jslaveName, jint masterFD, jboolean console)
{ {
jint *channels = (*env)->GetIntArrayElements(env, jchannels, 0);
const char *dirpath = (*env)->GetStringUTFChars(env, jdir, NULL); const char *dirpath = (*env)->GetStringUTFChars(env, jdir, NULL);
const char *pts_name = (*env)->GetStringUTFChars(env, jslaveName, NULL); const char *pts_name = (*env)->GetStringUTFChars(env, jslaveName, NULL);
char **cmd = NULL; char **cmd = NULL;
@ -103,7 +97,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec2
int fd[3]; int fd[3];
pid_t pid = -1; pid_t pid = -1;
if (channels == NULL) if (jchannels == NULL)
goto bail_out; goto bail_out;
cmd = alloc_c_array(env, jcmd); cmd = alloc_c_array(env, jcmd);
@ -127,12 +121,15 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec2
if (pid < 0) if (pid < 0)
goto bail_out; goto bail_out;
channels[0] = fd[0]; jobject cls = (*env)->FindClass(env, "org/eclipse/cdt/utils/spawner/Spawner$UnixChannel");
channels[1] = fd[1]; jmethodID constructor = (*env)->GetMethodID(env, cls, "<init>", "(I)V");
channels[2] = fd[2]; for (jsize i = 0; i < 3; i++) {
jobject chan = (*env)->NewObject(env, cls, constructor, fd[i]);
(*env)->SetObjectArrayElement(env, jchannels, i, chan);
}
bail_out: bail_out:
(*env)->ReleaseIntArrayElements(env, jchannels, channels, 0);
(*env)->ReleaseStringUTFChars(env, jdir, dirpath); (*env)->ReleaseStringUTFChars(env, jdir, dirpath);
(*env)->ReleaseStringUTFChars(env, jslaveName, pts_name); (*env)->ReleaseStringUTFChars(env, jslaveName, pts_name);
if (cmd) if (cmd)
@ -183,26 +180,30 @@ Java_org_eclipse_cdt_utils_spawner_Spawner_exec1(JNIEnv * env, jobject jobj,
return pid; return pid;
} }
/*
* Class: org_eclipse_cdt_utils_spawner_Spawner
* Method: exec0
* Signature: ([Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;[I)I
*/
JNIEXPORT jint JNICALL JNIEXPORT jint JNICALL
Java_org_eclipse_cdt_utils_spawner_Spawner_exec0(JNIEnv * env, jobject jobj, Java_org_eclipse_cdt_utils_spawner_Spawner_exec0(JNIEnv * env, jobject jobj,
jobjectArray jcmd, jobjectArray jcmd,
jobjectArray jenv, jobjectArray jenv,
jstring jdir, jstring jdir,
jintArray jchannels) jobjectArray jchannels)
{ {
jint *channels = (*env)->GetIntArrayElements(env, jchannels, 0);
const char *dirpath = (*env)->GetStringUTFChars(env, jdir, NULL); const char *dirpath = (*env)->GetStringUTFChars(env, jdir, NULL);
char **cmd = NULL; char **cmd = NULL;
char **envp = NULL; char **envp = NULL;
int fd[3]; int fd[3];
pid_t pid = -1; pid_t pid = -1;
jclass channelClass = NULL;
jmethodID channelConstructor = NULL;
if (channels == NULL) if (jchannels == NULL)
goto bail_out;
channelClass = (*env)->FindClass(env, "org/eclipse/cdt/utils/spawner/Spawner$UnixChannel");
if (channelClass == 0)
goto bail_out;
channelConstructor = (*env)->GetMethodID(env, channelClass, "<init>", "(I)V");
if (channelConstructor == 0)
goto bail_out; goto bail_out;
cmd = alloc_c_array(env, jcmd); cmd = alloc_c_array(env, jcmd);
@ -220,17 +221,16 @@ Java_org_eclipse_cdt_utils_spawner_Spawner_exec0(JNIEnv * env, jobject jobj,
print_array(envp); print_array(envp);
fprintf(stderr, "dirpath: %s\n", dirpath); fprintf(stderr, "dirpath: %s\n", dirpath);
#endif #endif
pid = exec0(cmd[0], cmd, envp, dirpath, fd); pid = exec0(cmd[0], cmd, envp, dirpath, fd);
if (pid < 0) if (pid < 0)
goto bail_out; goto bail_out;
channels[0] = fd[0]; for (jsize i = 0; i < 3; i++) {
channels[1] = fd[1]; jobject chan = (*env)->NewObject(env, channelClass, channelConstructor, fd[i]);
channels[2] = fd[2]; (*env)->SetObjectArrayElement(env, jchannels, i, chan);
}
bail_out: bail_out:
(*env)->ReleaseIntArrayElements(env, jchannels, channels, 0);
(*env)->ReleaseStringUTFChars(env, jdir, dirpath); (*env)->ReleaseStringUTFChars(env, jdir, dirpath);
if (cmd) if (cmd)
free_c_array(cmd); free_c_array(cmd);

View file

@ -70,6 +70,8 @@ static int copyTo(wchar_t * target, const wchar_t * source, int cpyLenght, int
// Use this function to clean project descriptor and return it to the pool of available blocks. // Use this function to clean project descriptor and return it to the pool of available blocks.
static void cleanUpProcBlock(pProcInfo_t pCurProcInfo); static void cleanUpProcBlock(pProcInfo_t pCurProcInfo);
int interruptProcess(int pid);
// Signal codes // Signal codes
typedef enum { typedef enum {
@ -106,7 +108,7 @@ static int nCounter = 0; // We use it to build unique synchronization object nam
extern "C" extern "C"
#endif #endif
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec2 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, jboolean console) (JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir, jobjectArray channels, jstring slaveName, jint fdm, jboolean console)
{ {
return -1; return -1;
} }
@ -133,7 +135,7 @@ void ensureSize(wchar_t** ptr, int* psize, int requiredLength)
extern "C" extern "C"
#endif #endif
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
(JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir, jintArray channels) (JNIEnv * env, jobject process, jobjectArray cmdarray, jobjectArray envp, jstring dir, jobjectArray channels)
{ {
HANDLE stdHandles[3]; HANDLE stdHandles[3];
PROCESS_INFORMATION pi = {0}, *piCopy; PROCESS_INFORMATION pi = {0}, *piCopy;
@ -169,6 +171,28 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
wchar_t inPipeName[PIPE_NAME_LENGTH]; wchar_t inPipeName[PIPE_NAME_LENGTH];
wchar_t outPipeName[PIPE_NAME_LENGTH]; wchar_t outPipeName[PIPE_NAME_LENGTH];
wchar_t errPipeName[PIPE_NAME_LENGTH]; wchar_t errPipeName[PIPE_NAME_LENGTH];
jclass channelClass = NULL;
jmethodID channelConstructor = NULL;
if (channels == NULL)
{
ThrowByName(env, "java/io/IOException", "Channels can't be null");
return 0;
}
channelClass = (*env)->FindClass(env, "org/eclipse/cdt/utils/spawner/Spawner$WinChannel");
if (channelClass == 0)
{
ThrowByName(env, "java/io/IOException", "Unable to find channel class");
return 0;
}
channelConstructor = (*env)->GetMethodID(env, channelClass, "<init>", "(J)V");
if (channelConstructor == 0)
{
ThrowByName(env, "java/io/IOException", "Unable to find channel constructor");
return 0;
}
nCmdLineLength= MAX_CMD_SIZE; nCmdLineLength= MAX_CMD_SIZE;
szCmdLine= (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t)); szCmdLine= (wchar_t *)malloc(nCmdLineLength * sizeof(wchar_t));
@ -406,7 +430,6 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
} }
else else
{ {
int file_handles[3];
HANDLE h[2]; HANDLE h[2];
int what; int what;
@ -434,10 +457,10 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_Spawner_exec0
ret = (long)(pCurProcInfo -> uid); ret = (long)(pCurProcInfo -> uid);
// Prepare stream handlers to return to java program // Prepare stream handlers to return to java program
file_handles[0] = (int)stdHandles[0]; for (jsize i = 0; i < 3; i++) {
file_handles[1] = (int)stdHandles[1]; jobject chan = (*env)->NewObject(env, channelClass, channelConstructor, (jlong)stdHandles[i]);
file_handles[2] = (int)stdHandles[2]; (*env)->SetObjectArrayElement(env, channels, i, chan);
(*env)->SetIntArrayRegion(env, channels, 0, 3, (jint *)file_handles); }
// do the cleanup so launch the according thread // do the cleanup so launch the according thread
// create a copy of the PROCESS_INFORMATION as this might get destroyed // create a copy of the PROCESS_INFORMATION as this might get destroyed

View file

@ -29,20 +29,39 @@ void ThrowByName(JNIEnv *env, const char *name, const char *msg);
#define BUFF_SIZE (1024) #define BUFF_SIZE (1024)
static HANDLE channelToHandle(JNIEnv * env, jobject channel)
{
if (channel == 0) {
ThrowByName(env, "java/io/IOException", "Invalid channel object");
return NULL;
}
jclass cls = (*env)->GetObjectClass(env, channel);
if (cls == NULL) {
ThrowByName(env, "java/io/IOException", "Unable to get channel class");
return NULL;
}
jfieldID fid = (*env)->GetFieldID(env, cls, "handle", "J");
if (fid == NULL) {
ThrowByName(env, "java/io/IOException", "Unable to find handle");
return NULL;
}
jlong handle = (*env)->GetLongField(env, channel, fid);
return (HANDLE)handle;
}
/* Inaccessible static: skipBuffer */ /* Inaccessible static: skipBuffer */
/*
* Class: SpawnerInputStream
* Method: read0
* Signature: (I)I
*/
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
#endif #endif
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_read0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_read0
(JNIEnv * env, jobject proc, jint fd, jbyteArray buf, jint len) (JNIEnv * env, jobject proc, jobject channel, jbyteArray buf, jint len)
{ {
jbyte tmpBuf[BUFF_SIZE]; jbyte tmpBuf[BUFF_SIZE];
int nBuffOffset = 0; int nBuffOffset = 0;
HANDLE handle = channelToHandle(env, channel);
#ifdef DEBUG_MONITOR #ifdef DEBUG_MONITOR
_TCHAR buffer[1000]; _TCHAR buffer[1000];
#endif #endif
@ -84,7 +103,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_rea
{ {
DWORD nNumberOfBytesToRead = min(len - nBuffOffset, BUFF_SIZE); DWORD nNumberOfBytesToRead = min(len - nBuffOffset, BUFF_SIZE);
DWORD nNumberOfBytesRead; DWORD nNumberOfBytesRead;
if(0 == ReadFile((HANDLE)fd, tmpBuf, nNumberOfBytesToRead, &nNumberOfBytesRead, &overlapped )) if(0 == ReadFile(handle, tmpBuf, nNumberOfBytesToRead, &nNumberOfBytesRead, &overlapped ))
{ {
int err = GetLastError(); int err = GetLastError();
@ -92,7 +111,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_rea
{ {
// asynchronous i/o is still in progress // asynchronous i/o is still in progress
// check on the results of the asynchronous read // check on the results of the asynchronous read
if(GetOverlappedResult((HANDLE)fd, &overlapped, if(GetOverlappedResult(handle, &overlapped,
&nNumberOfBytesRead, TRUE)) &nNumberOfBytesRead, TRUE))
err = 0; err = 0;
// if there was a problem ... // if there was a problem ...
@ -151,7 +170,7 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_rea
{ {
// Is there data left in the pipe? // Is there data left in the pipe?
DWORD bytesAvailable = 0; DWORD bytesAvailable = 0;
if (!PeekNamedPipe((HANDLE)fd, NULL, 0, NULL, &bytesAvailable, NULL) if (!PeekNamedPipe(handle, NULL, 0, NULL, &bytesAvailable, NULL)
|| bytesAvailable == 0) || bytesAvailable == 0)
// No bytes left // No bytes left
break; break;
@ -168,24 +187,20 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_rea
} }
/*
* Class: SpawnerInputStream
* Method: close0
* Signature: (I)I
*/
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
#endif #endif
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0
(JNIEnv * env, jobject proc, jint fd) (JNIEnv * env, jobject proc, jobject channel)
{ {
int rc; int rc;
HANDLE handle = channelToHandle(env, channel);
#ifdef DEBUG_MONITOR #ifdef DEBUG_MONITOR
_TCHAR buffer[1000]; _TCHAR buffer[1000];
_stprintf(buffer, _T("Close %i\n"), fd); _stprintf(buffer, _T("Close %i\n"), fd);
OutputDebugStringW(buffer); OutputDebugStringW(buffer);
#endif #endif
rc = (CloseHandle((HANDLE)fd) ? 0 : -1); rc = (CloseHandle(handle) ? 0 : -1);
#ifdef DEBUG_MONITOR #ifdef DEBUG_MONITOR
_stprintf(buffer, _T("Closed %i\n"), fd); _stprintf(buffer, _T("Closed %i\n"), fd);
OutputDebugStringW(buffer); OutputDebugStringW(buffer);
@ -197,38 +212,34 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_clo
extern "C" extern "C"
#endif #endif
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_available0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_available0
(JNIEnv * env, jobject proc, jint fd) (JNIEnv * env, jobject proc, jobject channel)
{ {
DWORD nAvail = 0; DWORD nAvail = 0;
HANDLE handle = channelToHandle(env, channel);
if (0 == PeekNamedPipe((HANDLE)fd, NULL, 0, NULL, &nAvail, NULL)) { if (0 == PeekNamedPipe(handle, NULL, 0, NULL, &nAvail, NULL)) {
// error // error
return 0; return 0;
} }
return nAvail; return nAvail;
} }
/*
* Class: SpawnerOutputStream
* Method: write0
* Signature: (I[BI)I
*/
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
#endif #endif
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_write0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_write0
(JNIEnv * env, jobject proc, jint fd, jbyteArray buf, jint len) (JNIEnv * env, jobject proc, jobject channel, jbyteArray buf, jint len)
{ {
jbyte tmpBuf[BUFF_SIZE]; jbyte tmpBuf[BUFF_SIZE];
int nBuffOffset = 0; int nBuffOffset = 0;
HANDLE handle = channelToHandle(env, channel);
while(len > nBuffOffset) while(len > nBuffOffset)
{ {
DWORD nNumberOfBytesToWrite = min(len - nBuffOffset, BUFF_SIZE); DWORD nNumberOfBytesToWrite = min(len - nBuffOffset, BUFF_SIZE);
DWORD nNumberOfBytesWritten; DWORD nNumberOfBytesWritten;
(*env)->GetByteArrayRegion(env, buf, nBuffOffset, nNumberOfBytesToWrite, tmpBuf); (*env)->GetByteArrayRegion(env, buf, nBuffOffset, nNumberOfBytesToWrite, tmpBuf);
if(0 == WriteFile((HANDLE)fd, tmpBuf, nNumberOfBytesToWrite, &nNumberOfBytesWritten, NULL)) if(0 == WriteFile(handle, tmpBuf, nNumberOfBytesToWrite, &nNumberOfBytesWritten, NULL))
{ {
char * lpMsgBuf; char * lpMsgBuf;
FormatMessage( FormatMessage(
@ -252,25 +263,21 @@ JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_wr
return 0; return 0;
} }
/*
* Class: SpawnerOutputStream
* Method: close0
* Signature: (I)I
*/
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
#endif #endif
JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0 JNIEXPORT jint JNICALL Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0
(JNIEnv * env, jobject proc, jint fd) (JNIEnv * env, jobject proc, jobject channel)
{ {
int rc; int rc;
HANDLE handle = channelToHandle(env, channel);
#ifdef DEBUG_MONITOR #ifdef DEBUG_MONITOR
_TCHAR buffer[1000]; _TCHAR buffer[1000];
_stprintf(buffer, _T("Close %i\n"), fd); _stprintf(buffer, _T("Close %i\n"), fd);
OutputDebugStringW(buffer); OutputDebugStringW(buffer);
#endif #endif
FlushFileBuffers((HANDLE)fd); FlushFileBuffers(handle);
rc = (CloseHandle((HANDLE)fd) ? 0 : -1); rc = (CloseHandle(handle) ? 0 : -1);
#ifdef DEBUG_MONITOR #ifdef DEBUG_MONITOR
_stprintf(buffer, _T("Closed %i\n"), fd); _stprintf(buffer, _T("Closed %i\n"), fd);
OutputDebugStringW(buffer); OutputDebugStringW(buffer);

View file

@ -20,6 +20,7 @@ import java.io.IOException;
import org.eclipse.cdt.internal.core.natives.CNativePlugin; import org.eclipse.cdt.internal.core.natives.CNativePlugin;
import org.eclipse.cdt.internal.core.natives.Messages; import org.eclipse.cdt.internal.core.natives.Messages;
import org.eclipse.cdt.utils.spawner.Spawner; import org.eclipse.cdt.utils.spawner.Spawner;
import org.eclipse.cdt.utils.spawner.Spawner.IChannel;
import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Platform;
/** /**
@ -223,7 +224,8 @@ public class PTY {
* @noreference This method is not intended to be referenced by clients. * @noreference This method is not intended to be referenced by clients.
* @since 5.6 * @since 5.6
*/ */
public int exec_pty(Spawner spawner, String[] cmdarray, String[] envp, String dir, int[] chan) throws IOException { public int exec_pty(Spawner spawner, String[] cmdarray, String[] envp, String dir, IChannel[] chan)
throws IOException {
if (isWinPTY) { if (isWinPTY) {
return exec2(cmdarray, envp, dir, chan, slave, master, console); return exec2(cmdarray, envp, dir, chan, slave, master, console);
} else { } else {
@ -250,7 +252,7 @@ public class PTY {
/** /**
* Native method when executing with a terminal emulation (winpty only). * Native method when executing with a terminal emulation (winpty only).
*/ */
native int exec2(String[] cmdarray, String[] envp, String dir, int[] chan, String slaveName, int masterFD, native int exec2(String[] cmdarray, String[] envp, String dir, IChannel[] chan, String slaveName, int masterFD,
boolean console) throws IOException; boolean console) throws IOException;
/** /**

View file

@ -65,7 +65,7 @@ public class Spawner extends Process {
int pid = 0; int pid = 0;
int status; int status;
final int[] fChannels = { -1, -1, -1 }; final IChannel[] fChannels = { null, null, null };
boolean isDone; boolean isDone;
OutputStream out; OutputStream out;
InputStream in; InputStream in;
@ -363,7 +363,7 @@ public class Spawner extends Process {
Reaper reaper = new Reaper(cmdarray, envp, dirpath) { Reaper reaper = new Reaper(cmdarray, envp, dirpath) {
@Override @Override
int execute(String[] cmd, String[] env, String dir, int[] channels) throws IOException { int execute(String[] cmd, String[] env, String dir, IChannel[] channels) throws IOException {
return pty.exec_pty(Spawner.this, cmd, env, dir, channels); return pty.exec_pty(Spawner.this, cmd, env, dir, channels);
} }
@ -429,7 +429,7 @@ public class Spawner extends Process {
/** /**
* Native method use in normal exec() calls. * Native method use in normal exec() calls.
*/ */
native int exec0(String[] cmdarray, String[] envp, String dir, int[] chan) throws IOException; native int exec0(String[] cmdarray, String[] envp, String dir, IChannel[] chan) throws IOException;
/** /**
* Native method use in no redirect meaning to streams will created. * Native method use in no redirect meaning to streams will created.
@ -440,8 +440,8 @@ public class Spawner extends Process {
* Native method when executing with a terminal emulation. * Native method when executing with a terminal emulation.
* @noreference This method is not intended to be referenced by clients. * @noreference This method is not intended to be referenced by clients.
*/ */
public native int exec2(String[] cmdarray, String[] envp, String dir, int[] chan, String slaveName, int masterFD, public native int exec2(String[] cmdarray, String[] envp, String dir, IChannel[] chan, String slaveName,
boolean console) throws IOException; int masterFD, boolean console) throws IOException;
/** /**
* Native method to drop a signal on the process with pid. * Native method to drop a signal on the process with pid.
@ -464,6 +464,34 @@ public class Spawner extends Process {
} }
} }
/**
* @since 6.0
*/
public static interface IChannel {
}
/**
* @since 6.0
*/
public static class WinChannel implements IChannel {
final long handle;
public WinChannel(long handle) {
this.handle = handle;
}
}
/**
* @since 6.0
*/
public static class UnixChannel implements IChannel {
final int fd;
public UnixChannel(int fd) {
this.fd = fd;
}
}
// Spawn a thread to handle the forking and waiting // Spawn a thread to handle the forking and waiting
// We do it this way because on linux the SIGCHLD is // We do it this way because on linux the SIGCHLD is
// send to the one thread. So do the forking and // send to the one thread. So do the forking and
@ -482,7 +510,7 @@ public class Spawner extends Process {
fException = null; fException = null;
} }
int execute(String[] cmdarray, String[] envp, String dir, int[] channels) throws IOException { int execute(String[] cmdarray, String[] envp, String dir, IChannel[] channels) throws IOException {
return exec0(cmdarray, envp, dir, channels); return exec0(cmdarray, envp, dir, channels);
} }

View file

@ -18,16 +18,17 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import org.eclipse.cdt.internal.core.natives.Messages; import org.eclipse.cdt.internal.core.natives.Messages;
import org.eclipse.cdt.utils.spawner.Spawner.IChannel;
class SpawnerInputStream extends InputStream { class SpawnerInputStream extends InputStream {
private int fd; private IChannel channel;
/** /**
* From a Unix valid file descriptor set a Reader. * From a Unix valid file descriptor set a Reader.
* @param fd file descriptor. * @param fd file descriptor.
*/ */
public SpawnerInputStream(int fd) { public SpawnerInputStream(IChannel channel) {
this.fd = fd; this.channel = channel;
} }
/** /**
@ -48,7 +49,7 @@ class SpawnerInputStream extends InputStream {
*/ */
@Override @Override
public int read(byte[] buf, int off, int len) throws IOException { public int read(byte[] buf, int off, int len) throws IOException {
if (fd == -1) { if (channel == null) {
return -1; return -1;
} }
if (buf == null) { if (buf == null) {
@ -60,7 +61,7 @@ class SpawnerInputStream extends InputStream {
} }
byte[] tmpBuf = off > 0 ? new byte[len] : buf; byte[] tmpBuf = off > 0 ? new byte[len] : buf;
len = read0(fd, tmpBuf, len); len = read0(channel, tmpBuf, len);
if (len <= 0) if (len <= 0)
return -1; return -1;
@ -76,21 +77,21 @@ class SpawnerInputStream extends InputStream {
*/ */
@Override @Override
public void close() throws IOException { public void close() throws IOException {
if (fd == -1) if (channel == null)
return; return;
int status = close0(fd); int status = close0(channel);
if (status == -1) if (status == -1)
throw new IOException(Messages.Util_exception_closeError); throw new IOException(Messages.Util_exception_closeError);
fd = -1; channel = null;
} }
@Override @Override
public int available() throws IOException { public int available() throws IOException {
if (fd == -1) { if (channel == null) {
return 0; return 0;
} }
try { try {
return available0(fd); return available0(channel);
} catch (UnsatisfiedLinkError e) { } catch (UnsatisfiedLinkError e) {
// for those platforms that do not implement available0 // for those platforms that do not implement available0
return super.available(); return super.available();
@ -102,11 +103,11 @@ class SpawnerInputStream extends InputStream {
close(); close();
} }
private native int read0(int fileDesc, byte[] buf, int len) throws IOException; private native int read0(IChannel channel, byte[] buf, int len) throws IOException;
private native int close0(int fileDesc) throws IOException; private native int close0(IChannel channel) throws IOException;
private native int available0(int fileDesc) throws IOException; private native int available0(IChannel channel) throws IOException;
static { static {
System.loadLibrary("spawner"); //$NON-NLS-1$ System.loadLibrary("spawner"); //$NON-NLS-1$

View file

@ -16,19 +16,22 @@ package org.eclipse.cdt.utils.spawner;
import java.io.IOException; import java.io.IOException;
import java.io.OutputStream; import java.io.OutputStream;
import org.eclipse.cdt.utils.spawner.Spawner.IChannel;
/** /**
* @noextend This class is not intended to be subclassed by clients. * @noextend This class is not intended to be subclassed by clients.
* @noinstantiate This class is not intended to be instantiated by clients. * @noinstantiate This class is not intended to be instantiated by clients.
*/ */
public class SpawnerOutputStream extends OutputStream { public class SpawnerOutputStream extends OutputStream {
private int fd; private IChannel channel;
/** /**
* From a Unix valid file descriptor set a Reader. * From a Unix valid file descriptor set a Reader.
* @param fd file descriptor. * @param channel file descriptor.
* @since 6.0
*/ */
public SpawnerOutputStream(int fd) { public SpawnerOutputStream(IChannel channel) {
this.fd = fd; this.channel = channel;
} }
/** /**
@ -45,7 +48,7 @@ public class SpawnerOutputStream extends OutputStream {
} }
byte[] tmpBuf = new byte[len]; byte[] tmpBuf = new byte[len];
System.arraycopy(b, off, tmpBuf, off, len); System.arraycopy(b, off, tmpBuf, off, len);
write0(fd, tmpBuf, len); write0(channel, tmpBuf, len);
} }
/** /**
@ -66,12 +69,12 @@ public class SpawnerOutputStream extends OutputStream {
*/ */
@Override @Override
public void close() throws IOException { public void close() throws IOException {
if (fd == -1) if (channel == null)
return; return;
int status = close0(fd); int status = close0(channel);
if (status == -1) if (status == -1)
throw new IOException("close error"); //$NON-NLS-1$ throw new IOException("close error"); //$NON-NLS-1$
fd = -1; channel = null;
} }
@Override @Override
@ -79,9 +82,9 @@ public class SpawnerOutputStream extends OutputStream {
close(); close();
} }
private native int write0(int fd, byte[] b, int len) throws IOException; private native int write0(IChannel channel, byte[] b, int len) throws IOException;
private native int close0(int fd); private native int close0(IChannel channel);
static { static {
System.loadLibrary("spawner"); //$NON-NLS-1$ System.loadLibrary("spawner"); //$NON-NLS-1$