JNI calling Java from C++ with multiple threads - c++

I'm working on a project, where I call Java functions from C++ code (using JNI) and I have a problem about multithreading. I want to call Java searching function and for each call I want to make a separate thread. I have a singleton MainClass and nested Query class. Query class is inherited from QThread. Code looks like this
MainClass::MyQuery query("<some search query>");
query.LaunchQuery();
//functions of Query
void MainClass::MyQuery::LaunchQuery() const
{
this->start();
}
void MainClass::Query::run()
{
const MainClass& mainClass = MainClass::GetInstance();
const jclass& obj = mainClass.GetClass();
JNIEnv& env = mainClass.GetJavaEnvironment();
jmethodID methodId = env.GetMethodID(obj, "SearchQuery", "(Ljava/lang/String;)V"); //Run-time error
if(methodId != 0)
{
//calling "SearchQuery" function
}
Now, if run this code in a single thread - everything is fine, but if try to run above code - using multithreading, it causes run-time error by message
"Unhandled exception at 0x777715de in MyApp.exe: 0xC0000005: Access violation reading location 0x000000ac." when I try to get method id. I've tried also with boost::thread but result was the same.
So why it fails when I'm doing it in a separate thread, when in the same thread everything is fine?
Any ideas?

Scroll down to 'Attaching to the VM' in the JNI docs :
http://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/invocation.html
The JNI interface pointer (JNIEnv) is valid only in the current
thread. Should another thread need to access the Java VM, it must
first call AttachCurrentThread() to attach itself to the VM and obtain
a JNI interface pointer.

Related

Instantiating boost::beast in dynamic library causes a crash

I'm trying to implement a very simple, local, HTTP server for my C++ application — I'm using XCode on macOS. I have to implement it from within a dynamically loaded library rather than the "main" thread of the program. I decided to try using boost::beast since another part of the application uses boost libraries already. I'm trying to implement this example, but within the context of my library, and not as part its main program.
The host application for this library calls on the following function to start a localhost server, but crashes when instantiating "acceptor":
extern "C" BASICEXTERNALOBJECT_API long startLocalhost(TaggedData* argv, long argc, TaggedData * retval) {
try {
string status;
retval->type = kTypeString;
auto const address = net::ip::make_address("127.0.0.1");
unsigned short port = static_cast<unsigned short>(std::atoi("1337"));
net::io_context ioc{1};
tcp::acceptor acceptor{ioc, {address, port}}; // <-- crashes on this line
tcp::socket socket{ioc};
http_server(acceptor, socket);
ioc.run();
status = "{'status':'ok', 'message':'localhost server started!'}";
retval->data.string = getNewBuffer(status);
}
catch(std::exception const& e)
{
string status;
//err_msg = "Error: " << e.what() << std::endl;
status = "{'status':'fail', 'message':'Error starting web server'}";
retval->data.string = getNewBuffer(status);
}
return kESErrOK;
}
When stepping through the code, I see that XCode reports an error when the line with tcp::acceptor ... is executed:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x783c0a3e3f22650c)
and is highlighted at the single line of code in a function in scheduler.h:
//Get the concurrency hint that was used to initialize the scheduler.
int concurrency_hint() const
{
return concurrency_hint_; //XCode halts here
}
I'm debating as to whether or not I should include a different C++ web server, like Drogon, instead of boost::beast, but I thought I would post here to see if anybody had any insight as to why the crash is happening in this case.
Update
I found a fix that is a workaround for my particular circumstances, hopefully it can help others running into this issue.
The address to the service_registry::create static factory method resolves correctly when I add ASIO_DECL in front of the methods declaration in asio/detail/service_registry.hpp.
It should look like this:
// Factory function for creating a service instance.
template <typename Service, typename Owner>
ASIO_DECL static execution_context::service* create(void* owner);
By adding ASIO_DECL in front of it, it resolves correctly and the scheduler and kqueue_reactor objects initialize properly avoiding the bad access to concurrency_hint().
In my case I am trying to use non-Boost ASIO inside of a VST3 audio plug-in running in Ableton Live 11 on macOS on an M1 processor. Using the VST3 plug-in in I'm getting this same crash. Using the same plug-in in other DAW applications, such as Reaper, does not cause the crash. It also does not occur for Ableton Live 11 on Windows.
I've got it narrowed down to the following issue:
In asio/detail/impl/service_registry.hpp the following method attempts to return a function pointer address to a create/factory method.
template <typename Service>
Service& service_registry::use_service(io_context& owner)
{
execution_context::service::key key;
init_key<Service>(key, 0);
factory_type factory = &service_registry::create<Service, io_context>;
return *static_cast<Service*>(do_use_service(key, factory, &owner));
}
Specifically, this line: factory_type factory = &service_registry::create<Service, io_context>;
When debugging in Xcode, in the hosts that work, when inspecting
factory, it shows the correct address linking to the service_registry::create<Service, io_context> static method.
However, in Ableton Live 11, it doesn't point to anything - somehow the address to the static method does not resolve correctly. This causes a cascade of issues, ultimately leading up to trying to invoke the factory function pointer in asio/asio/detail/impl/service_registry.ipp in the method service_registry::do_use_service. Since it doesn't point to a proper create method, nothing is created, it results in uninitialized objects, including the scheduler instance.
Therefore, when calling scheduler_.concurrency_hint() in kqueue_reactor.ipp the scheduler is uninitialized, and the EXC_BAD_ACCESS error results.
It's unclear to me why under some host processes, dynamically loading the plug-in cannot resolve the static method address, but others have no problem. In my case I compiled asio.hpp for standalone ASIO into the plug-in directly, there was no linking.
The best guesses I can come up with are
maybe your http_server might start additional threads or even fork. This might cause io_context and friends to be accessed after startLocalhost returned. To explain the crash location appearing to be at the indicated line, I could add the heuristic that something is already off during the destructor for ioc
the only other idea I have is that actually the opening/binding of the acceptor throws, but due to possible incompatibilities of types in the shared module vs the main program, the exception thrown is not actually caught and causes abnormal termination. This might happen more easily if the main program also uses Boost libraries, but a different copy (build/version) of them.
In this case there's a simple thing you can do: split up initialization and use the overloads that take error_code to instead use them.

