Getting error "attempting to detach while still running code" when calling JavaVm->DetachCurrentThread [duplicate] - multithreading

I have an Android app that uses NDK - a regular Android Java app with regular UI and C++ core. There are places in the core where I need to call Java methods, which means I need a JNIEnv* for that thread, which in turn means that I need to call JavaVM->AttachCurrentThread() to get the valid env.
Previously, was just doing AttachCurrentThread and didn't bother to detach at all. It worked fine in Dalvik, but ART aborts the application as soon as a thread that has called AttachCurrentThread exits without calling DetachCurrentThread. So I've read the JNI reference, and indeed it says that I must call DetachCurrentThread. But when I do that, ART aborts the app with the following message:
attempting to detach while still running code
What's the problem here, and how to call DetachCurrentThread properly?

Dalvik will also abort if the thread exits without detaching. This is implemented through a pthread key -- see threadExitCheck() in Thread.cpp.
A thread may not detach unless its call stack is empty. The reasoning behind this is to ensure that any resources like monitor locks (i.e. synchronized statements) are properly released as the stack unwinds.
The second and subsequent attach calls are, as defined by the spec, low-cost no-ops. There's no reference counting, so detach always detaches, no matter how many attaches have happened. One solution is to add your own reference-counted wrapper.
Another approach is to attach and detach every time. This is used by the app framework on certain callbacks. This wasn't so much a deliberate choice as a side-effect of wrapping Java sources around code developed primarily in C++, and trying to shoe-horn the functionality in. If you look at SurfaceTexture.cpp, particularly JNISurfaceTextureContext::onFrameAvailable(), you can see that when SurfaceTexture needs to invoke a Java-language callback function, it will attach the thread, invoke the callback, and then if the thread was just attached it will immediately detach it. The "needsDetach" flag is set by calling GetEnv to see if the thread was previously attached.
This isn't a great thing performance-wise, as each attach needs to allocate a Thread object and do some internal VM housekeeping, but it does yield the correct behavior.

