blob: 7415961a43f0cfb2f969ad1358901a8def14b858 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2002, 2009 QNX Software Systems and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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)
*******************************************************************************/
#include <string.h>
#include <stdlib.h>
#include <jni.h>
#include <windows.h>
#include "util.h"
#include "org_eclipse_cdt_utils_spawner_Spawner.h"
void ThrowByName(JNIEnv *env, const char *name, const char *msg);
#define BUFF_SIZE (1024)
static HANDLE channelToHandle(JNIEnv *env, jobject channel) {
if (!channel) {
ThrowByName(env, "java/io/IOException", "Invalid channel object");
return NULL;
}
jclass cls = (*env)->GetObjectClass(env, channel);
if (!cls) {
ThrowByName(env, "java/io/IOException", "Unable to get channel class");
return NULL;
}
jfieldID fid = (*env)->GetFieldID(env, cls, "handle", "J");
if (!fid) {
ThrowByName(env, "java/io/IOException", "Unable to find handle");
return NULL;
}
jlong handle = (*env)->GetLongField(env, channel, fid);
return (HANDLE)handle;
}
/* Inaccessible static: skipBuffer */
#ifdef __cplusplus
extern "C"
#endif
JNIEXPORT jint JNICALL
Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_read0(JNIEnv *env, jobject proc, jobject channel,
jbyteArray buf, jint len) {
jbyte tmpBuf[BUFF_SIZE];
int nBuffOffset = 0;
HANDLE handle = channelToHandle(env, channel);
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 (!overlapped.hEvent) {
char *lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL,
GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(wchar_t *)&lpMsgBuf, 0, NULL);
ThrowByName(env, "java/io/IOException", lpMsgBuf);
// Free the buffer.
LocalFree(lpMsgBuf);
}
if (isTraceEnabled(CDT_TRACE_MONITOR) && isTraceEnabled(CDT_TRACE_READ_REPORT)) {
cdtTrace(L"Start read %p\n", handle);
}
while (len > nBuffOffset) {
DWORD nNumberOfBytesToRead = min(len - nBuffOffset, BUFF_SIZE);
DWORD nNumberOfBytesRead;
if (0 == ReadFile(handle, tmpBuf, nNumberOfBytesToRead, &nNumberOfBytesRead, &overlapped)) {
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, &overlapped, &nNumberOfBytesRead, TRUE)) {
err = 0;
} else { // if there was a problem ...
err = GetLastError();
}
}
if (err == ERROR_BROKEN_PIPE) { // Pipe was closed
break;
}
if (err != 0) {
char *lpMsgBuf;
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Read failed - %p, error %i\n", handle, err);
}
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
(wchar_t *)&lpMsgBuf, 0, NULL);
ThrowByName(env, "java/io/IOException", lpMsgBuf);
LocalFree(lpMsgBuf);
nBuffOffset = 0;
break;
} else {
// buffer overflow?
// according to msdn this happens in message read mode only
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Buffer full - %p, bytes read: %i\n", handle, nNumberOfBytesRead);
}
// nNumberOfBytesRead can be 0 here for unknown reason (bug 269223)
nNumberOfBytesRead = nNumberOfBytesToRead;
}
}
}
if (nNumberOfBytesRead > 0) {
(*env)->SetByteArrayRegion(env, buf, nBuffOffset, nNumberOfBytesRead, tmpBuf);
} else {
break;
}
nBuffOffset += nNumberOfBytesRead;
if (nNumberOfBytesRead != nNumberOfBytesToRead) {
break;
} else {
// Is there data left in the pipe?
DWORD bytesAvailable = 0;
if (!PeekNamedPipe(handle, NULL, 0, NULL, &bytesAvailable, NULL) || bytesAvailable == 0) {
// No bytes left
break;
}
}
}
CloseHandle(overlapped.hEvent);
if (isTraceEnabled(CDT_TRACE_MONITOR) && isTraceEnabled(CDT_TRACE_READ_REPORT)) {
cdtTrace(L"End read %p - bytes read: %d\n", handle, nBuffOffset);
}
return nBuffOffset; // This is a real full readed length
}
#ifdef __cplusplus
extern "C"
#endif
JNIEXPORT jint JNICALL
Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_close0(JNIEnv *env, jobject proc, jobject channel) {
int rc;
HANDLE handle = channelToHandle(env, channel);
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Close %p\n", handle);
}
rc = (CloseHandle(handle) ? 0 : -1);
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Closed %p\n", handle);
}
return (rc ? GetLastError() : 0);
}
#ifdef __cplusplus
extern "C"
#endif
JNIEXPORT jint JNICALL
Java_org_eclipse_cdt_utils_spawner_SpawnerInputStream_available0(JNIEnv *env, jobject proc, jobject channel) {
DWORD nAvail = 0;
HANDLE handle = channelToHandle(env, channel);
if (0 == PeekNamedPipe(handle, NULL, 0, NULL, &nAvail, NULL)) {
// error
return 0;
}
return nAvail;
}
#ifdef __cplusplus
extern "C"
#endif
JNIEXPORT jint JNICALL
Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_write0(JNIEnv *env, jobject proc, jobject channel,
jbyteArray buf, jint len) {
jbyte tmpBuf[BUFF_SIZE];
int nBuffOffset = 0;
HANDLE handle = channelToHandle(env, channel);
while (len > nBuffOffset) {
DWORD nNumberOfBytesToWrite = min(len - nBuffOffset, BUFF_SIZE);
DWORD nNumberOfBytesWritten;
(*env)->GetByteArrayRegion(env, buf, nBuffOffset, nNumberOfBytesToWrite, tmpBuf);
if (0 == WriteFile(handle, tmpBuf, nNumberOfBytesToWrite, &nNumberOfBytesWritten, NULL)) {
char *lpMsgBuf;
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
(wchar_t *)&lpMsgBuf, 0, NULL);
ThrowByName(env, "java/io/IOException", lpMsgBuf);
LocalFree(lpMsgBuf);
return 0;
}
nBuffOffset += nNumberOfBytesWritten;
}
return 0;
}
#ifdef __cplusplus
extern "C"
#endif
JNIEXPORT jint JNICALL
Java_org_eclipse_cdt_utils_spawner_SpawnerOutputStream_close0(JNIEnv *env, jobject proc, jobject channel) {
int rc;
HANDLE handle = channelToHandle(env, channel);
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Close %p\n", handle);
}
FlushFileBuffers(handle);
rc = (CloseHandle(handle) ? 0 : -1);
if (isTraceEnabled(CDT_TRACE_MONITOR)) {
cdtTrace(L"Closed %p\n", handle);
}
return (rc ? GetLastError() : 0);
}