Null error while dynamically creating AWS Lambda from java

I am trying to create lambda function from another lamda function (java).
here a snippet of code
LambdaFunctionCreater implements RequestHandler<Object, Object> {
...
}
I have the following method inside my class
createNewLambdaFunction (Map<String, String> lambdaEnvProperties) {
try {
AWSLambdaClientBuilder awsLambdaClient = AWSLambdaClient.builder();
awsLambdaClient.setRegion(RegionUtils.getRegion("us-east-1").getName());
CreateFunctionRequest req = new CreateFunctionRequest ();
req.withDescription("Hello World")
.withEnvironment(new Environment ().withVariables(myProperties))
.withFunctionName("Sample Lambda Dynamically created"))
.withHandler("com.sample.SampleLambda::handleRequest")
.withRole("MyRole")
.withRuntime("java8")
.withMemorySize(128)
.withTimeout(600)
.addTagsEntry("Tag1", "Value1")
.withCode(new FunctionCode().withS3Bucket("mybucket").withS3Key("myfile.jar").withS3ObjectVersion("latestversionid"));
CreateFunctionResult result = awsLambdaClient.build().createFunction(req);
} catch (Exception e) {
logger.error("Failed to create ", e.fillInStackTrace());
}
}
The above call fails with message
java.lang.NullPointerExceptionnull at
com.capitalone.aws.lambda.handler.LambdaFunctionCreater.createNewLambdaFunction(LambdaFunctionCreater.java:154)null at
com.capitalone.aws.lambda.handler.LambdaFunctionCreater.handleRequest(LambdaFunctionCreater.java:104)null at
sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)null at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)null at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)null at
java.lang.reflect.Method.invoke(Method.java:498)null at
lambdainternal.EventHandlerLoader$PojoMethodRequestHandler.handleRequest(EventHandlerLoader.java:456)null at
lambdainternal.EventHandlerLoader$PojoHandlerAsStreamHandler.handleRequest(EventHandlerLoader.java:375)null at
lambdainternal.EventHandlerLoader$2.call(EventHandlerLoader.java:1139)null at
lambdainternal.AWSLambda.startRuntime(AWSLambda.java:278)null at
lambdainternal.AWSLambda.(AWSLambda.java:62)null at
java.lang.Class.forName0(Native Method)null at
java.lang.Class.forName(Class.java:348)null at
lambdainternal.LambdaRTEntry.main(LambdaRTEntry.java:94)null
Any insight will be appreciated.
Since you're not posting the full code, it's hard to evaluate where the null pointer exception happens.
I'd split the code into more sections and avoid directly passing new objects into single statement like .withEnvironment(new Environment ().withVariables(myProperties)). This is very hard to debug since you can't inspect variable value if such statement fails.
I'd also recommend setting up your development environment in such a way that you can run and debug your code directly in your IDE. Debugger watch would immediately tell you which variable is the source of your NullPointerException.
This NullPointerException can be a configuration, permissions or dependency problem.
See also these Java Lambda examples.