I'll try a direct and practical approach (with sample code, without use of classes) answering this question for the occasional developer that came up with this error in android, in cases where they had it working and after a OS or framework update (Qt?) it started to give problems with that error and message.
JNIEXPORT void Java_com_package_class_function(JNIEnv* env.... {
JavaVM* jvm;
env->GetJavaVM(&jvm);
JNIEnv* myNewEnv; // as the code to run might be in a different thread (connections to signals for example) we will have a 'new one'
JavaVMAttachArgs jvmArgs;
jvmArgs.version = JNI_VERSION_1_6;
int attachedHere = 0; // know if detaching at the end is necessary
jint res = jvm->GetEnv((void**)&myNewEnv, JNI_VERSION_1_6); // checks if current env needs attaching or it is already attached
if (JNI_EDETACHED == res) {
// Supported but not attached yet, needs to call AttachCurrentThread
res = jvm->AttachCurrentThread(reinterpret_cast<JNIEnv **>(&myNewEnv), &jvmArgs);
if (JNI_OK == res) {
attachedHere = 1;
} else {
// Failed to attach, cancel
return;
}
} else if (JNI_OK == res) {
// Current thread already attached, do not attach 'again' (just to save the attachedHere flag)
// We make sure to keep attachedHere = 0
} else {
// JNI_EVERSION, specified version is not supported cancel this..
return;
}
// Execute code using myNewEnv
// ...
if (attachedHere) { // Key check
jvm->DetachCurrentThread(); // Done only when attachment was done here
}
}
Everything made sense after seeing the The Invocation API docs for GetEnv:
RETURNS:
If the current thread is not attached to the VM, sets *env to NULL, and returns JNI_EDETACHED. If the specified version is not supported, sets *env to NULL, and returns JNI_EVERSION. Otherwise, sets *env to the appropriate interface, and returns JNI_OK.
Credits to:
- This question Getting error "attempting to detach while still running code" when calling JavaVm->DetachCurrentThread that in its example made it clear that it was necessary to double check every time (even though before calling detach it doesn't do it).
- #Michael that in this question comments he notes it clearly about not calling detach.
- What #fadden said: "There's no reference counting, so detach always detaches, no matter how many attaches have happened."

Related

Dispatcher xps memory leak

I'm call a .net 4.0 dll from a vb6 app using com interop. In .net I create an xps document, via a xaml fixed document and save it to disk. This causes and memory leak and I've found a great solution here.
Saving a FixedDocument to an XPS file causes memory leak
The solution above, that worked for me, involves this line of code:
Dispatcher.CurrentDispatcher.Invoke(DispatcherPriority.SystemIdle, new DispatcherOperationCallback(delegate { return null; }), null);
What exactly is happening with this line of code. Is that by setting the delegate to null this disposes the Dispatcher object?
While it initially appears that the supplied code does nothing, it actually has a non-obvious side effect that is resolving your problem. Let's break it down into steps:
Dispatcher.CurrentDispatcher Gets the dispatcher for the current thread.
Invoke synchronously executes the supplied delegate on the dispatcher's thread (the current one)
DispatcherPriority.SystemIdle sets the execution priority
new DispatcherOperationCallback(delegate { return null; }) creates a delegate that does nothing
null is passed as an argument to the delegate
All together, this looks like it does nothing, and indeed it actually does do "nothing". The important part is that it waits until the dispatcher for the current thread has cleared any scheduled tasks that are higher priority than SystemIdle before doing the "nothing". This allows the scheduled cleanup work to happen before you return to your vb6 app.

GCHandle, AppDomains managed code and 3rd party dll

I have looking at many threads about the exception "cannot pass a GCHandle across AppDomains" but I still don't get it....
I'm working with an RFID Reader which is driven by a DLL. I don't have source code for this DLL but only a sample to show how to use it.
The sample works great but I have to copy some code in another project to add the reader to the middleware Microsoft Biztalk.
The problem is that the process of Microsoft Biztalk works in another AppDomain. The reader handle events when a tag is read. But when I run it under Microsoft Biztalk I got this annoying exception.
I can't see any solution on how to make it work...
Here is some code that may be interesting :
// Let's connecting the result handlers.
// The reader calls a command-specific result handler if a command is done and the answer is ready to send.
// So let's tell the reader which functions should be called if a result is ready to send.
// result handler for reading EPCs synchronous
Reader.KSRWSetResultHandlerSyncGetEPCs(ResultHandlerSyncGetEPCs);
[...]
var readerErrorCode = Reader.KSRWSyncGetEPCs();
if (readerErrorCode == tKSRWReaderErrorCode.KSRW_REC_NoError)
{
// No error occurs while sending the command to the reader. Let's wait until the result handler was called.
if (ResultHandlerEvent.WaitOne(TimeSpan.FromSeconds(10)))
{
// The reader's work is done and the result handler was called. Let's check the result flag to make sure everything is ok.
if (_readerResultFlag == tKSRWResultFlag.KSRW_RF_NoError)
{
// The command was successfully processed by the reader.
// We'll display the result in the result handler.
}
else
{
// The command can't be proccessed by the reader. To know why check the result flag.
logger.error("Command \"KSRWSyncGetEPCs\" returns with error {0}", _readerResultFlag);
}
}
else
{
// We're getting no answer from the reader within 10 seconds.
logger.error("Command \"KSRWSyncGetEPCs\" timed out");
}
}
[...]
private static void ResultHandlerSyncGetEPCs(object sender, tKSRWResultFlag resultFlag, tKSRWExtendedResultFlag extendedResultFlag, tKSRWEPCListEntry[] epcList)
{
if (Reader == sender)
{
// Let's store the result flag in a global variable to get access from everywhere.
_readerResultFlag = resultFlag;
// Display all available epcs in the antenna field.
Console.ForegroundColor = ConsoleColor.White;
foreach (var resultListEntry in epcList)
{
handleTagEvent(resultListEntry);
}
// Let's set the event so that the calling process knows the command was processed by reader and the result is ready to get processed.
ResultHandlerEvent.Set();
}
}
You are having a problem with the gcroot<> helper class. It is used in the code that nobody can see, inside that DLL. It is frequently used by C++ code that was designed to interop with managed code, gcroot<> stores a reference to a managed object. The class uses the GCHandle type to add the reference. The GCHandle.ToIntPtr() method returns a pointer that the C++ code can store. The operation that fails is GCHandle.FromIntPtr(), used by the C++ code to recover the reference to the object.
There are two basic explanations for getting this exception:
It can be accurate. Which will happen when you initialized the code in the DLL from one AppDomain and use it in another. It isn't clear from the snippet where the Reader class object gets initialized so there are non-zero odds that this is the explanation. Be sure to keep it close to the code that uses the Reader class.
It can be caused by another bug, present in the C++ code inside the DLL. Unmanaged code often suffers from pointer bugs, the kind of bug that can accidentally overwrite memory. If that happens with the field that stores the gcroot<> object then nothing goes wrong for a while. Until the code tries to recover the object reference again. At that point the CLR notices that the corrupted pointer value no longer matches an actual object handle and generates this exception. This is certainly the hard kind of bug to solve since this happens in code you cannot fix and showing the programmer that worked on it a repro for the bug is very difficult, such memory corruption problems never repro well.
Chase bullet #1 first. There are decent odds that Biztalk runs your C# code in a separate AppDomain. And that the DLL gets loaded too soon, before or while the AppDomain is created. Something you can see with SysInternals' ProcMon. Create a repro of this by writing a little test program that creates an AppDomain and runs the test code. If that reproduces the crash then you'll have a very good way to demonstrate the issue to the RFID vendor and some hope that they'll use it and work on a fix.
Having a good working relationship with the RFID reader vendor to get to a resolution is going to be very important. That's never not a problem, always a good reason to go shopping elsewhere.

After adding multi threading to my app, VS2010 will not remove file handle after stopping debugging

today I've added multi threading to a windows forms application. On my UI thread I'm starting a thread via new Thread() {...}).Start(); Which itself will call a Method which uses ThreadPool.QueueUserWorkItem(). After the Method is called the thread will wait on a queue until a specific item is returned and the thread exits:
new Thread(o =>
{
s.SimulateChanges();
Boolean run = true;
while (run)
{
SimulationResult sr = queue.WaitDequeue();
//EOF is a static property which will be returned
//if the queue is at its end so I can break the while loop
if (SimulationResult.EOF.Equals(sr))
{
run = false;
continue;
}
this.simulationProgressBar.BeginInvoke((Action)delegate()
{
if (sr.IsDummy && this.simulationProgressBar.Value < this.simulationProgressBar.Maximum)
{
/*...*/
}
else
{
this.resultListView.AddObject(sr);
}
});
}
this.simulationProgressBar.BeginInvoke((Action)delegate()
{
this.ToggleSimulationControls(true);
});
}).Start();
And that is the code of the method called:
public void SimulateChanges()
{
ThreadPool.QueueUserWorkItem(o =>
{
foreach (IColElem elem in collection.AsEnumerable())
{
/*lot of code*/
queue.Enqueue(new SimulationResult() { IsDummy = true });
}
log.Debug("Finished!");
queue.Enqueue(SimulationResult.EOF);
});
}
My Queue is a self written class allowing a thread to wait on dequeue until an object ins enqueued.
Everything is working fine, except that if I stop debugging (using stop debugging or simply closing the application) I can't rebuild my application as VS2010 doesn't remove the file handle. I believe it has something to do with my threads not exiting correctly. Is their any way I can assure this?
Thanks for any advice :-)
Hard to explain all aspects of the question. But you are making a pretty common mistake, often made by programmers when they first start using threads. You are not making sure that the thread stops running when the user closes the main window. It is an easy mistake to make, the UI thread takes care of a lot of grunt work. Including automatically terminating when the main window of your app is closed by the user. So at least part of your problem is that you did manage to close the main window. But didn't actually terminate the process. Building cannot work, your program's EXE is still in use.
Properly shutting down a thread can be very difficult, given that the user will close the window regardless of what that thread is doing. It could be catatonic, buried deep inside an operating system call and waiting for it to complete. Tough to ask it to quit when it isn't executing code.
There is a very simple solution, at least good enough to keep going with your project or solve half the problem you have. You can mark the thread as "kill automatically at program termination" and the CLR will take care of it. Use the IsBackground property, like this:
var t = new Thread(o =>
{
// Lotsa code
});
t.IsBackground = true;
t.Start();
But do keep in mind that there's nothing graceful about that kind of kill. If you are writing a file or talking to a server then that's going to cause a partially written file or a very confused server. Otherwise not different from killing the program with task manager.

