RFR: 8335231: [macos] Test java/awt/print/PrinterJob/Cancel/PrinterJobCancel.java failed on macOS because the case didn't get the expected PrintAbortException [v4]

Phil Race prr at openjdk.org
Sun Aug 4 21:47:34 UTC 2024


On Fri, 2 Aug 2024 04:51:13 GMT, Prasanta Sadhukhan <psadhukhan at openjdk.org> wrote:

>> When a printjob is cancelled midway, `PrinterAbortException `was not thrown in macos. because 
>> firstly,` cancelCheck` invokes` LWCToolkit.invokeLater` with null as parameter causing it to fail with NPE and
>> secondly PrinterAbortException was consumed silently when `printLoop` throws any exception
>> which is rectified to throw the PrinterAbortException when encountered..
>
> Prasanta Sadhukhan has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Use EventQueue.invokeLater

I think we still have some things to look at here

(1) The job still gets queued for printing - should it ? Ideally not if there's some thing we can do.
(2) The "Error during printing" dialog I get after running the test is from macOS not us. Should it happen ?
(3) There's also an NSException printed which is because a call to CHECK_EXCEPTION thinks
the pending Java Exception is an error from an upcall made after terminating the print loop.

Here is the NSException printed for (3) :

2024-08-02 13:34:54.360 java[50622:37988054] Java Exception
2024-08-02 13:34:54.360 java[50622:37988054] (
    0   CoreFoundation                      0x00007ff8045ed11a __exceptionPreprocess + 242
    1   libobjc.A.dylib                     0x00007ff8041120b7 objc_exception_throw + 48
    2   CoreFoundation                      0x00007ff8045ecf80 +[NSException raise:format:] + 214
    3   libawt_lwawt.dylib                  0x0000000127355ed8 -[PrinterView complete:] + 552
    4   libawt_lwawt.dylib                  0x0000000127354050 -[PrintModel safePrintLoop:withEnv:] + 176
    5   libawt_lwawt.dylib                  0x00000001272f68ef Java_sun_lwawt_macosx_CPrinterJob_printLoop + 3871
    6   ???                                 0x000000011455ca87 0x0 + 4636134023
)
 
Note it is not a Java Exception, it is an NSException and we log this from JNI_COCOA_EXIT after we catch it.
Perhaps we should only log this if a debugging flag is set .. but at least in this case it helped me see the problem (3).

So what's going on with (3)? - I can partly help explain that.
When we get an unexpected Java Exception from a JNI call and need to bail back up to Java we use NSException to do this.
Unexpected exceptions mean bad method lookups, eg up calls that create an unexpected exception etc.
If an NSException is raised Objective-C transfers control to the next "catch" - which is in this case JNI_COCOA_EXIT

This particular NSException happens because after the printLoop we need to make an up-call from "complete"

    (*env)->CallVoidMethod(env, fPrinterJob, jf_completePrintLoop);
    CHECK_EXCEPTION();

But there's this PrinterAbortException already pending, which means we really should not be making the up-call without clearing it first, which is another issue (#4, or still part of #3 ?)

After the upcall CHECK_EXCEPTION  sees a pending Java Exception which it supposes is from a problem during the upcall and raises the NSException to "bail" up to the JNI_COCOA_EXIT  where we catch it and log it as seen above.
So the NSExceptions do not escape to Java and the Java Exception is seen by Java - which is OK so far as it goes.
BUT we've jumped over a lot of printer job clean up which might contribute to (1) and (2) above but probably isn't the whole story.

So how can we get that PrinterAbortException back up to Java without causing problems for subsequent upcalls?
If we just remove the CHECK_EXCEPTION then that would probably do it, but really we should have that check.
If we don't make the call at all with a pending exception what does that do ?
Some special handling of this whole case seems likely to be needed but I don't have time to look into this deeply enough to test a solution.
Perhaps we could
(1) grab the exception
(2) clear it from the current thread, but we still have a ref - it is just a Java object !
(3) store it in some field of the CPrinterJob
(4)  then check for it and re-throw when we reach Java code. \

Don't forget about (1) - the job being queued.
I'm also unclear if the NSException is detected by the macOS printing code and plays a role in the popup.
Hmm, perhaps not, since I still get it if I comment that out. Perhaps this something else we are skipping past that has nothing to do with the NSException

-------------

PR Comment: https://git.openjdk.org/jdk/pull/20027#issuecomment-2267725000


More information about the client-libs-dev mailing list