Dynamically loading client C++ dll using ACE_DLL giving error as Unhandled exception

I want to dynamically load the client dll in my C++ Windows application. So I am using ACE_DLL. I want to create the object of the class in client dll in my application .
So I have written a wrapper class. One of its member function creates the object of ACE_DLL.
Then using that object I am loading the client dll. Next I am calling the symbol function through ACE_DLL object and passing the mangled name of constructor of the class in client dll. Next I am calling the function pointer (_entry ) which contains address of the constructor but this time I am getting error as "Unhandled exception (Access violation)"
Please let me know if my approach is correct. Below are the calling sequence in my application.
ACE_DLL* _pDll;
typedef Test* (*TestFP)();
TestFP _entry;
_pDll = new ACE_DLL();
_pDll->open("dllname_to_be_opend");
std::string sSymbol = "Test"; // mangled name of the Test class constructor in client dll
_entry = (TestFP) _pDll->symbol(sSymbol.c_str());
Test *obj = _entry(); // Unhandled exception at 0x00362b2f in Testdll.exe: 0xC0000005: Access violation writing location 0x00362b0c.
Thank you,
Prasad
That looks about right. Can you run ACE_wrappers/tests/DLL_Test.exe? If that works then compare the test code to yours more closely.
The code you have presented i.e.
_pDll = new ACE_DLL();
_pDll->open("dllname_to_be_opend");
std::string sSymbol = "Test";
_entry = (TestFP) _pDll->symbol(sSymbol.c_str());
does not verify that the return value of ACE_DLL::open call is zero (0 for success, -1 on failure) or that the return value of ACE_DLL::symbol call is not zero (0 is returned on failure).

gSOAP multithread copy segmentation fault

I'm using gSOAP under Linux in one of my projects, and I have a problem when using the server for a pretty long time (actually not very long, I get this error after something like 10 hours...). I followed the example gave some time ago here for multithreading in gSOAP. I create a soap service, then use the copy method and pass it to a thread. The thread functions is something like this:
void MyClass::SoapServer(myservice::Service* soapService)
{
int res = soapService->serve();
if (res != SOAP_OK)
{
// log error
}
soapService->destroy();
soap_free(soapService);
}
After a few hours, when there is a constant poller that calls SOAP functions, I get segmentation fault in the gSOAP copy function. Below i attach the code that accepts the connection and creates the thread.
while(true)
{
int error = mySoapService.accept();
if (!soap_valid_socket(error))
{
//error
}
else
{
myservice::Service *soapServiceCopy = NULL;
soapServiceCopy = mySoapService.copy();
// create thread using the SoapServer function
// and pass soapServiceCopy as an argument
}
}
It seems to me that the soap service clean up is correctly performed, is there anything I'm missing?
Thanks
The difference between your code and my example that you link to is that you use soap_free() to free the soapService object and my example uses delete. Changing my example code to use soap_free() and then running it under valgrind leads to free / delete / delete[] mismatches being reported which makes me think that soap_free() is built on top of free but the .copy() method is using new to create the copy.

unable to successfully call function in dynamically loaded plugin in c++