How to make an assert window in QT

I currently have a very long running GUI-Application in QT. Later that application is going to be tested and run on an embedded device without a keyboard in full screen.
For easier debugging I have a custom assert macro, which allows me to ignore certain asserts (may include known buggy parts I have to work around for now) etc. For the time being I just print something on the console such as "Assertion: XXXX failed; abort/ignore". This is fine when I start the application within a console, but ultimately fails when I run it on the final device. In that case the assert will just block the main thread waiting for input and make the GUI hang badly without hope for recovery.
Now I am thinking about how to remedy this situation. One Idea is to just have the assert crash, as the standard assert does. But I do not really like that Idea, since there are a lot of know problems, and I've always found ignorable asserts very helpful when testing applications. Also I would have to put the messages into a separate file, so I can later see what happened while testing. Reading these files afterwards is possible, but I would prefer a simpler way to find out what went wrong.
The other idea was to make a window instead. However the asserts may be triggered in any thread and I can only create new windows in the GUI thread. Also the main event loop may be blocked by the assert, so I cannot be sure that it will handle the events correctly. I would somehow need a fully responsive stand-alone window in a separate thread, which only handles a few buttons.
Is this somehow possible in QT4?
You may post events to main thread to display dialog and wait for an answer from non-gui threads, or just display dialog if current thread is app thread
int result = -1;
if ( QTrhead::currentThread() == QCoreApplication::instance()->thread() )
{
result = AssertHandler->ShowDialog(where, what, condition);
}
else
{
QMetaObject::invokeMethod(AssertHandler, "ShowDialog", Qt::QueuedBlockingConnection, Q_RETURN_ARG(int, result), Q_ARG(QString, where), Q_ARG(QString, what), Q_ARG(QString, condition);
}
if (result != 0)
{
// handle assert
}
The AssertHandler is QObject based class with slot int ShowDialog(const QString &where, const QString what, const QString &condition). It should display dialog with assert data and buttons assert/ignore. Returns 0 when user pressed ignore, otherwise returns non zero value.

Thread returning into bad space address

I have a weird problem regarding the use of threads inside a Firebreath plugin (in this case a FB plugin, but could happen anywhere); I will try to explain:
1) My plugin creates a thread (static), and it receives a pointer to "this" every time it gets added to a page.
2) So, now I have a thread with a pointer to the plugin, so I can call it's methods.
3) Very nice so far, BUT, suppose that I have a button (coded in HTML), which when pressed will REMOVE the current plugin, put in place another one and launch another thread.
I have described my scenario, now for the problem, when a plugin gets added it launches a thread; inside the thread there is a pointer to "this". First time, it gets fired...while the thread is executing I press the HTML button (so, the current plugin now is destroyed) and a new one is placed. The thread from the 1st plugin ends, and now returns...but it returns to the 2nd instance of the plugin.
The plugin is an image viewer, the first plugin look for a picture, it gets removed and a new one is placed; BUT the image from the 1st plugin is placed in the 2nd one. I don't know where to start looking, apparently the pointer has an address to the plugin (e.g. 12345), the plugin gets removed and instantiated again with the same memory address (12345).
Is there some way to avoid that behavior?
This is the code I have so far:
myPlugin.h
unsigned ThreadId;
HANDLE hThread;
myPlugin.cpp
unsigned __stdcall myPlugin::Thread(void *data)
{
myPlugin* this = (myPlugin*) data;
this->getImage("http:\\host.com\\image.jpg");
_endthreadex(0); //EDIT: addedd this missing line to end the thread
}
void myPlugin::onPluginReady(std::string imageUrl)
{
hThread = (HANDLE)_beginthreadex(NULL, 0, myPlugin::Thread, (void*) **this**, 0, &ThreadId);
}
void myPlugin::getImage()
{
//get an image using CURL... //no problem here
}
You need to stop and join the thread in the shutdown() function of your Plugin class; that will be called before things are actually unloaded and that will help avoid the problem.
I would also recommend using boost::thread, since FireBreath already compiles it all in, and that will help simplify some of this; you can hold a weak_ptr in your thread to the plugin class rather than passing in a void*. Of course, either way you'll need to stop and join the thread during the plugin shutdown (and the thread needs to stop quickly or the browser will get cranky about it taking so long).

Resources