On Aug 28, 2014, at 20:16, Anthony Petrov <anthony.pet...@oracle.com> wrote:

> JI-9014527 was closed as Incomplete "Not enough information.", supposedly 
> because there's not a reproducible test case and instructions to reproduce 
> the issue.

That is correct. I erroneously assumed that people reviewing bug reports would 
be interested in crashes, and their crashlogs, even if they do not contain 
step-by-step instructions on how to reproduce the issue.

> If you come up with a simple test that crashes easily, we can re-open that 
> bug.

I wish I could.

> BTW, from the full stack trace in the bug report I can see you're running 
> some accessibility software on your system because the crash happens during 
> an a11y callback. This may be a contributing factor to the crash. You will 
> need to test with and without a11y on, and also perhaps try another assistive 
> technology (e.g. the built-in VoiceOver vs. a third-party software) to see if 
> this changes anything.

Digging into the source code it becomes clear that

Java_sun_lwawt_macosx_LWCToolkit_stopAWTRunLoop is only called from 

 - sun.lwawt.macosx.CToolkitThreadBlockedHandler and
 - sun.lwawt.macosx.LWCToolkit


The call from LWCToolkit is coded defensively, i.e. it has a 0-check:

if (mediator != 0) {
    stopAWTRunLoop(mediator);
}

Therefore it cannot lead to the failure described in 
http://www.beatunes.com/download/stopAWTRunLoop.crash

The call from CToolkitThreadBlockedHandler is NOT coded defensively. To the 
contrary, it relies on the implicit contract, that the  exit() method is called 
at most once after the enter() method is called:

    public void exit() {
        if (!isOwned()) {
            throw new IllegalMonitorStateException();
        }
        LWCToolkit.stopAWTRunLoop(awtRunLoopMediator);
        awtRunLoopMediator = 0;
    }

It might be a good idea to simply guard against other classes using 
enter()/exit() in unintended ways by rewriting it defensively like this:

    public void enter() {
        if (!isOwned()) {
            throw new IllegalMonitorStateException();
        }
        if (awtRunLoopMediator != 0) {
            throw new IllegalStateException("Call exit() first.");
        }
        awtRunLoopMediator = LWCToolkit.createAWTRunLoopMediator();
        unlock();
        LWCToolkit.doAWTRunLoop(awtRunLoopMediator, processEvents);
        lock();
    }

    public void exit() {
        if (!isOwned()) {
            throw new IllegalMonitorStateException();
        }
        if (awtRunLoopMediator != 0) {
            LWCToolkit.stopAWTRunLoop(awtRunLoopMediator);
            awtRunLoopMediator = 0;
        }
    }

That said, enter() and exit() are only called from one place, 
sun.awt.datatransfer.DataTransferer#convertData(...).
My guess is, that for some reason getToolkitThreadBlockedHandler().exit(); is 
either called multiple times or LWCToolkit.createAWTRunLoopMediator() in 
CToolkitThreadBlockedHandler#enter() returns 0 for whatever reason.

Frankly, I don't quite understand how it can happen that the dataConverter 
Runnable in DataTransferer#convertData(...) is executed multiple times, but 
clearly it is a problem, as the code tries to guard against it. It does not do 
so in a threadsafe way though.

Anyhow.

I would appreciate it, if you considered reviewing both my suggestion for 
improving sun.lwawt.macosx.CToolkitThreadBlockedHandler and perhaps the code in 
sun.awt.datatransfer.DataTransferer to improve the stability of the Java VM on 
OS X.

Thank you.

-hendrik

Reply via email to