/*
* Copyright 2009-2010 Shashank Tulsyan
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* File: jpfmMount.cpp
* Author: Shashank Tulsyan
*/
#include <string.h>
#include "jpfm.h"
#include "JPfmConcurrent.h"
#include "Opmethodidinitializer.h"
//#include "include/traces.h"
//const int fileErrorNotImplemented = ERROR_CALL_NOT_IMPLEMENTED;
#ifndef WINAPI
#define WINAPI
#endif
#ifdef _WIN32
////////////////WIN//////////////////
const int fileErrorNotImplemented = ERROR_CALL_NOT_IMPLEMENTED;
DWORD WINAPI mountingThread(LPVOID lpParam);
DWORD WINAPI mountingThreadForConcurrentFS(LPVOID lpParam);
#else
//#ifdef __APPLE__
////////////////MAC//////////////////
//#else
////////////////LINUX//////////////////
const int fileErrorNotImplemented = ENOSYS;
void * mountingThread(void* lpParam);
void * mountingThreadForConcurrentFS(void* lpParam);
//#endif
#endif
#define USE_FAST_PIPE
PfmApi * pfmapi;
JavaVM * jvm;
int jvmInitialized;
int initiatedByNative;
HANDLE FORMATTER_READ;
HANDLE FORMATTER_WRITE;
JNIEnv *mainThread;
const char * THREAD_NAME = "JPfm Native Thread";
//jmethodID FileDescriptor_constructor;
//jmethodID FormatterEvent_constructor;
#ifdef _WIN32
#define USE_FAST_PIPE
#endif
inline void attachAndMessageC(
jint attachResult,
JPfmFormatterDispatch * formatterDispatch,
char * threadName,
int jpfmMessageType,
char * message,
char * filename,
int lineNumber,
INT64 systemError){
attachResult = 0 ;
JNIEnv *env;
if(formatterDispatch->noListenerAttached)return;
attachResult = jvm->AttachCurrentThreadAsDaemon(
(void **)&env,
formatterDispatch->createAttachArgs(threadName));
if(attachResult >= 0){
formatterDispatch->messageFormatterListener(env,
jpfmMessageType,
message,
filename,
lineNumber,
systemError,
formatterDispatch->jpfmMount
);
jvm->DetachCurrentThread();
}else{
printf("attach to java failed in %s at linenumber %i ",__FILE__,__LINE__);
}
}
inline void attachAndMessage(
jint attachResult,
JPfmReadOnlyFormatterDispatch * formatterDispatch,
char * threadName,
int jpfmMessageType,
char * message,
char * filename,
int lineNumber,
INT64 systemError){
attachResult = 0 ;
JNIEnv *env;
if(formatterDispatch->noListenerAttached)return;
attachResult = jvm->AttachCurrentThreadAsDaemon(
(void **)&env,
formatterDispatch->createAttachArgs((char *)threadName));
if(attachResult >= 0){
formatterDispatch->messageFormatterListener(env,
jpfmMessageType,
message,
filename,
lineNumber,
systemError,
formatterDispatch->jpfmMount
);
jvm->DetachCurrentThread();
}else{
printf("attach to java failed in %s at linenumber %i ",__FILE__,__LINE__);
}
}
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *JVM, void *reserved) {
if (jvm != JVM) {
jvm = JVM;
jvmInitialized = true;
initiatedByNative = false;
mainThread = 0;
}
return JNI_VERSION_IN_USE;
}
JNIEXPORT void JNICALL
JNI_OnUnload(JavaVM *JVM, void *reserved) {
if (!IsBadReadPointer(pfmapi, sizeof (PfmApi))) {
if (pfmapi)pfmapi->Release();
pfmapi = 0;
}jvmInitialized = false;
}
JNIEXPORT jlong JNICALL Java_jpfm_JPfmMount_getPismoVersion
(JNIEnv *env, jclass clazz){
return (jlong)(pfmapi);
}
JNIEXPORT jlong JNICALL Java_jpfm_JPfmMount_getMyProcessId
(JNIEnv *env, jclass clazz){
#ifdef _WIN32
return GetCurrentProcessId();
#else
return getpid();
#endif
}
JNIEXPORT jboolean JNICALL
Java_jpfm_JPfmMount_isAlive(JNIEnv *env, jobject self, jlong formatterHandle) {
JPfmReadOnlyFormatterDispatch * formatter = getFormatter(formatterHandle);
if (!isFormatterPointerValid(formatter))return JNI_FALSE;
return (jboolean) formatter->isAlive;
}
JNIEXPORT jstring JNICALL
Java_jpfm_JPfmMount_convertErrorCodeToString(JNIEnv *env, jclass self, jlong errorCode){
jstring jmessage;
#ifdef _WIN32
// DWORD WINAPI FormatMessage(
// __in DWORD dwFlags,
// __in_opt LPCVOID lpSource,
// __in DWORD dwMessageId,
// __in DWORD dwLanguageId,
// __out LPTSTR lpBuffer,
// __in DWORD nSize,
// __in_opt va_list *Arguments
//);
int size = 100+1;
wchar_t * mesbuf = new wchar_t[size];
int messSz = 0;
messSz = FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
(DWORD)errorCode,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
mesbuf,
size,
NULL
);
if(messSz>0){
jmessage = toJavaString(env,mesbuf,messSz);
}else{
jmessage = env->NewStringUTF((const char *)" Could not convert system error to string ");
}delete mesbuf;
return jmessage;
#else //works for linux and mac
jmessage = env->NewStringUTF((const char *)strerror((int)errorCode));
return jmessage;
#endif
}
JNIEXPORT jint JNICALL
Java_jpfm_JPfmMount_unMountAndRelease(JNIEnv *env, jobject self, jlong formatterHandle) {
JPfmReadOnlyFormatterDispatch * formatterDispatch = getFormatter(formatterHandle);
if (!isFormatterPointerValid(formatterDispatch))return -1*(__LINE__);
int error = 0;
if(formatterDispatch->isAlive){
formatterDispatch->isAlive = false; // when unmount is done externally,
// this value is still true, can be used to check if unmount was done externally
error = formatterDispatch->pfmmount->Unmount(pfmUnmountFlagForce);
}
return error;
}
JNIEXPORT void JNICALL
Java_jpfm_JPfmMount_destroyAll(JNIEnv *env, jclass clazz) {
if (!IsBadReadPointer(pfmapi, sizeof (PfmApi))) {
return;
}
PFM_INT64 startChangeInstance = 0;
PFM_INT64 nextChangeInstance = startChangeInstance;
PfmIterator* pfmiterator;
PfmMount* pfmMount;
int mountId = 0;
if (
!pfmapi->MountIterate(startChangeInstance, &nextChangeInstance, &pfmiterator)
) {
for (
mountId = pfmiterator->Next(&nextChangeInstance);
mountId != 0;
mountId = pfmiterator->Next(&nextChangeInstance)
) {
if (
!pfmapi->MountOpenId(mountId, &pfmMount)
) {
pfmMount->Unmount(0);
pfmMount->Release();
pfmMount = 0;
}
}
pfmiterator->Release();
} else {
}
//pfmapi->Release();
return;
}
JNIEXPORT jint JNICALL
Java_jpfm_JPfmMount_createJPfmApi(JNIEnv *env, jclass clazz) {
/*JNIEnv *env;
JavaVMAttachArgs * args = new JavaVMAttachArgs();
args->group = NULL;
args->version = JNI_VERSION_IN_USE;
args->name = "JPfm methodId intializer (native)";
jint attachResult = jvm->AttachCurrentThreadAsDaemon((void **) & env, args);
if(attachResult < 0){
return JNI_ERR;
}
printf("going to initialize \n");
initializeMethodId(env);
jvm->DetachCurrentThread();*/
if(!jvmInitialized){
env->GetJavaVM(&jvm);
jvmInitialized = true;
//printf("Unexpected behaviour : JNI_ON_LOAD_WAS_NOT_CALLED!\n");
}
int error = !(initializeMethodId(env));
/*FileDescriptor_constructor = env->GetMethodID(FileDescriptor_class, "<init>", "()V");
if(FileDescriptor_constructor==NULL)error = true;
FormatterEvent_constructor = env->GetMethodID(FormatterEvent_class, "<init>", "(ILjava/lang/String;)V");
if(FormatterEvent_constructor==NULL)error = true;*/
if(error){
printf("Some classes of jpfm are missing or incorrectly defined\n");
return 1;
}
error = !(initializeOpMethodId(env));
if(error){
printf("Some classes of concurrent filesystem in jpfm are missing or incorrectly defined\n");
return 1;
}
error = PfmApiFactory(&pfmapi);
if(error)printf("Error initializing pfmapi, error=%i\n",error);
if(error)return 2; //pismo has not been installed
return 0;
}
JNIEXPORT jlong JNICALL
Java_jpfm_JPfmMount_mountNewReadOnly(
JNIEnv *env,
jobject jpfmMount,
jobject jpfmReadOnlyFileSystem,
jstring mountLocation,
jobject rootDirectory,
jobject formatterListener,
jobject threadGroup,
jstring formatterName,
jint jpfmSuppliedMountFlag,
jint visibleProcessId) {
//all null checks have been done by the java side code
JPfmReadOnlyFormatterDispatch * formatter =
new JPfmReadOnlyFormatterDispatch(
env->NewGlobalRef(jpfmReadOnlyFileSystem),
env->NewGlobalRef(rootDirectory),
env->NewGlobalRef(formatterListener),
env->NewGlobalRef(threadGroup)
);
if( env->IsSameObject(formatter->formatterListener,NULL) == JNI_FALSE )
formatter->noListenerAttached = false;
else formatter->noListenerAttached = true;
formatter->mountFileName = makeALocalCopyOfString(env, mountLocation);
formatter->jpfmSuppliedMountFlag = jpfmSuppliedMountFlag;
formatter->formattername = makeALocalUTFCopyOfString(env, formatterName);
formatter->jpfmMount = env->NewGlobalRef(jpfmMount);
//correct processid here itself, because it from here that it will be passed
//everywhere
if(visibleProcessId==-2) { // impylies process id of myself
#ifdef _WIN32
formatter->visibleProcessId = GetCurrentProcessId();
#else
formatter->visibleProcessId = getpid();
//docs says getpid shall never be unsuccessfull and no value exists to
//indicate a failure.
//Assuming the same for GetCurrentProcessId
#endif
} else {
formatter->visibleProcessId = visibleProcessId;
}
if(initiatedByNative){
mountingThread((void*)formatter);
return 0;//formatter is never passed to java side
} else {
#ifdef _WIN32
////////////////WIN//////////////////
DWORD dwThreadId;
formatter->hThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
(LPTHREAD_START_ROUTINE) mountingThread, // thread function
formatter, // argument to thread function
0, // use default creation flags
&dwThreadId);
#else
#ifdef __APPLE__
//////////////////MAC/////////////////////////
pthread_attr_t attr;
int returnVal;
returnVal = pthread_attr_init(&attr);
//assert(!returnVal);
returnVal = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
//assert(!returnVal);
#endif
// works on both mac and linux
int thread_ret;
pthread_t mountingThread_pthread_t;
thread_ret = formatter->hThread = pthread_create(
&mountingThread_pthread_t,
#ifdef __APPLE__
&attr
#else
NULL
#endif
,mountingThread,
(void*)formatter);
#endif
}
//DWORD waitResult = WaitForSingleObject(formatter->hThread,10000);
/*DWORD waitResult = WaitForSingleObject(formatter->hThread,INFINITE);
if(waitResult==WAIT_FAILED){
printf("volume mounting thread failed wait failed\n");
}
if(waitResult==WAIT_TIMEOUT){
printf("volume mounting thread failed wait timeout\n");
}*/
return (jlong) formatter;
}
JNIEXPORT jlong JNICALL
Java_jpfm_JPfmMount_mountNewConcurrent(
JNIEnv *env,
jobject jpfmMount,
jobject jpfmFileSystem,
jstring mountLocation,
jchar driveLetter,
jobject formatterListener,
jobject threadGroup,
jstring formatterName,
jint jpfmSuppliedMountFlag,
jint volumeFlags,
jint visibleProcessId) {
//all null checks have been done by the java side code
JPfmFormatterDispatch * formatter =
new JPfmFormatterDispatch(
env->NewGlobalRef(jpfmFileSystem),
env->NewGlobalRef(formatterListener),
env->NewGlobalRef(threadGroup)
);
if( env->IsSameObject(formatter->formatterListener,NULL) == JNI_FALSE )
formatter->noListenerAttached = false;
else formatter->noListenerAttached = true;
formatter->mountFileName = makeALocalCopyOfString(env, mountLocation);
formatter->driveLetter = (wchar_t)driveLetter;
formatter->jpfmSuppliedMountFlag = jpfmSuppliedMountFlag;
formatter->volumeFlags = volumeFlags;
//correct processid here itself, because it from here that it will be passed
//everywhere
if(visibleProcessId==-2) { // impylies process id of myself
#ifdef _WIN32
formatter->visibleProcessId = GetCurrentProcessId();
#else
formatter->visibleProcessId = getpid();
//docs says getpid shall never be unsuccessfull and no value exists to
//indicate a failure.
//Assuming the same for GetCurrentProcessId
#endif
} else {
formatter->visibleProcessId = visibleProcessId;
}
formatter->formattername = makeALocalUTFCopyOfString(env, formatterName);
formatter->jpfmMount = env->NewGlobalRef(jpfmMount);
if(initiatedByNative){
mountingThreadForConcurrentFS((void*)formatter);
return 0;//formatter is never passed to java side
}else{
#ifdef _WIN32
////////////////WIN//////////////////
DWORD dwThreadId;
formatter->hThread = CreateThread(
NULL, // default security attributes
0, // use default stack size
(LPTHREAD_START_ROUTINE) mountingThreadForConcurrentFS, // thread function
formatter, // argument to thread function
0, // use default creation flags
&dwThreadId);
#else
//#ifdef __APPLE__
////////////////MAC//////////////////
//#else
////////////////LINUX//////////////////
//#endif
#endif
}
//DWORD waitResult = WaitForSingleObject(formatter->hThread,10000);
/*DWORD waitResult = WaitForSingleObject(formatter->hThread,INFINITE);
if(waitResult==WAIT_FAILED){
printf("volume mounting thread failed wait failed\n");
}
if(waitResult==WAIT_TIMEOUT){
printf("volume mounting thread failed wait timeout\n");
}*/
return (jlong) formatter;
}
#ifdef _WIN32
DWORD WINAPI mountingThread(LPVOID lpParam) {
#else
//#ifdef __APPLE__
////////////////MAC//////////////////
//#else
////////////////LINUX//////////////////
void * mountingThread(void* lpParam) {
//#endif
#endif
JPfmReadOnlyFormatterDispatch * formatterDispatch = (JPfmReadOnlyFormatterDispatch *) lpParam;
PfmMountCreateParams * mountCreateParams = new PfmMountCreateParams();
PfmMarshallerServeParams * marshallerServeParams = new PfmMarshallerServeParams();
PfmFastPipeCreateParams * fastPipeCreateParams = new PfmFastPipeCreateParams();
//fast pipe handles
PFM_HANDLE clientHandle = PFM_INVALIDHANDLE;
PFM_HANDLE serverHandle = PFM_INVALIDHANDLE;
//fast pipe
//to remove
PFM_HANDLE toFormatterRead = PFM_INVALIDHANDLE;
PFM_HANDLE toFormatterWrite = PFM_INVALIDHANDLE;
PFM_HANDLE fromFormatterRead = PFM_INVALIDHANDLE;
PFM_HANDLE fromFormatterWrite = PFM_INVALIDHANDLE;
//normal pipe handle
JNIEnv *env;
int error = 0;
jint attachResult = 0;
char * pipeErrorMess ;
// For communication between driver and formatter, use
// fastpipe if available. Fastpipe direct maps buffers
// into formatter address space, providing increased
// maximum throughput for high bandwidth file systems.
// Fastpipe also saves the marshaller from needing to
// create an extra "write" thread.
#ifdef USE_FAST_PIPE
pipeErrorMess = "Could not create fast pipe";
#ifdef __APPLE__
error = fileErrorNotImplemented;
#else
memset(fastPipeCreateParams, 0, sizeof (PfmFastPipeCreateParams)); //t_memzero(&pcp);
fastPipeCreateParams->paramsSize = sizeof (PfmFastPipeCreateParams);
fastPipeCreateParams->fastPipeFlags = pfmFastPipeFlagFastMapping|
pfmFastPipeFlagAsyncClient|pfmFastPipeFlagAsyncServer;
error = pfmapi->FastPipeCreate(
fastPipeCreateParams,
&clientHandle, //driverEndHandle
&serverHandle //formatterEndHandle
);
#endif
pipeErrorMess = "Could not create fast pipe, trying to create and use normal pipe";
#else
pipeErrorMess = "Using normal pipe because USE_FAST_PIPE was not defined";
error = fileErrorNotImplemented; // testing normal pipe procedures
#endif
if(error)
attachAndMessage(
attachResult,
formatterDispatch,
(char *)THREAD_NAME,
JPFM_FORMATTER_EVENT_MESSAGE,
pipeErrorMess,
__FILE__,
__LINE__,
error);
if (error == fileErrorNotImplemented) {
// If no fastpipe then use a domain socket.
error = EFileCreateSocket(&clientHandle, &serverHandle);
pipeErrorMess = "Could not even create normal pipe";
}
if(error){
attachAndMessage(
attachResult,
formatterDispatch,
(char *)THREAD_NAME,
JPFM_FORMATTER_EVENT_ERROR,
pipeErrorMess,
__FILE__,
__LINE__,
error);
if (!IsBadWritePointer(formatterDispatch, sizeof (JPfmReadOnlyFormatterDispatch)))
delete formatterDispatch;
#ifdef _WIN32
return __LINE__;
#else
pthread_exit(NULL);
return NULL;
#endif
}
memset(mountCreateParams, 0, sizeof (PfmMountCreateParams));
/*mountCreateParams->mountFlags |= (
//pfmMountFlagUncOnly|
pfmMountFlagSystemVisible| pfmMountFlagWorldRead | pfmMountFlagReadOnly); */
mountCreateParams->mountFlags = 0;
mountCreateParams->mountFlags |= formatterDispatch->jpfmSuppliedMountFlag;
mountCreateParams->mountFileName = formatterDispatch->mountFileName;
mountCreateParams->visibleProcessId = formatterDispatch->visibleProcessId; ;// pfmVisibleProcessIdAll;
#ifdef USE_FAST_PIPE
mountCreateParams->toFormatterWrite = clientHandle;
mountCreateParams->fromFormatterRead = clientHandle;
#else
mountCreateParams->toFormatterWrite = toFormatterWrite;
mountCreateParams->fromFormatterRead = fromFormatterRead;
#endif
mountCreateParams->toAuthWrite = PFM_INVALIDHANDLE;
mountCreateParams->fromAuthRead = PFM_INVALIDHANDLE;
mountCreateParams->paramsSize = sizeof (PfmMountCreateParams);
error = pfmapi->MountCreate(mountCreateParams, &formatterDispatch->pfmmount);
if(error){
attachAndMessage(
attachResult,
formatterDispatch,
(char *)THREAD_NAME,
JPFM_FORMATTER_EVENT_MOUNT_CREATE_FAILED,
"Mounting was unsuccessful.",
__FILE__,
__LINE__,
error);
delete mountCreateParams;
delete fastPipeCreateParams;
if (!IsBadWritePointer(formatterDispatch, sizeof (JPfmReadOnlyFormatterDispatch)));
delete formatterDispatch;
#ifdef _WIN32
return error;
#else
pthread_exit(NULL);
return NULL;
#endif
}else{
attachResult = jvm->AttachCurrentThreadAsDaemon((void **)&env,formatterDispatch->createAttachArgs((char *)THREAD_NAME));
if(attachResult >=0){
env->CallVoidMethod(formatterDispatch->jpfmMount,JPfmMount_setMountId,(jlong)formatterDispatch->pfmmount->GetMountId());
jvm->DetachCurrentThread();
}
}
#ifdef USE_FAST_PIPE
FileClose(clientHandle);//this is a little modified than what we have for ramfs
clientHandle = PFM_INVALIDHANDLE;
#else
/* Close driver end pipe handles now. Driver has duplicated what
it needs. If these handles are not closed then pipes will not
break if driver disconnects, leaving us stuck in the
marshaller.
*/
FileClose(toFormatterWrite);
FileClose(fromFormatterRead);
#endif
memset(marshallerServeParams, 0, sizeof (PfmMarshallerServeParams));
marshallerServeParams->dispatch = formatterDispatch;
marshallerServeParams->paramsSize = sizeof (PfmMarshallerServeParams);
marshallerServeParams->formatterName = (const char *) formatterDispatch->formattername;
#ifdef USE_FAST_PIPE
marshallerServeParams->toFormatterRead = serverHandle;
marshallerServeParams->fromFormatterWrite = serverHandle;
#else
marshallerServeParams->toFormatterRead = toFormatterRead;
marshallerServeParams->fromFormatterWrite = fromFormatterWrite;
#endif
marshallerServeParams->volumeFlags = pfmVolumeFlagReadOnly;//files can be deleted
error = PfmMarshallerFactory(&formatterDispatch->marshaller);
if (error) {
attachAndMessage(
attachResult,
formatterDispatch,
(char *)THREAD_NAME,
JPFM_FORMATTER_EVENT_ERROR,
"Marshaller could not be created",
__FILE__,
__LINE__,
error);
delete mountCreateParams;
delete fastPipeCreateParams;
delete marshallerServeParams;
if (!IsBadWritePointer(formatterDispatch, sizeof (JPfmReadOnlyFormatterDispatch)));
delete formatterDispatch;
jvm->DetachCurrentThread();
#ifdef _WIN32
return __LINE__;
#else
pthread_exit(NULL);
return NULL;
#endif
}
//formatterDispatch->marshaller->SetStatus(GetStdHandle(STD_ERROR_HANDLE));
formatterDispatch->marshaller->SetTrace(formatterDispatch->mountFileName/*L"JPfm"*/);
//JNIEnv *env;
//char *nm = /*_strdup(*/"Formatter ServeDispatch thread";/*);*/
//printf("attaching %s\n",nm);
//jvm->AttachCurrentThread((void **)&env,formatter->createAttachArgs(nm));
//attaching thread is useless as the first method that
//is invoked after servedispatch is formatterDispatch's open method
//After finishing it 's work it kills the thread
//Checks can be added, but, even so, it cannot be said for sure
//if this thread will be used again. In such a case
//checks will have to be added everywhere, which might be a good
//thing because it seems all reside in the same thread.
//The classic method followed is going in a loop to read the driver requests
//so maybe this same thread is used. Yet again I wonder how
//this type of formatter is multithreaded
if(!formatterDispatch->noListenerAttached){
#ifdef __APPLE__
printf("Just going to dispatch formatter\n" );
#else
attachResult = jvm->AttachCurrentThreadAsDaemon((void **)&env,formatterDispatch->createAttachArgs((char *)THREAD_NAME));
if(attachResult >=0){
formatterDispatch->messageFormatterListener(env,
JPFM_FORMATTER_EVENT_MESSAGE,
"Just going to dispatch formatter.",0
);
jvm->DetachCurrentThread();
}
#endif
}
error = formatterDispatch->marshaller->ServeDispatch(marshallerServeParams);
if(!formatterDispatch->noListenerAttached){
if(error){
attachAndMessage(
attachResult,
formatterDispatch,
(char *)THREAD_NAME,
JPFM_FORMATTER_EVENT_ERROR,
"ServeDispatch returned with error",
__FILE__,
__LINE__,
error);
}
attachResult = jvm->AttachCurrentThreadAsDaemon((void **)&env,formatterDispatch->createAttachArgs((char *)THREAD_NAME));
if(attachResult >=0){
if(formatterDispatch->isAlive==true){
// if unmount was intiated by us, we set isAlive false,
formatterDispatch->messageFormatterListener(env,
JPFM_FORMATTER_EVENT_DETACHED,
"Some external tool might have initiated an unmount operation or and error might have occurred.",0);
}else /*we did it*/{
formatterDispatch->messageFormatterListener(env,
JPFM_FORMATTER_EVENT_DETACHED,
"Unmount intiated internally was successful",0);
}jvm->DetachCurrentThread();//this will detach the
}
}
// NULL);
//printf("served\n");
//separated by | oring
#ifdef USE_FAST_PIPE
if (serverHandle != PFM_INVALIDHANDLE){
FileClose(serverHandle);//CloseHandle(serverHandle);
}
#else
if(toFormatterRead != PFM_INVALIDHANDLE)
FileClose(toFormatterRead);
if(toFormatterRead != PFM_INVALIDHANDLE)
FileClose(fromFormatterWrite);
#endif
if(formatterDispatch->pfmmount){
//formatterDispatch->pfmmount->Release();
formatterDispatch->pfmmount = 0;
}
delete mountCreateParams;
delete marshallerServeParams;
delete fastPipeCreateParams;
if (!IsBadWritePointer(formatterDispatch, sizeof (JPfmReadOnlyFormatterDispatch)));
delete formatterDispatch;
#ifdef _WIN32
////////////////WIN//////////////////
return error;
#else
//#ifdef __APPLE__
////////////////MAC//////////////////
//#else
////////////////LINUX//////////////////
pthread_exit(NULL);
//#endif
#endif
}
#ifdef _WIN32
////////////////WIN//////////////////
DWORD WINAPI mountingThreadForConcurrentFS(LPVOID lpParam) {
#else
//#ifdef __APPLE__
////////////////MAC//////////////////
//#else
////////////////LINUX//////////////////
void * mountingThreadForConcurrentFS(void* lpParam) {
//#endif
#endif
JPfmFormatterDispatch * formatterDispatch = (JPfmFormatterDispatch *) lpParam;
PfmMountCreateParams * mountCreateParams = new PfmMountCreateParams();
PfmMarshallerServeParams * marshallerServeParams = new PfmMarshallerServeParams();
PfmFastPipeCreateParams * fastPipeCreateParams = new PfmFastPipeCreateParams();
PFM_HANDLE clientHandle = PFM_INVALIDHANDLE;
PFM_HANDLE serverHandle = PFM_INVALIDHANDLE;
//to remove
PFM_HANDLE toFormatterRead = PFM_INVALIDHANDLE;
PFM_HANDLE toFormatterWrite = PFM_INVALIDHANDLE;
PFM_HANDLE fromFormatterRead = PFM_INVALIDHANDLE;
PFM_HANDLE fromFormatterWrite = PFM_INVALIDHANDLE;
//normal pipe handle
JNIEnv *env;
int error = 0;
jint attachResult;
char * pipeErrorMess ;
// For communication between driver and formatter, use
// fastpipe if available. Fastpipe direct maps buffers
// into formatter address space, providing increased
// maximum throughput for high bandwidth file systems.
// Fastpipe also saves the marshaller from needing to
// create an extra "write" thread.
#ifdef USE_FAST_PIPE
pipeErrorMess = "Could not create fast pipe";
memset(fastPipeCreateParams, 0, sizeof (PfmFastPipeCreateParams)); //t_memzero(&pcp);
fastPipeCreateParams->paramsSize = sizeof (PfmFastPipeCreateParams);
fastPipeCreateParams->fastPipeFlags = pfmFastPipeFlagFastMapping|
pfmFastPipeFlagAsyncClient|pfmFastPipeFlagAsyncServer;
error = pfmapi->FastPipeCreate(
fastPipeCreateParams,
&clientHandle, //driverEndHandle
&serverHandle //formatterEndHandle
);
#else // use normal pipes
pipeErrorMess = "Using normal pipe as USE_FAST_PIPE is undefined";
error = fileErrorNotImplemented;
#endif
if (error == fileErrorNotImplemented) {
// If no fastpipe then use a domain socket.
error = EFileCreateSocket(&clientHandle, &serverHandle);
pipeErrorMess = "Could not even use EFileCreateSoket";
}
if(error){
attachAndMessageC(
attachResult,
formatterDispatch,
(char *)THREAD_NAME,
JPFM_FORMATTER_EVENT_ERROR,
pipeErrorMess,
__FILE__,
__LINE__,
error);
if (!IsBadWritePointer(formatterDispatch, sizeof (JPfmReadOnlyFormatterDispatch)));
delete formatterDispatch;
#ifdef _WIN32
return __LINE__;
#else
pthread_exit(NULL);
return NULL;
#endif
}
memset(mountCreateParams, 0, sizeof (PfmMountCreateParams));
mountCreateParams->mountFlags |= (
//pfmMountFlagSystemVisible|
pfmMountFlagWorldRead /*| pfmMountFlagReadOnly*/);
mountCreateParams->mountFlags |= formatterDispatch->jpfmSuppliedMountFlag;
mountCreateParams->mountFileName = formatterDispatch->mountFileName;
mountCreateParams->driveLetter = formatterDispatch->driveLetter;
mountCreateParams->visibleProcessId = formatterDispatch->visibleProcessId;//checks for this already done
#ifdef USE_FAST_PIPE
mountCreateParams->toFormatterWrite = clientHandle;
mountCreateParams->fromFormatterRead = clientHandle;
#else
mountCreateParams->toFormatterWrite = toFormatterWrite;
mountCreateParams->fromFormatterRead = fromFormatterRead;
#endif
mountCreateParams->paramsSize = sizeof (PfmMountCreateParams);
error = pfmapi->MountCreate(mountCreateParams, &formatterDispatch->pfmmount);
jvm->AttachCurrentThreadAsDaemon((void **)&env,formatterDispatch->createAttachArgs((char *)THREAD_NAME));
if(error){
attachAndMessageC(
attachResult,
formatterDispatch,
(char *)THREAD_NAME,
JPFM_FORMATTER_EVENT_MOUNT_CREATE_FAILED,
"Mounting was unsuccessful.",
__FILE__,
__LINE__,
error
);
delete mountCreateParams;
delete fastPipeCreateParams;
if (!IsBadWritePointer(formatterDispatch, sizeof (JPfmReadOnlyFormatterDispatch)));
delete formatterDispatch;
#ifdef _WIN32
return __LINE__;
#else
pthread_exit(NULL);
return NULL;
#endif
}else{
attachResult = jvm->AttachCurrentThreadAsDaemon((void**)&env,formatterDispatch->createAttachArgs((char *)THREAD_NAME));
if(attachResult >= 0){
env->CallVoidMethod(formatterDispatch->jpfmMount,JPfmMount_setMountId,(jlong)formatterDispatch->pfmmount->GetMountId());
if(env->ExceptionCheck()){
env->ExceptionDescribe();
env->ExceptionClear();
}
jvm->DetachCurrentThread();
}
}
#ifdef USE_FAST_PIPE
FileClose(clientHandle);//this is a little modified than what we have for ramfs
clientHandle = PFM_INVALIDHANDLE;
#else
/* Close driver end pipe handles now. Driver has duplicated what
it needs. If these handles are not closed then pipes will not
break if driver disconnects, leaving us stuck in the
marshaller.
*/
FileClose(toFormatterWrite);
FileClose(fromFormatterRead);
#endif
memset(marshallerServeParams, 0, sizeof (PfmMarshallerServeParams));
marshallerServeParams->dispatch = formatterDispatch;
marshallerServeParams->paramsSize = sizeof (PfmMarshallerServeParams);
marshallerServeParams->formatterName = (const char *) formatterDispatch->formattername;
#ifdef USE_FAST_PIPE
marshallerServeParams->toFormatterRead = serverHandle;
marshallerServeParams->fromFormatterWrite = serverHandle;
#else
marshallerServeParams->toFormatterRead = toFormatterRead;
marshallerServeParams->fromFormatterWrite = fromFormatterWrite;
#endif
marshallerServeParams->volumeFlags = formatterDispatch->volumeFlags; //pfmVolumeFlagReadOnly;//files can be deleted even though pfmVolumeFlagReadOnly maybe this setting is purely cosmetic
error = PfmMarshallerFactory(&formatterDispatch->marshaller);
if (error) {
attachAndMessageC(
attachResult,
formatterDispatch,
(char *)THREAD_NAME,
JPFM_FORMATTER_EVENT_MOUNT_CREATE_FAILED,
"Could not create fast pipe. Giving up.",
__FILE__,
__LINE__,
error);
if (!IsBadWritePointer(formatterDispatch, sizeof (JPfmReadOnlyFormatterDispatch)));
delete formatterDispatch;
delete mountCreateParams;
delete fastPipeCreateParams;
delete marshallerServeParams;
#ifdef _WIN32
return __LINE__;
#else
pthread_exit(NULL);
return NULL;
#endif
}
//formatterDispatch->marshaller->SetStatus(GetStdHandle(STD_ERROR_HANDLE));
formatterDispatch->marshaller->SetTrace(formatterDispatch->mountFileName/*L"JPfm"*/);
//JNIEnv *env;
//char *nm = /*_strdup(*/"Formatter ServeDispatch thread";/*);*/
//printf("attaching %s\n",nm);
//jvm->AttachCurrentThread((void **)&env,formatter->createAttachArgs(nm));
//attaching thread is useless as the first method that
//is invoked after servedispatch is formatterDispatch's open method
//After finishing it 's work it kills the thread
//Checks can be added, but, even so, it cannot be said for sure
//if this thread will be used again. In such a case
//checks will have to be added everywhere, which might be a good
//thing because it seems all reside in the same thread.
//The classic method followed is going in a loop to read the driver requests
//so maybe this same thread is used. Yet again I wonder how
//this type of formatter is multithreaded
if(!formatterDispatch->noListenerAttached){
jvm->AttachCurrentThreadAsDaemon((void **)&env,formatterDispatch->createAttachArgs((char *)THREAD_NAME));
formatterDispatch->messageFormatterListener(env,
JPFM_FORMATTER_EVENT_MESSAGE,
"Just going to dispatch formatter.",0
);
jvm->DetachCurrentThread();
}
error = formatterDispatch->marshaller->ServeDispatch(marshallerServeParams);
if(error){
attachAndMessageC(
attachResult,
formatterDispatch,
(char *)THREAD_NAME,
JPFM_FORMATTER_EVENT_ERROR,
"ServeDispatch ended with error",
__FILE__,
__LINE__,
error);
}
if(!formatterDispatch->noListenerAttached){
jvm->AttachCurrentThreadAsDaemon((void **)&env,formatterDispatch->createAttachArgs((char *)THREAD_NAME));
if(formatterDispatch->isAlive==JNI_TRUE){
// if unmount was intiated by us, we set isAlive false,
formatterDispatch->messageFormatterListener(env,
JPFM_FORMATTER_EVENT_DETACHED,
"Some external tool might have initiated an unmount operation or and error might have occurred.",0);
}else /*we did it*/{
formatterDispatch->messageFormatterListener(env,
JPFM_FORMATTER_EVENT_DETACHED,
"Unmount intiated internally was successful",0);
}
jvm->DetachCurrentThread();
}
// NULL);
//printf("served\n");
//separated by | oring
#ifdef USE_FAST_PIPE
if (serverHandle != PFM_INVALIDHANDLE){
FileClose(serverHandle);//CloseHandle(serverHandle);
}
#else
if(toFormatterRead != PFM_INVALIDHANDLE)
FileClose(toFormatterRead);
if(toFormatterRead != PFM_INVALIDHANDLE)
FileClose(fromFormatterWrite);
#endif
if(formatterDispatch->pfmmount){
//formatterDispatch->pfmmount->Release();
formatterDispatch->pfmmount = 0;
}
delete mountCreateParams;
delete marshallerServeParams;
delete fastPipeCreateParams;
if (!IsBadWritePointer(formatterDispatch, sizeof (JPfmReadOnlyFormatterDispatch)));
delete formatterDispatch;
#ifdef _WIN32
#else
//#ifdef __APPLE__
////////////////MAC//////////////////
//#else
////////////////LINUX//////////////////
pthread_exit(NULL);
//#endif
#endif
#ifdef _WIN32
return error;
#else
pthread_exit(NULL);
#endif
}
//not required on windows and fast pipe is always implemented there
#ifdef _WIN32
static long file_last_pipe_instance = 0;
INT64 PFM_CCALL file_get_system_time(void){
union{
INT64 file;
FILETIME system;
} time;
GetSystemTimeAsFileTime(&(time.system));
return time.file;
}
int/*error*/ EFileCreateSocket(HANDLE* out_handle_1,HANDLE* out_handle_2) {
#else
int/*error*/ EFileCreateSocket(int* handle1,int* handle2){
#endif
#ifdef _WIN32
int/*bool*/ bidir = true;
int error = 0;
HANDLE handle1;
HANDLE handle2 = INVALID_HANDLE_VALUE;
enum { max_pipe_name_chars = 100 };
wchar_t pipe_name[max_pipe_name_chars];
// CreatePipe creates handles that do not support overlapped IO and
// are unidirectional, so use named pipe instead.
wsprintfW(pipe_name,L"\\\\.\\Pipe\\AnonymousPipe.%i.%p.%i.%I64i",
GetCurrentProcessId(),&file_last_pipe_instance,
InterlockedIncrement(&file_last_pipe_instance),file_get_system_time());
handle1 = CreateNamedPipeW(pipe_name,(bidir?(PIPE_ACCESS_DUPLEX|
FILE_FLAG_OVERLAPPED):PIPE_ACCESS_INBOUND)|
FILE_FLAG_FIRST_PIPE_INSTANCE,PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|
PIPE_WAIT,1/*pipeCount*/,0/*outBufSize*/,0/*inBufSize*/,
30*1000/*timeout*/,0/*security*/);
if(!handle1)
{
handle1 = INVALID_HANDLE_VALUE;
}
if(handle1 == INVALID_HANDLE_VALUE)
{
error = GetLastError();
}
if(!error)
{
handle2 = CreateFileW(pipe_name,(bidir?GENERIC_READ:0)|GENERIC_WRITE,
0/*shareMode*/,0/*security*/,OPEN_EXISTING,
bidir?FILE_FLAG_OVERLAPPED:0,0/*template*/);
if(handle2 == INVALID_HANDLE_VALUE)
{
error = GetLastError();
/*VERIFY(*/CloseHandle(handle1)/*)*/;
handle1 = INVALID_HANDLE_VALUE;
}
}
*out_handle_1 = handle1;
*out_handle_2 = handle2;
return error;
return -1; // fast pipe always available on windows :)
#else
int error = 0;
int handles[2];
if(socketpair(AF_UNIX,SOCK_STREAM,0,handles) != 0){
error = errno;
}/*else {
// Convert socket to uni-directional.
shutdown(handles[0],SHUT_WR);
shutdown(handles[1],SHUT_RD);
}*/
*handle1 = handles[0];
*handle2 = handles[1];
return error;
#endif
}