I've successfully loaded a C++ plugin using a custom plugin loader class. Each plugin has an extern "C" create_instance function that returns a new instance using "new".
A plugin is an abstract class with a few non-virtual functions and several protected variables(std::vector refList being one of them).
The plugin_loader class successfully loads and even calls a virtual method on the loaded class (namely "std::string plugin::getName()".
The main function creates an instance of "host" which contains a vector of reference counted smart pointers, refptr, to the class "plugin". Then, main creates an instance of plugin_loader which actually does the dlopen/dlsym, and creates an instance of refptr passing create_instance() to it. Finally, it passes the created refptr back to host's addPlugin function. host::addPlugin successfully calls several functions on the passed plugin instance and finally adds it to a vector<refptr<plugin> >.
The main function then subscribes to several Apple events and calls RunApplicationEventLoop(). The event callback decodes the result and then calls a function in host, host::sendToPlugin, that identifies the plugin the event is intended for and then calls the handler in the plugin. It's at this point that things stop working.
host::sendToPlugin reads the result and determines the plugin to send the event off to.
I'm using an extremely basic plugin created as a debugging plugin that returns static values for every non-void function.
Any call on any virtual function in plugin in the vector causes a bad access exception. I've tried replacing the refptrs with regular pointers and also boost::shared_ptrs and I keep getting the same exception. I know that the plugin instance is valid as I can examine the instance in Xcode's debugger and even view the items in the plugin's refList.
I think it might be a threading problem because the plugins were created in the main thread while the callback is operating in a seperate thread. I think things are still running in the main thread judging by the backtrace when the program hits the error but I don't know Apple's implementation of RunApplicationEventLoop so I can't be sure.
Any ideas as to why this is happening?
class plugin
{
public:
virtual std::string getName();
protected:
std::vector<std::string> refList;
};
and the pluginLoader class:
template<typename T> class pluginLoader
{
public: pluginLoader(std::string path);
// initializes private mPath string with path to dylib
bool open();
// opens the dylib and looks up the createInstance function. Returns true if successful, false otherwise
T * create_instance();
// Returns a new instance of T, NULL if unsuccessful
};
class host
{
public:
addPlugin(int id, plugin * plug);
sendToPlugin(); // this is the problem method
static host * me;
private:
std::vector<plugin *> plugins; // or vector<shared_ptr<plugin> > or vector<refptr<plugin> >
};
apple event code from host.cpp;
host * host::me;
pascal OSErr HandleSpeechDoneAppleEvent(const AppleEvent *theAEevt, AppleEvent *reply, SRefCon refcon) {
// this is all boilerplate taken straight from an apple sample except for the host::me->ae_callback line
OSErr status = 0;
Result result = 0;
// get the result
if (!status) {
host::me->ae_callback(result);
}
return status;
}
void host::ae_callback(Result result) {
OSErr err;
// again, boilerplate apple code
// grab information from result
if (!err)
sendToPlugin();
}
void host::sendToPlugin() {
// calling *any* method in plugin results in failure regardless of what I do
}
EDIT: This is being run on OSX 10.5.8 and I'm using GCC 4.0 with Xcode. This is not designed to be a cross platform app.
EDIT: To be clear, the plugin works up until the Apple-supplied event loop calls my callback function. When the callback function calls back into host is when things stop working. This is the problem I'm having, everything else up to that point works.
Without seeing all of your code it isn't going to be easy to work out exactly what is going wrong. Some things to look at:
Make sure that the linker isn't throwing anything away. On gcc try the compile options -Wl -E -- we use this on Linux, but don't seem to have found a need for it on the Macs.
Make sure that you're not accidentally unloading the dynamic library before you've finished with it. RAII doesn't work for unloading dynamic libraries unless you also stop exceptions at the dynamic library border.
You may want to examine our plug in library which works on Linux, Macs and Windows. The dynamic loading code (along with a load of other library stuff) is available at http://svn.felspar.com/public/fost-base/trunk/
We don't use the dlsym mechanism -- it's kind of hard to use properly (and portably). Instead we create a library of plugins by name and put what are basically factories in there. You can examine how this works by looking at the way that .so's with test suites can be dynamically loaded. An example loader is at http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-ftest/ftest.cpp and the test suite registration is in http://svn.felspar.com/public/fost-base/trunk/fost-base/Cpp/fost-test/testsuite.cpp The threadsafe_store holds the factories by name and the suite constructor registers the factory.
I completely missed the fact that I was calling dlclose in my plugin_loader's dtor and for some reason the plugins were getting destructed between the RunApplicatoinEventLoop call and the call to sendToPlugin. I removed dlclose and things work now.