[squeak-dev] Priority of WeakArray finalizationProcess
Levente Uzonyi
leves at elte.hu
Mon Jun 14 20:06:51 UTC 2010
On Mon, 14 Jun 2010, Joachim Geidel wrote:
> Am 13.06.10 20:35 schrieb Levente Uzonyi:
>
>> If I select JVMWithoutCallbacks(JVM)>>own: in the debugger and inspect the
>> instance variable "sharedMutex", I find that the UI process is still the
>> owner of the mutex, the mutex's semaphore has no signals and the process
>> is in the list of the semaphore. But the process is not in the critical
>> section of the mutex, because the block containing the #critical: send is
>> already evaluated (JNIPortWeakRegistry>>registerValueOf:). So the mutex is
>> "locked", but it's not used by the process that "locks" it.
>> The deadlock occurs, because the finalization process is trying to access
>> the same mutex to finalize the objects, while it's also in the critical
>> section of the WeakRegistry's semaphore. While this is happening, the UI
>> process is trying to register new objects to the WeakRegistry.
>> I couldn't find out how can the Mutex have this invalid state.
>
> I am going to look into this, but this week I am quite busy, so it may take
> some time.
>
> However, I think that it's unsafe to send #finalize to the executors while
> WeakRegistry is still in the protected block in finalizeValues. You don't
> have control over what finalize is doing, and this can lead to deadlocks if
> a #finalize waits on a Semaphore. Would it be possible to collect the
> objects to be finalized in a collection in the protected block, and finalize
> them afterwards?
After looking at the deadlock again, I found that it's a simple 2 process
- 2 lock circular wait deadlock.
Here is the stack trace of the user process (which isn't the UI process
as I called it previously):
[] in Semaphore>>critical:
BlockClosure>>ensure:
Semaphore>>critical:
Semaphore>>critical:ifError:
JNIPortWeakRegistry(WeakRegistry)>>protected:
JNIPortWeakRegistry(WeakRegistry)>>add:executor:
JNIPortWeakRegistry(WeakRegistry)>>add:
JNIPortWeakRegistry>>registerValueOf:
JVMWithoutCallbacks(JVM)>>own:
JavaLangReflectMethod(JavaClassInstance)>>jniObject:static:
JavaLangReflectMethod class(JavaClassInstance class)>>jniObject:static:
StaticJavaLangObject(JavaClassStatic)>>basicWrapJNIObject:
[] in StaticJavaLangObject(JavaClassStatic)>>wrapJNIObject:
JavaObjectRegistry>>basicFindOrRelease:ifAbsentPut:
[] in JavaObjectRegistry>>findOrRelease:ifAbsentPut:
BlockClosure>>ensure:
[] in Mutex>>critical:
[] in Semaphore>>critical:
BlockClosure>>ensure:
Semaphore>>critical:
And here is the finalization process' stack trace:
[] in Semaphore>>critical:
BlockClosure>>ensure:
Semaphore>>critical:
Mutex>>critical:
JVMWithoutCallbacks(JVM)>>disown:
JavaLangReflectMethod(JavaClassInstance)>>free
JavaLangReflectMethod(JavaClassInstance)>>finalize
ByteSymbol(Symbol)>>value:
WeakIdentityKeyDictionary(WeakKeyDictionary)>>finalizeValues
[] in JNIPortWeakRegistry(WeakRegistry)>>finalizeValues
[] in [] in Semaphore>>critical:ifError:
BlockClosure>>on:do:
BlockClosure>>ifError:
[] in Semaphore>>critical:ifError:
[] in Semaphore>>critical:
BlockClosure>>ensure:
Semaphore>>critical:
Semaphore>>critical:ifError:
JNIPortWeakRegistry(WeakRegistry)>>protected:
JNIPortWeakRegistry(WeakRegistry)>>finalizeValues
So the user process entered the mutex of the JVM and it's trying to enter
the WeakRegistry's semaphore, while the finalization process entered the
WeakRegistry's semaphore and it's trying to enter the JVM's mutex.
(The mutex's owner was is not nil when the deadlock happens, because the
code enters the mutex more than once, so that's normal.)
This deadlock doesn't happen in Pharo, because it uses the old
WeakRegistry >> #finalizeValues implementation which does the actual
finalization outside the critical section. I will soon upload a version of
the Collections package to the Inbox which does the same. With this code
it took 2.9 seconds to start the JVM on my notebook.
Levente
>
> Joachim
>
>
>
>
More information about the Squeak-dev
mailing list
|