Revert "JBR-8651 Pycharm Crashing after lock/sleep: SIGABRT at # C [libsystem_kernel.dylib+0x9388] __pthread_kill / __displaycb_handle_block_invoke"

This reverts commit 986d578731.
This commit is contained in:
bourgesl
2025-11-05 23:01:26 +01:00
committed by jbrbot
parent 0fe8c94936
commit ef22561af0
20 changed files with 318 additions and 790 deletions

View File

@@ -741,7 +741,8 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
DECLARE_CLASS_RETURN(jc_CPlatformView, "sun/lwawt/macosx/CPlatformView", NULL);
DECLARE_FIELD_RETURN(jf_Peer, jc_CPlatformView, "peer", "Lsun/lwawt/LWWindowPeer;", NULL);
if ((env == NULL) || (m_cPlatformView == NULL)) {
NSAPP_AWT_LOG_MESSAGE(@"Apple AWT: Error AWTView:awtComponent given bad parameters.");
NSLog(@"Apple AWT : Error AWTView:awtComponent given bad parameters.");
NSLog(@"%@",[NSThread callStackSymbols]);
return NULL;
}
@@ -754,7 +755,8 @@ static void debugPrintNSEvent(NSEvent* event, const char* comment) {
DECLARE_CLASS_RETURN(jc_LWWindowPeer, "sun/lwawt/LWWindowPeer", NULL);
DECLARE_FIELD_RETURN(jf_Target, jc_LWWindowPeer, "target", "Ljava/awt/Component;", NULL);
if (peer == NULL) {
NSAPP_AWT_LOG_MESSAGE(@"Apple AWT: Error AWTView:awtComponent got null peer from CPlatformView");
NSLog(@"Apple AWT : Error AWTView:awtComponent got null peer from CPlatformView");
NSLog(@"%@",[NSThread callStackSymbols]);
return NULL;
}
jobject comp = (*env)->GetObjectField(env, peer, jf_Target);

View File

@@ -232,9 +232,10 @@ AWT_NS_WINDOW_IMPLEMENTATION
};
void (*_objc_msgSendSuper)(struct objc_super *, SEL) = (void *)&objc_msgSendSuper; //cast our pointer so the compiler can sort out the ABI
(*_objc_msgSendSuper)(&mySuper, @selector(_changeJustMain));
} @catch (NSException *exception) {
} @catch (NSException *ex) {
NSLog(@"WARNING: suppressed exception from _changeJustMain (workaround for JBR-2562)");
NSAPP_AWT_LOG_EXCEPTION(exception);
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
[NSApplicationAWT logException:ex forProcess:processInfo];
}
}
@@ -1058,9 +1059,10 @@ AWT_ASSERT_APPKIT_THREAD;
NSRect frame;
@try {
frame = ConvertNSScreenRect(env, [self.nsWindow frame]);
} @catch (NSException *exception) {
} @catch (NSException *e) {
NSLog(@"WARNING: suppressed exception from ConvertNSScreenRect() in [AWTWindow _deliverMoveResizeEvent]");
NSAPP_AWT_LOG_EXCEPTION(exception);
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
[NSApplicationAWT logException:e forProcess:processInfo];
return;
}
@@ -1394,9 +1396,7 @@ AWT_ASSERT_APPKIT_THREAD;
jobject target = (*env)->GetObjectField(env, platformWindow, jf_target);
if (target) {
h = (CGFloat) (*env)->CallFloatMethod(env, target, jm_internalCustomTitleBarHeight);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
} else {
if (!(*env)->ExceptionCheck(env)) {
self.customTitleBarControlsVisible = (BOOL) (*env)->CallBooleanMethod(env, target, jm_internalCustomTitleBarControlsVisible);
}
(*env)->DeleteLocalRef(env, target);
@@ -1565,8 +1565,8 @@ AWT_ASSERT_APPKIT_THREAD;
GET_CPLATFORM_WINDOW_CLASS();
DECLARE_METHOD(jm_deliverNCMouseDown, jc_CPlatformWindow, "deliverNCMouseDown", "()V");
(*env)->CallVoidMethod(env, platformWindow, jm_deliverNCMouseDown);
(*env)->DeleteLocalRef(env, platformWindow);
CHECK_EXCEPTION();
(*env)->DeleteLocalRef(env, platformWindow);
}
}
}
@@ -2234,7 +2234,6 @@ JNI_COCOA_ENTER(env);
DECLARE_METHOD_RETURN(jm_isIgnoreMouseEvents, jc_Window, "isIgnoreMouseEvents", "()Z", 0);
isIgnoreMouseEvents = (*env)->CallBooleanMethod(env, awtWindow, jm_isIgnoreMouseEvents) == JNI_TRUE ? YES : NO;
(*env)->DeleteLocalRef(env, awtWindow);
CHECK_EXCEPTION();
}
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){

View File

@@ -126,7 +126,7 @@ AWT_ASSERT_APPKIT_THREAD;
BOOL isApplicationOwner = NO;
if (NSApp != nil) {
if ([NSApp isMemberOfClass:[NSApplication class]] && overrideDelegate) shouldInstall = YES;
if ([NSApplicationAWT isNSApplicationAWT]) {
if ([NSApp isKindOfClass:[NSApplicationAWT class]]) {
shouldInstall = YES;
isApplicationOwner = YES;
}
@@ -213,7 +213,7 @@ AWT_ASSERT_APPKIT_THREAD;
// Prep for about and preferences menu
BOOL usingDefaultNib = YES;
if ([NSApplicationAWT isNSApplicationAWT]) {
if ([NSApp isKindOfClass:[NSApplicationAWT class]]) {
usingDefaultNib = [NSApp usingDefaultNib];
}
if (!usingDefaultNib) return self;

View File

@@ -102,7 +102,6 @@ JNI_COCOA_ENTER(env);
// Pass the data to drop target:
@try {
(*env)->CallVoidMethod(env, jthis, newDataMethod, jformat, jdropdata); // AWT_THREADING Safe (!appKit)
CHECK_EXCEPTION();
} @catch (NSException *ex) {
DLog2(@"[CDropTargetContextPeer startTransfer]: exception in newData() for %d.\n", (NSInteger) jdroptarget);
(*env)->DeleteGlobalRef(env, jdropdata);

View File

@@ -116,7 +116,6 @@ static void displaycb_handle
(CGDirectDisplayID displayId, CGDisplayChangeSummaryFlags flags, void *userInfo)
{
AWT_ASSERT_APPKIT_THREAD;
JNIEnv *env = [ThreadUtilities getJNIEnv];
JNI_COCOA_ENTER(env);
if (TRACE_DISPLAY_CALLBACKS) {
@@ -153,6 +152,7 @@ JNI_COCOA_ENTER(env);
block:^()
{
@try {
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject graphicsEnv = (*env)->NewLocalRef(env, cgeRef);
if (graphicsEnv == NULL) return; // ref already GC'd
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");
@@ -173,6 +173,7 @@ JNI_COCOA_ENTER(env);
// braces to reduce variable scope
{
JNIEnv *env = [ThreadUtilities getJNIEnv];
jobject graphicsEnv = (*env)->NewLocalRef(env, cgeRef);
if (graphicsEnv == NULL) return; // ref already GC'd
DECLARE_CLASS(jc_CGraphicsEnvironment, "sun/awt/CGraphicsEnvironment");

View File

@@ -223,12 +223,6 @@ void JavaCT_DrawGlyphVector
// Using the Quartz Surface Data context, draw a hot-substituted character run
void JavaCT_DrawTextUsingQSD(JNIEnv *env, const QuartzSDOps *qsdo, const AWTStrike *strike, const jchar *chars, const jsize length)
{
NSAttributedString *attribString = nil;
CTTypesetterRef typeSetterRef = NULL;
CTLineRef lineRef = NULL;
JNI_COCOA_ENTER(env);
CGContextRef cgRef = qsdo->cgRef;
AWTFont *awtFont = strike->fAWTFont;
@@ -257,18 +251,20 @@ JNI_COCOA_ENTER(env);
CTTypesetterRef typeSetterRef = CTTypesetterCreateWithAttributedStringAndOptions((CFAttributedStringRef) attribString, (CFDictionaryRef) ctsDictionaryFor(nsFont, JRSFontStyleUsesFractionalMetrics(strike->fStyle)));
*/
attribString = [[NSAttributedString alloc]
NSAttributedString *attribString = [[NSAttributedString alloc]
initWithString:string
attributes:ctsDictionaryFor(nsFont, JRSFontStyleUsesFractionalMetrics(strike->fStyle))];
typeSetterRef = CTTypesetterCreateWithAttributedString((CFAttributedStringRef) attribString);
CTTypesetterRef typeSetterRef = CTTypesetterCreateWithAttributedString((CFAttributedStringRef) attribString);
CFRange range = {0, length};
lineRef = CTTypesetterCreateLine(typeSetterRef, range);
CTLineRef lineRef = CTTypesetterCreateLine(typeSetterRef, range);
CTLineDraw(lineRef, cgRef);
JNI_COCOA_EXIT_WITH_ACTION(env, ( [attribString release], CFRelease_even_NULL(lineRef), CFRelease_even_NULL(typeSetterRef) ) );
[attribString release];
CFRelease(lineRef);
CFRelease(typeSetterRef);
}
@@ -284,16 +280,16 @@ static void DrawTextContext
return;
}
JNI_COCOA_ENTER(env);
qsdo->BeginSurface(env, qsdo, SD_Text);
if (qsdo->cgRef == NULL)
{
qsdo->FinishSurface(env, qsdo);
return;
}
CGContextRef cgRef = qsdo->cgRef;
CGContextSaveGState(cgRef);
JRSFontSetRenderingStyleOnContext(cgRef, strike->fStyle);
@@ -307,7 +303,7 @@ JNI_COCOA_ENTER(env);
CGContextRestoreGState(cgRef);
JNI_COCOA_RENDERER_EXIT(env);
qsdo->FinishSurface(env, qsdo);
}
#pragma mark --- Glyph Vector Pipeline ---
@@ -532,34 +528,40 @@ static inline void doDrawGlyphsPipe_getGlyphVectorLengthAndAlloc
CGSize advances[length];
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
}
else {
CGGlyph *glyphs = NULL;
int *uniChars = NULL;
CGSize *advances = NULL;
@try {
// otherwise, we should malloc and free buffers for this large run
glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * length);
uniChars = (int *) malloc(sizeof(int) * length);
advances = (CGSize *) malloc(sizeof(CGSize) * length);
else
{
// otherwise, we should malloc and free buffers for this large run
CGGlyph *glyphs = (CGGlyph *)malloc(sizeof(CGGlyph) * length);
int *uniChars = (int *)malloc(sizeof(int) * length);
CGSize *advances = (CGSize *)malloc(sizeof(CGSize) * length);
if ((glyphs == NULL) || (uniChars == NULL) || (advances == NULL)) {
[NSException raise:NSMallocException format:@"allocation failure (%s:%d %s)", __FILE__, __LINE__, __FUNCTION__];
} else {
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
}
} @finally {
if (glyphs != NULL) {
if (glyphs == NULL || uniChars == NULL || advances == NULL)
{
(*env)->DeleteLocalRef(env, glyphsArray);
[NSException raise:NSMallocException format:@"%s-%s:%d", __FILE__, __FUNCTION__, __LINE__];
if (glyphs)
{
free(glyphs);
}
if (uniChars != NULL) {
if (uniChars)
{
free(uniChars);
}
if (advances != NULL) {
if (advances)
{
free(advances);
}
(*env)->DeleteLocalRef(env, glyphsArray);
return;
}
doDrawGlyphsPipe_fillGlyphAndAdvanceBuffers(env, qsdo, strike, gVector, glyphs, uniChars, advances, length, glyphsArray);
free(glyphs);
free(uniChars);
free(advances);
}
(*env)->DeleteLocalRef(env, glyphsArray);
}
// Setup and save the state of the CGContext, and apply any java.awt.Font transforms to the context.

View File

@@ -28,7 +28,6 @@
#import <objc/runtime.h>
#import <Cocoa/Cocoa.h>
#import <Security/AuthSession.h>
#import <ExceptionHandling/NSExceptionHandler.h>
#import "JNIUtilities.h"
#import "LWCToolkit.h"
@@ -204,22 +203,19 @@ static BOOL inDoDragDropLoop;
}
- (void)perform {
@try {
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
DECLARE_CLASS(sjc_Runnable, "java/lang/Runnable");
DECLARE_METHOD(jm_Runnable_run, sjc_Runnable, "run", "()V");
(*env)->CallVoidMethod(env, self.runnable, jm_Runnable_run);
CHECK_EXCEPTION();
} @finally {
[self release];
}
JNIEnv* env = [ThreadUtilities getJNIEnvUncached];
DECLARE_CLASS(sjc_Runnable, "java/lang/Runnable");
DECLARE_METHOD(jm_Runnable_run, sjc_Runnable, "run", "()V");
(*env)->CallVoidMethod(env, self.runnable, jm_Runnable_run);
CHECK_EXCEPTION();
[self release];
}
@end
void setBusy(BOOL busy) {
AWT_ASSERT_APPKIT_THREAD;
JNIEnv *env = [ThreadUtilities getJNIEnv];
JNI_COCOA_ENTER(env);
DECLARE_CLASS(jc_AWTAutoShutdown, "sun/awt/AWTAutoShutdown");
if (busy) {
@@ -229,8 +225,7 @@ void setBusy(BOOL busy) {
DECLARE_STATIC_METHOD(jm_notifyFreeMethod, jc_AWTAutoShutdown, "notifyToolkitThreadFree", "()V");
(*env)->CallStaticVoidMethod(env, jc_AWTAutoShutdown, jm_notifyFreeMethod);
}
CHECK_EXCEPTION();
JNI_COCOA_EXIT(env);
CHECK_EXCEPTION();
}
static void setUpAWTAppKit(BOOL installObservers)
@@ -274,6 +269,7 @@ static void setUpAWTAppKit(BOOL installObservers)
DECLARE_STATIC_METHOD(jsm_installToolkitThreadInJava, jc_LWCToolkit, "installToolkitThreadInJava", "()V");
(*env)->CallStaticVoidMethod(env, jc_LWCToolkit, jsm_installToolkitThreadInJava);
CHECK_EXCEPTION();
}
BOOL isSWTInWebStart(JNIEnv* env) {
@@ -281,6 +277,11 @@ BOOL isSWTInWebStart(JNIEnv* env) {
return [@"true" isCaseInsensitiveLike:swtWebStart];
}
static void AWT_NSUncaughtExceptionHandler(NSException *exception) {
NSLog(@"Apple AWT Internal Exception: %@", [exception description]);
NSLog(@"trace: %@", [exception callStackSymbols]);
}
@interface AWTStarter : NSObject
+ (void)start:(BOOL)headless;
+ (void)starter:(BOOL)onMainThread headless:(BOOL)headless;
@@ -373,73 +374,70 @@ BOOL isSWTInWebStart(JNIEnv* env) {
if (delegate != nil) {
OSXAPP_SetApplicationDelegate(delegate);
}
// Intercept any exception to let NSApplicationAWT handle them:
NSExceptionHandler* exceptionHandler = [NSExceptionHandler defaultExceptionHandler];
exceptionHandler.exceptionHandlingMask = NSLogAndHandleEveryExceptionMask;
[exceptionHandler setDelegate:[NSApplication sharedApplication]];
}];
}
}
+ (void)starter:(BOOL)wasOnMainThread headless:(BOOL)headless {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
@try {
// Headless mode trumps either ordinary AWT or SWT-in-AWT mode. Declare us a daemon and return.
if (headless) {
// Note that we don't install run loop observers in headless mode
// because we don't need them (see 7174704)
if (!forceEmbeddedMode) {
setUpAWTAppKit(false);
}
[AWTStarter markAppAsDaemon];
return;
// Add the exception handler of last resort
NSSetUncaughtExceptionHandler(AWT_NSUncaughtExceptionHandler);
// Headless mode trumps either ordinary AWT or SWT-in-AWT mode. Declare us a daemon and return.
if (headless) {
// Note that we don't install run loop observers in headless mode
// because we don't need them (see 7174704)
if (!forceEmbeddedMode) {
setUpAWTAppKit(false);
}
if (forceEmbeddedMode) {
AWT_STARTUP_LOG(@"in SWT or SWT/WebStart mode");
// Init a default NSApplication instance instead of the NSApplicationAWT.
// Note that [NSApp isRunning] will return YES after that, though
// this behavior isn't specified anywhere. We rely on that.
NSApplicationLoad();
}
// This will create a NSApplicationAWT for standalone AWT programs, unless there is
// already a NSApplication instance. If there is already a NSApplication instance,
// and -[NSApplication isRunning] returns YES, AWT is embedded inside another
// AppKit Application.
NSApplication *app = [NSApplicationAWT sharedApplication];
isEmbedded = ![NSApplicationAWT isNSApplicationAWT];
if (!isEmbedded) {
// Install run loop observers and set the AppKit Java thread name
setUpAWTAppKit(true);
}
// AWT gets to this point BEFORE NSApplicationDidFinishLaunchingNotification is sent.
if (![app isRunning]) {
AWT_STARTUP_LOG(@"+[AWTStarter startAWT]: ![app isRunning]");
// This is where the AWT AppKit thread parks itself to process events.
[NSApplicationAWT runAWTLoopWithApp:app];
} else {
// We're either embedded, or showing a splash screen
if (isEmbedded) {
AWT_STARTUP_LOG(@"running embedded");
// We don't track if the runloop is busy, so set it free to let AWT finish when it needs
setBusy(NO);
} else {
AWT_STARTUP_LOG(@"running after showing a splash screen");
}
// Signal so that JNI_OnLoad can proceed.
if (!wasOnMainThread) [AWTStarter appKitIsRunning:nil];
// Proceed to exit this call as there is no reason to run the NSApplication event loop.
}
} @finally {
[pool drain];
[AWTStarter markAppAsDaemon];
return;
}
if (forceEmbeddedMode) {
AWT_STARTUP_LOG(@"in SWT or SWT/WebStart mode");
// Init a default NSApplication instance instead of the NSApplicationAWT.
// Note that [NSApp isRunning] will return YES after that, though
// this behavior isn't specified anywhere. We rely on that.
NSApplicationLoad();
}
// This will create a NSApplicationAWT for standalone AWT programs, unless there is
// already a NSApplication instance. If there is already a NSApplication instance,
// and -[NSApplication isRunning] returns YES, AWT is embedded inside another
// AppKit Application.
NSApplication *app = [NSApplicationAWT sharedApplication];
isEmbedded = ![NSApp isKindOfClass:[NSApplicationAWT class]];
if (!isEmbedded) {
// Install run loop observers and set the AppKit Java thread name
setUpAWTAppKit(true);
}
// AWT gets to this point BEFORE NSApplicationDidFinishLaunchingNotification is sent.
if (![app isRunning]) {
AWT_STARTUP_LOG(@"+[AWTStarter startAWT]: ![app isRunning]");
// This is where the AWT AppKit thread parks itself to process events.
[NSApplicationAWT runAWTLoopWithApp: app];
} else {
// We're either embedded, or showing a splash screen
if (isEmbedded) {
AWT_STARTUP_LOG(@"running embedded");
// We don't track if the runloop is busy, so set it free to let AWT finish when it needs
setBusy(NO);
} else {
AWT_STARTUP_LOG(@"running after showing a splash screen");
}
// Signal so that JNI_OnLoad can proceed.
if (!wasOnMainThread) [AWTStarter appKitIsRunning:nil];
// Proceed to exit this call as there is no reason to run the NSApplication event loop.
}
[pool drain];
}
@end
@@ -454,8 +452,9 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_nativeSyncQueue
{
long currentEventNum = [AWTToolkit getEventCount];
NSApplicationAWT* app = [NSApplicationAWT sharedApplicationAWT];
if (app != nil) {
NSApplication* sharedApp = [NSApplication sharedApplication];
if ([sharedApp isKindOfClass:[NSApplicationAWT class]]) {
NSApplicationAWT* theApp = (NSApplicationAWT*)sharedApp;
// We use two different API to post events to the application,
// - [NSApplication postEvent]
// - CGEventPost(), see CRobot.m
@@ -466,30 +465,25 @@ JNIEXPORT jboolean JNICALL Java_sun_lwawt_macosx_LWCToolkit_nativeSyncQueue
// If the native drag is in progress, skip native sync.
if (!AWTToolkit.inDoDragDropLoop) {
@try {
[app postDummyEvent:false];
} @finally {
[app waitForDummyEvent:timeout / 2.0];
}
[theApp postDummyEvent:false];
[theApp waitForDummyEvent:timeout / 2.0];
}
// test the condition again as inDoDragDropLoop may have changed?
if (!AWTToolkit.inDoDragDropLoop) {
@try {
[app postDummyEvent:true];
} @finally {
[app waitForDummyEvent:timeout / 2.0];
}
[theApp postDummyEvent:true];
[theApp waitForDummyEvent:timeout / 2.0];
}
} else {
// could happen if we are embedded inside SWT application,
// in this case just spin a single empty block through
// the event loop to give it a chance to process pending events
[ThreadUtilities performOnMainThreadWaiting:YES block:[ThreadUtilities GetEmptyBlock]];
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){}];
}
if (([AWTToolkit getEventCount] - currentEventNum) != 0) {
return JNI_TRUE;
}
return JNI_FALSE;
}
@@ -502,7 +496,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_flushNativeSelectors
(JNIEnv *env, jclass clz)
{
JNI_COCOA_ENTER(env);
[ThreadUtilities performOnMainThreadWaiting:YES block:[ThreadUtilities GetEmptyBlock]];
[ThreadUtilities performOnMainThreadWaiting:YES block:^(){}];
JNI_COCOA_EXIT(env);
}
@@ -899,9 +893,6 @@ JNIEXPORT void JNICALL
Java_sun_lwawt_macosx_LWCToolkit_initIDs
(JNIEnv *env, jclass klass) {
// Add the exception handler of last resort:
GetAWTUncaughtExceptionHandler();
JNI_COCOA_ENTER(env);
gNumberOfButtons = sun_lwawt_macosx_LWCToolkit_BUTTONS;
@@ -923,7 +914,8 @@ Java_sun_lwawt_macosx_LWCToolkit_initIDs
return;
}
for (int i = 0; i < gNumberOfButtons; i++) {
int i;
for (i = 0; i < gNumberOfButtons; i++) {
gButtonDownMasks[i] = tmp[i];
}

View File

@@ -1339,7 +1339,6 @@ static void treeNodeExpandedCollapsedImpl(
const jobject cAccessibleGlobal = (*env)->NewGlobalRef(env, cAccessible);
if ((*env)->ExceptionCheck(env) == JNI_TRUE) {
(*env)->ExceptionDescribe(env);
if (cAccessibleGlobal != NULL) {
(*env)->DeleteGlobalRef(env, cAccessibleGlobal);
}
@@ -1528,7 +1527,7 @@ void nativeAnnounceAppKit(
JNIEnv* const env = [ThreadUtilities getJNIEnv];
if (env == NULL) { // unlikely
NSAPP_AWT_LOG_MESSAGE(@"Failed to get JNIEnv instance");
NSLog(@"%s: failed to get JNIEnv instance\n%@\n", __func__, [NSThread callStackSymbols]);
return; // I believe it's dangerous to go on announcing in that case
}

View File

@@ -49,7 +49,6 @@ JNIEXPORT JAWT_DrawingSurfaceInfo* JNICALL awt_DrawingSurface_GetDrawingSurfaceI
DECLARE_METHOD_RETURN(jm_getPointer, jc_PlatformComponent, "getPointer", "()J", NULL);
AWTSurfaceLayers *surfaceLayers = jlong_to_ptr((*env)->CallLongMethod(env, platformComponent, jm_getPointer));
// REMIND: assert(surfaceLayers)
CHECK_EXCEPTION();
dsi->platformInfo = surfaceLayers;
dsi->ds = ds;

View File

@@ -1087,8 +1087,7 @@ extern void initSamplers(id<MTLDevice> device);
}
CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* nowTime, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) {
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
JNI_COCOA_ENTER(env);
JNI_COCOA_ENTER();
J2dTraceLn(J2D_TRACE_VERBOSE, "MTLContext_mtlDisplayLinkCallback: ctx=%p", displayLinkContext);
MTLDisplayLinkState *dlState = (__bridge MTLDisplayLinkState*) displayLinkContext;
@@ -1131,7 +1130,7 @@ CVReturn mtlDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp*
[ThreadUtilities performOnMainThread:@selector(redraw:) on:mtlc withObject:@(displayID)
waitUntilDone:NO useJavaModes:NO]; // critical
JNI_COCOA_EXIT(env);
JNI_COCOA_EXIT();
return kCVReturnSuccess;
}

View File

@@ -37,7 +37,6 @@ void
MTLGC_DestroyMTLGraphicsConfig(jlong pConfigInfo)
{
J2dTraceLn(J2D_TRACE_INFO, "MTLGC_DestroyMTLGraphicsConfig");
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
JNI_COCOA_ENTER(env);
__block MTLGraphicsConfigInfo *mtlinfo = (MTLGraphicsConfigInfo *)jlong_to_ptr(pConfigInfo);
if (mtlinfo == NULL) {

View File

@@ -569,7 +569,9 @@ Java_sun_java2d_metal_MTLLayer_nativeCreateLayer
(JNIEnv *env, jobject obj, jboolean perfCountersEnabled)
{
__block MTLLayer *layer = nil;
JNI_COCOA_ENTER(env);
JNI_COCOA_ENTER(env);
jobject javaLayer = (*env)->NewWeakGlobalRef(env, obj);
// Wait and ensure main thread creates the MTLLayer instance now:
@@ -581,7 +583,8 @@ Java_sun_java2d_metal_MTLLayer_nativeCreateLayer
if (TRACE_DISPLAY) {
J2dRlsTraceLn(J2D_TRACE_INFO, "MTLLayer_nativeCreateLayer: created layer[%p]", layer);
}
JNI_COCOA_EXIT(env);
JNI_COCOA_EXIT(env);
return ptr_to_jlong(layer);
}
@@ -590,7 +593,6 @@ JNIEXPORT void JNICALL
Java_sun_java2d_metal_MTLLayer_validate
(JNIEnv *env, jclass cls, jlong layerPtr, jobject surfaceData)
{
JNI_COCOA_ENTER(env);
MTLLayer *layer = OBJC(layerPtr);
if (surfaceData != NULL) {
@@ -642,7 +644,6 @@ Java_sun_java2d_metal_MTLLayer_validate
layer.ctx = NULL;
[layer stopRedraw:YES];
}
JNI_COCOA_EXIT(env);
}
JNIEXPORT void JNICALL
@@ -687,6 +688,7 @@ Java_sun_java2d_metal_MTLLayer_blitTexture
}
return;
}
[layer blitTexture];
JNI_COCOA_EXIT(env);
}
@@ -696,11 +698,13 @@ Java_sun_java2d_metal_MTLLayer_nativeSetOpaque
(JNIEnv *env, jclass cls, jlong layerPtr, jboolean opaque)
{
JNI_COCOA_ENTER(env);
MTLLayer *layer = jlong_to_ptr(layerPtr);
// Ensure main thread changes the MTLLayer instance later:
[ThreadUtilities performOnMainThreadWaiting:NO useJavaModes:NO // critical
block:^(){
[layer setOpaque:(opaque == JNI_TRUE)];
}];
JNI_COCOA_EXIT(env);
}

View File

@@ -62,7 +62,7 @@ static const char* mtlOpToStr(uint op);
BOOL sync = NO; \
jint opcode = -1; \
const NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; \
@try {
@try
/*
* Derived from JNI_COCOA_EXIT(env):
@@ -70,18 +70,23 @@ static const char* mtlOpToStr(uint op);
* If there is a Java exception that has been thrown that should escape.
* And ensure we drain the auto-release pool.
*/
#define RENDER_LOOP_EXIT(env, className) \
} @catch (NSException *exception) { \
#define RENDER_LOOP_EXIT(env, className) \
@catch (NSException *e) { \
lwc_plog(env, "%s_flushBuffer: Failed opcode=%s op=%s dstType=%s ctx=%p", \
className, mtlOpCodeToStr(opcode), mtlOpToStr(mtlPreviousOp), \
mtlDstTypeToStr(DST_TYPE(dstOps)), mtlc); \
char* str = [NSString stringWithFormat:@"%@", [e description]].UTF8String; \
lwc_plog(env, "%s_flushBuffer Exception: %s", className, str); \
str = [NSString stringWithFormat:@"%@", [e callStackSymbols]].UTF8String; \
lwc_plog(env, "%s_flushBuffer callstack: %s", className, str); \
/* Finally (JetBrains Runtime only) report this message to JVM crash log: */ \
JNU_LOG_EVENT(env, "%s_flushBuffer: Failed opcode=%s op=%s dstType=%s ctx=%p", \
className, mtlOpCodeToStr(opcode), mtlOpToStr(mtlPreviousOp), \
mtlDstTypeToStr(DST_TYPE(dstOps)), mtlc); \
/* report exception to the NSApplicationAWT exception handler: */ \
NSAPP_AWT_REPORT_EXCEPTION(exception, NO); \
} @finally { \
/* report fatal failure to make a crash report: */ \
JNU_Fatal(env, __FILE__, __LINE__, "flushBuffer failed"); \
} \
@finally { \
/* flush GPU state before draining pool: */ \
MTLRenderQueue_reset(mtlc, sync); \
[pool drain]; \
@@ -172,7 +177,7 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
// Handle any NSException thrown:
RENDER_LOOP_ENTER(env)
{
while (b < end) {
opcode = NEXT_INT(b);
@@ -953,7 +958,7 @@ Java_sun_java2d_metal_MTLRenderQueue_flushBuffer
return;
}
} // while op
}
RENDER_LOOP_EXIT(env, "MTLRenderQueue");
}

View File

@@ -172,13 +172,8 @@ MTLSD_SetNativeDimensions(JNIEnv *env, BMTLSDOps *mtlsdo,
}
JNU_SetFieldByName(env, NULL, sdObject, "nativeWidth", "I", width);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
} else {
if (!((*env)->ExceptionCheck(env))) {
JNU_SetFieldByName(env, NULL, sdObject, "nativeHeight", "I", height);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
}
}
(*env)->DeleteLocalRef(env, sdObject);
@@ -220,12 +215,8 @@ MTLSD_Delete(JNIEnv *env, BMTLSDOps *bmtlsdo)
void
MTLSD_Dispose(JNIEnv *env, SurfaceDataOps *ops)
{
jboolean exc;
JNU_CallStaticMethodByName(env, &exc, "sun/java2d/metal/MTLSurfaceData",
JNU_CallStaticMethodByName(env, NULL, "sun/java2d/metal/MTLSurfaceData",
"dispose", "(J)V", ptr_to_jlong(ops));
if (exc) {
(*env)->ExceptionDescribe(env);
}
}
/**

View File

@@ -28,18 +28,15 @@
#include "jni.h"
#include "jni_util.h"
#include "ThreadUtilities.h"
#import <Cocoa/Cocoa.h>
/* Define to 1 to check for pending exceptions in JNI_COCOA_EXIT */
#define CHECK_PENDING_EXCEPTION 0
/******** LOGGING SUPPORT *********/
#define LOG_NULL(dst_var, name) \
if (dst_var == NULL) { \
NSLog(@"Bad JNI lookup %s\n%@", name, [NSThread callStackSymbols]); \
NSLog(@"Bad JNI lookup %s\n", name); \
NSLog(@"%@",[NSThread callStackSymbols]); \
if ([NSThread isMainThread] == NO) { \
if (!(*env)->ExceptionCheck(env)) { \
JNU_ThrowInternalError(env, "Bad JNI Lookup"); \
@@ -189,36 +186,22 @@
#define CHECK_EXCEPTION_IN_ENV(env) { \
jthrowable exc = (*(env))->ExceptionOccurred(env); \
if (exc != NULL) { \
if ([NSThread isMainThread]) { \
if ([NSThread isMainThread] == YES) { \
if (getenv("JNU_APPKIT_TRACE")) { \
(*(env))->ExceptionDescribe(env); \
NSLog(@"%@", [NSThread callStackSymbols]); \
NSLog(@"%@",[NSThread callStackSymbols]); \
} else { \
(*(env))->ExceptionClear(env); \
} \
} \
(*env)->ExceptionClear(env); \
} \
if (getenv("JNU_NO_COCOA_EXCEPTION") == NULL) {\
[NSException raise:NSGenericException \
format:@"%@", ThrowableToNSString(env, exc)]; \
} else { \
(*(env))->ExceptionClear(env); \
} \
} \
}
/*
* Use this macro to raise an NSException.
* The message is a printf-style format string.
* The arguments are the arguments to the format string.
*
* ONLY FOR DEBUGGING PURPOSES.
* for example:
* TEST_RAISE_EXCEPTION(@"LWCToolkit.setBusy: busy = %d", busy);
*/
#define TEST_RAISE_EXCEPTION(message, ...) { \
[NSException raise:NSGenericException \
format:@"RAISE_EXCEPTION in (%s:%d %s): %@", \
__FILE__, __LINE__, __FUNCTION__, \
[NSString stringWithFormat:message, ##__VA_ARGS__] \
]; \
}
};
#define CHECK_EXCEPTION() CHECK_EXCEPTION_IN_ENV(env)
@@ -226,21 +209,7 @@
CHECK_EXCEPTION(); \
if ((x) == NULL) { \
return y; \
}
#define __JNI_LOG_EXCEPTION(exception) \
NSAPP_AWT_LOG_EXCEPTION_PREFIX(exception, @"Apple AWT Cocoa Exception");
#if (CHECK_PENDING_EXCEPTION == 1)
#define __JNI_CHECK_PENDING_EXCEPTION(env) \
@try { \
CHECK_EXCEPTION_IN_ENV(env); \
} @catch (NSException *exception) { \
__JNI_LOG_EXCEPTION(exception); \
}
#else
#define __JNI_CHECK_PENDING_EXCEPTION(env) {}
#endif
};
/* Create a pool and initiate a try block to catch any exception */
#define JNI_COCOA_ENTER(env) \
@@ -252,24 +221,28 @@
* And ensure we drain the auto-release pool.
*/
#define JNI_COCOA_EXIT(env) \
} @catch (NSException *exception) { \
__JNI_LOG_EXCEPTION(exception); \
} @finally { \
__JNI_CHECK_PENDING_EXCEPTION(env); \
} \
@catch (NSException *e) { \
NSLog(@"Apple AWT Cocoa Exception: %@", [e description]); \
NSLog(@"Apple AWT Cocoa Exception callstack: %@", [e callStackSymbols]); \
} \
@finally { \
[pool drain]; \
}
};
/* Same as above but adds a clean up action.
* Requires that whatever is being cleaned up is in scope.
*/
#define JNI_COCOA_EXIT_WITH_ACTION(env, action) \
} @catch (NSException *exception) { \
__JNI_LOG_EXCEPTION(exception); \
} \
@catch (NSException *e) { \
{ action; }; \
} @finally { \
__JNI_CHECK_PENDING_EXCEPTION(env); \
NSLog(@"Apple AWT Cocoa Exception: %@", [e description]); \
NSLog(@"Apple AWT Cocoa Exception callstack: %@", [e callStackSymbols]); \
} \
@finally { \
[pool drain]; \
}
};
/******** STRING CONVERSION SUPPORT *********/

View File

@@ -115,6 +115,8 @@ jstring NormalizedPathJavaStringFromNSString(JNIEnv* env, NSString *str) {
}
NSString *ThrowableToNSString(JNIEnv *env, jthrowable exc) {
(*env)->ExceptionClear(env);
if (JNU_IsInstanceOfByName(env, exc, "java/lang/OutOfMemoryError")) {
static NSString* const OOMEDescr = @"OutOfMemoryError";
return OOMEDescr;
@@ -126,26 +128,17 @@ NSString *ThrowableToNSString(JNIEnv *env, jthrowable exc) {
DECLARE_METHOD_RETURN(jm_getStackTrace, sjc_Throwable, "getStackTrace",
"()[Ljava/lang/StackTraceElement;", nil);
jobject jstr = (*env)->CallObjectMethod(env, exc, jm_toString);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
}
NSString* result = JavaStringToNSString(env, jstr);
jobjectArray frames =
(jobjectArray) (*env)->CallObjectMethod(env, exc, jm_getStackTrace);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
}
if (frames != NULL) {
jsize framesLen = (*env)->GetArrayLength(env, frames);
for (int i = 0; i < framesLen; i++) {
jobject stackElem = (*env)->GetObjectArrayElement(env, frames, i);
jobject stackElemStr = (*env)->CallObjectMethod(env, stackElem, jm_toString);
if ((*env)->ExceptionCheck(env)) {
(*env)->ExceptionDescribe(env);
}
NSString *frameStr = JavaStringToNSString(env, stackElemStr);
result = [result stringByAppendingFormat:@"\n%@", frameStr];
(*env)->DeleteLocalRef(env, stackElem);
@@ -157,3 +150,4 @@ NSString *ThrowableToNSString(JNIEnv *env, jthrowable exc) {
return result;
}

View File

@@ -41,24 +41,7 @@ JNIEXPORT @interface NSApplicationAWT : NSApplication {
- (void) waitForDummyEvent:(double) timeout;
+ (void) runAWTLoopWithApp:(NSApplication*)app;
+ (void) interruptAWTLoop;
+ (BOOL) isNSApplicationAWT;
+ (NSApplicationAWT*) sharedApplicationAWT;
- (void) reportException:(NSException *)exception;
- (void) reportException:(NSException *)exception uncaught:(BOOL)uncaught
file:(const char*)file line:(int)line function:(const char*)function;
+ (void) logException:(NSException *)exception;
+ (void) logException:(NSException *)exception
file:(const char*)file line:(int)line function:(const char*)function;
+ (void) logException:(NSException *)exception prefix:(NSString *)prefix
file:(const char*)file line:(int)line function:(const char*)function;
+ (void) logMessage:(NSString *)message;
+ (void) logMessage:(NSString *)message
file:(const char*)file line:(int)line function:(const char*)function;
+ (void)logException:(NSException *)exception forProcess:(NSProcessInfo*)processInfo;
@end
@@ -70,3 +53,4 @@ JNIEXPORT @interface NSApplicationAWT : NSApplication {
@end
JNIEXPORT void OSXAPP_SetApplicationDelegate(id <NSApplicationDelegate> delegate);

View File

@@ -26,7 +26,6 @@
#import "NSApplicationAWT.h"
#import <objc/runtime.h>
#import <ExceptionHandling/NSExceptionHandler.h>
#import <JavaRuntimeSupport/JavaRuntimeSupport.h>
#import "PropertiesUtilities.h"
@@ -39,17 +38,6 @@
*/
DEF_STATIC_JNI_OnLoad
/* may be worth to use system properties ? */
#define MAX_RETRY_WRITE_EXCEPTION 3
#define MAX_WRITE_EXCEPTION 50
#define MAX_LOGGED_EXCEPTION 1000
#define JBR_ERR_PID_FILE @"%@/jbr_err_pid%d.log"
/** JBR file pattern with extra count parameter (see MAX_WRITE_EXCEPTION) */
#define JBR_ERR_PID_FILE_COUNT @"%@/jbr_err_pid%d-%02d.log"
#define NO_FILE_LINE_FUNCTION_ARGS file:nil line:0 function:nil
static BOOL sUsingDefaultNIB = YES;
static NSString *SHARED_FRAMEWORK_BUNDLE = @"/System/Library/Frameworks/JavaVM.framework";
static id <NSApplicationDelegate> applicationDelegate = nil;
@@ -135,14 +123,9 @@ AWT_ASSERT_APPKIT_THREAD;
[NSBundle loadNibFile:defaultNibFile externalNameTable: [NSDictionary dictionaryWithObject:self forKey:@"NSOwner"] withZone:nil];
// Set user defaults to not try to parse application arguments.
NSDictionary *defaults = [NSDictionary dictionaryWithObjectsAndKeys:
(shouldCrashOnException() ? @"YES" : @"NO"), @"NSApplicationCrashOnExceptions",
@"NO", @"NSTreatUnknownArgumentsAsOpen",
/* fix for JBR-3127 Modal dialogs invoked from modal or floating dialogs are opened in full screen */
@"NO", @"NSWindowAllowsImplicitFullScreen",
nil];
[[NSUserDefaults standardUserDefaults] registerDefaults:defaults];
NSUserDefaults * defs = [NSUserDefaults standardUserDefaults];
NSDictionary * noOpenDict = [NSDictionary dictionaryWithObject:@"NO" forKey:@"NSTreatUnknownArgumentsAsOpen"];
[defs registerDefaults:noOpenDict];
// Fix up the dock icon now that we are registered with CAS and the Dock.
[self setDockIconWithEnv:env];
@@ -174,6 +157,9 @@ AWT_ASSERT_APPKIT_THREAD;
[super finishLaunching];
// fix for JBR-3127 Modal dialogs invoked from modal or floating dialogs are opened in full screen
[defs setBool:NO forKey:@"NSWindowAllowsImplicitFullScreen"];
// temporary possibility to load deprecated NSJavaVirtualMachine (just for testing)
// todo: remove when completely tested on BigSur
// see https://youtrack.jetbrains.com/issue/JBR-3127#focus=Comments-27-4684465.0-0
@@ -333,6 +319,8 @@ AWT_ASSERT_APPKIT_THREAD;
}
+ (void) runAWTLoopWithApp:(NSApplication*)app {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
// Define the special Critical RunLoop mode to ensure action executed ASAP:
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:[ThreadUtilities criticalRunLoopMode]];
@@ -340,36 +328,20 @@ AWT_ASSERT_APPKIT_THREAD;
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:[ThreadUtilities javaRunLoopMode]];
do {
NSAutoreleasePool *pool = [NSAutoreleasePool new];
@try {
[app run];
} @catch (NSException *exception) {
NSLog(@"Apple AWT runAWTLoop Exception: %@\nCallstack: %@",
[exception description], [exception callStackSymbols]);
} @catch (NSException* e) {
NSLog(@"Apple AWT Startup Exception: %@", [e description]);
NSLog(@"Apple AWT Startup Exception callstack: %@", [e callStackSymbols]);
NSLog(@"Apple AWT Restarting Native Event Thread");
// interrupt the run loop now:
[NSApplicationAWT interruptAWTLoop];
} @ finally {
[pool drain];
[app stop:app];
}
} while (YES);
}
/*
* Thread-safe:
* stop the shared application (run loop [NSApplication run])
* and restart it
*/
+ (void) interruptAWTLoop {
NSLog(@"Apple AWT Restarting Native Event Thread...");
NSApplication *app = [NSApplicationAWT sharedApplication];
// mark the current run loop [NSApplication run] to be stopped:
[app stop:app];
// send event to interrupt the run loop now (after the current event is processed):
[app abortModal];
[pool drain];
}
- (BOOL)usingDefaultNib {
return sUsingDefaultNIB;
}
@@ -408,34 +380,27 @@ untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)deqFlag {
// NSTimeInterval has microseconds precision
#define TS_EQUAL(ts1, ts2) (fabs((ts1) - (ts2)) < 1e-6)
- (void)sendEvent:(NSEvent *)event {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@try {
if ([event type] == NSApplicationDefined
&& TS_EQUAL([event timestamp], dummyEventTimestamp)
&& (short)[event subtype] == NativeSyncQueueEvent
&& [event data1] == NativeSyncQueueEvent
&& [event data2] == NativeSyncQueueEvent) {
[seenDummyEventLock lockWhenCondition:NO];
[seenDummyEventLock unlockWithCondition:YES];
} else if ([event type] == NSApplicationDefined
&& (short)[event subtype] == ExecuteBlockEvent
&& [event data1] != 0 && [event data2] == ExecuteBlockEvent) {
void (^block)() = (void (^)()) [event data1];
block();
[block release];
} else if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSCommandKeyMask)) {
// Cocoa won't send us key up event when releasing a key while Cmd is down,
// so we have to do it ourselves.
[[self keyWindow] sendEvent:event];
} else {
[super sendEvent:event];
}
} @catch (NSException *exception) {
// report exception to the NSApplicationAWT exception handler:
NSAPP_AWT_REPORT_EXCEPTION(exception, NO);
} @finally {
[pool drain];
- (void)sendEvent:(NSEvent *)event
{
if ([event type] == NSApplicationDefined
&& TS_EQUAL([event timestamp], dummyEventTimestamp)
&& (short)[event subtype] == NativeSyncQueueEvent
&& [event data1] == NativeSyncQueueEvent
&& [event data2] == NativeSyncQueueEvent) {
[seenDummyEventLock lockWhenCondition:NO];
[seenDummyEventLock unlockWithCondition:YES];
} else if ([event type] == NSApplicationDefined
&& (short)[event subtype] == ExecuteBlockEvent
&& [event data1] != 0 && [event data2] == ExecuteBlockEvent) {
void (^block)() = (void (^)()) [event data1];
block();
[block release];
} else if ([event type] == NSEventTypeKeyUp && ([event modifierFlags] & NSCommandKeyMask)) {
// Cocoa won't send us key up event when releasing a key while Cmd is down,
// so we have to do it ourselves.
[[self keyWindow] sendEvent:event];
} else {
[super sendEvent:event];
}
}
@@ -448,23 +413,19 @@ untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)deqFlag {
{
void (^copy)() = [block copy];
NSInteger encode = (NSInteger) copy;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@try {
NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
location: NSMakePoint(0,0)
modifierFlags: 0
timestamp: 0
windowNumber: 0
context: nil
subtype: ExecuteBlockEvent
data1: encode
data2: ExecuteBlockEvent];
NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
location: NSMakePoint(0,0)
modifierFlags: 0
timestamp: 0
windowNumber: 0
context: nil
subtype: ExecuteBlockEvent
data1: encode
data2: ExecuteBlockEvent];
[NSApp postEvent: event atStart: NO];
} @finally {
[pool drain];
}
[NSApp postEvent: event atStart: NO];
[pool drain];
}
- (void)postDummyEvent:(bool)useCocoa {
@@ -472,272 +433,86 @@ untilDate:(NSDate *)expiration inMode:(NSString *)mode dequeue:(BOOL)deqFlag {
dummyEventTimestamp = [NSProcessInfo processInfo].systemUptime;
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@try {
NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
location: NSMakePoint(0,0)
modifierFlags: 0
timestamp: dummyEventTimestamp
windowNumber: 0
context: nil
subtype: NativeSyncQueueEvent
data1: NativeSyncQueueEvent
data2: NativeSyncQueueEvent];
if (useCocoa) {
[NSApp postEvent:event atStart:NO];
} else {
ProcessSerialNumber psn;
GetCurrentProcess(&psn);
CGEventPostToPSN(&psn, [event CGEvent]);
}
} @finally {
[pool drain];
NSEvent* event = [NSEvent otherEventWithType: NSApplicationDefined
location: NSMakePoint(0,0)
modifierFlags: 0
timestamp: dummyEventTimestamp
windowNumber: 0
context: nil
subtype: NativeSyncQueueEvent
data1: NativeSyncQueueEvent
data2: NativeSyncQueueEvent];
if (useCocoa) {
[NSApp postEvent:event atStart:NO];
} else {
ProcessSerialNumber psn;
GetCurrentProcess(&psn);
CGEventPostToPSN(&psn, [event CGEvent]);
}
[pool drain];
}
- (void)waitForDummyEvent:(double)timeout {
bool unlock = true;
@try {
if (timeout >= 0) {
double sec = timeout / 1000;
unlock = [seenDummyEventLock lockWhenCondition:YES
beforeDate:[NSDate dateWithTimeIntervalSinceNow:sec]];
} else {
[seenDummyEventLock lockWhenCondition:YES];
}
if (unlock) {
[seenDummyEventLock unlock];
}
} @finally {
[seenDummyEventLock release];
seenDummyEventLock = nil;
if (timeout >= 0) {
double sec = timeout / 1000;
unlock = [seenDummyEventLock lockWhenCondition:YES
beforeDate:[NSDate dateWithTimeIntervalSinceNow:sec]];
} else {
[seenDummyEventLock lockWhenCondition:YES];
}
}
// Provide helper methods to get the shared NSApplicationAWT instance
+ (BOOL) isNSApplicationAWT {
return [NSApp isKindOfClass:[NSApplicationAWT class]];
}
+ (NSApplicationAWT*) sharedApplicationAWT {
return [NSApplicationAWT isNSApplicationAWT] ? (NSApplicationAWT*)[NSApplication sharedApplication] : nil;
}
// Provide info from unhandled ObjectiveC exceptions
/*
* Handle all exceptions handled by NSApplication.
*
* Note: depending on the userDefaults.NSApplicationCrashOnExceptions (YES/ NO) flag,
* (set in finishLaunching), calling with crash or not the JVM.
*/
- (void) reportException:(NSException *)exception {
[self reportException:exception uncaught:NO NO_FILE_LINE_FUNCTION_ARGS];
}
- (void) _crashOnException:(NSException *)exception {
[self crashOnException:exception uncaught:NO withEnv:[ThreadUtilities getJNIEnvUncached] NO_FILE_LINE_FUNCTION_ARGS];
}
// implementation (internals)
- (void) reportException:(NSException *)exception uncaught:(BOOL)uncaught
file:(const char*)file line:(int)line function:(const char*)function
{
@autoreleasepool {
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
if (shouldCrashOnException()) {
// calling [super reportException:exception] will cause a crash
// so _crashOnException:exception will be then called but losing details.
// Use the direct approach (full details):
[self crashOnException:exception uncaught:uncaught withEnv:env
file:file line:line function:function];
} else {
NSMutableString *info = [[[NSMutableString alloc] init] autorelease];
[NSApplicationAWT logException:exception uncaught:uncaught forProcess:[NSProcessInfo processInfo]
withEnv:env prefix:@"Reported " to:info file:file line:line function:function];
// interrupt the run loop now:
[NSApplicationAWT interruptAWTLoop];
}
if (unlock) {
[seenDummyEventLock unlock];
}
[seenDummyEventLock release];
seenDummyEventLock = nil;
}
- (void) crashOnException:(NSException *)exception uncaught:(BOOL)uncaught withEnv:(JNIEnv *)env
file:(const char*)file line:(int)line function:(const char*)function
{
//Provide info from unhandled ObjectiveC exceptions
+ (void)logException:(NSException *)exception forProcess:(NSProcessInfo*)processInfo {
@autoreleasepool {
NSMutableString *info = [[[NSMutableString alloc] init] autorelease];
[NSApplicationAWT logException:exception uncaught:uncaught forProcess:[NSProcessInfo processInfo]
withEnv:env prefix:@"Crash: " to:info file:file line:line function:function];
[info appendString:
[NSString stringWithFormat:
@"Exception in NSApplicationAWT:\n %@\n",
exception]];
if (shouldCrashOnException()) {
// Use JNU_Fatal macro to trigger JVM fatal error with the esception information and generate hs_err_ file
JNU_Fatal(env, __FILE__, __LINE__, [info UTF8String]); \
}
}
}
NSArray<NSString *> *stack = [exception callStackSymbols];
// log exception methods
+ (void) logException:(NSException *)exception {
[NSApplicationAWT logException:exception NO_FILE_LINE_FUNCTION_ARGS];
}
+ (void) logException:(NSException *)exception
file:(const char*)file line:(int)line function:(const char*)function
{
[NSApplicationAWT logException:exception prefix:@"Log: "
file:file line:line function:function];
}
+ (void) logException:(NSException *)exception prefix:(NSString *)prefix
file:(const char*)file line:(int)line function:(const char*)function
{
@autoreleasepool {
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
NSMutableString *info = [[[NSMutableString alloc] init] autorelease];
[NSApplicationAWT logException:exception uncaught:NO forProcess:[NSProcessInfo processInfo]
withEnv:env prefix:prefix to:info
file:file line:line function:function];
}
}
+ (void) logException:(NSException *)exception uncaught:(BOOL)uncaught forProcess:(NSProcessInfo *)processInfo
withEnv:(JNIEnv *)env prefix:(NSString *)prefix to:(NSMutableString *)info
file:(const char*)file line:(int)line function:(const char*)function
{
static int loggedException = 0;
static int writtenException = 0;
if (loggedException < MAX_LOGGED_EXCEPTION) {
[NSApplicationAWT toString:exception uncaught:uncaught prefix:prefix to:info
file:file line:line function:function];
[NSApplicationAWT logMessage:info withEnv:env];
if (++loggedException == MAX_LOGGED_EXCEPTION) {
NSLog(@"Stop logging follow-up exceptions (max %d logged exceptions reached)",
MAX_LOGGED_EXCEPTION);
for (NSUInteger i = 0; i < stack.count; i++) {
[info appendString:stack[i]];
[info appendString:@"\n"];
}
if (writtenException < MAX_WRITE_EXCEPTION) {
const NSString *homePath = [processInfo environment][@"HOME"];
if (homePath != nil) {
const int processID = [processInfo processIdentifier];
const NSString *fileName = [NSString stringWithFormat:JBR_ERR_PID_FILE, homePath, processID];
NSLog(@"%@", info);
BOOL available = NO;
int retry = 0;
NSString *realFileName = nil;
int count = 0;
do {
realFileName = (count == 0) ? fileName :
[NSString stringWithFormat:JBR_ERR_PID_FILE_COUNT, homePath, processID, count];
int processID = [processInfo processIdentifier];
NSDictionary *env = [[NSProcessInfo processInfo] environment];
NSString *homePath = env[@"HOME"];
if (homePath != nil) {
NSString *fileName =
[NSString stringWithFormat:@"%@/jbr_err_pid%d.log",
homePath, processID];
available = ![[NSFileManager defaultManager] fileExistsAtPath:realFileName];
if (available) {
NSLog(@"Writing exception to '%@'...", realFileName);
// write the exception atomatically to the file:
if ([info writeToFile:realFileName
atomically:YES
encoding:NSUTF8StringEncoding
error:NULL])
{
if (++writtenException == MAX_WRITE_EXCEPTION) {
NSLog(@"Stop writing follow-up exceptions (max %d written exceptions reached)",
MAX_WRITE_EXCEPTION);
}
} else {
if (++retry >= MAX_RETRY_WRITE_EXCEPTION) {
NSLog(@"Failed to write exception to '%@' after %d retries", realFileName,
MAX_RETRY_WRITE_EXCEPTION);
break;
}
// retry few times:
available = NO;
}
}
count++;
} while (!available);
if (![[NSFileManager defaultManager] fileExistsAtPath:fileName]) {
[info writeToFile:fileName
atomically:YES
encoding:NSUTF8StringEncoding
error:NULL];
}
}
}
}
+ (void) logMessage:(NSString *)message {
[NSApplicationAWT logMessage:message NO_FILE_LINE_FUNCTION_ARGS];
- (void)_crashOnException:(NSException *)exception {
NSProcessInfo *processInfo = [NSProcessInfo processInfo];
[NSApplicationAWT logException:exception
forProcess:processInfo];
// Use SIGILL to generate hs_err_ file as well
kill([processInfo processIdentifier], SIGILL);
}
+ (void) logMessage:(NSString *)message
file:(const char*)file line:(int)line function:(const char*)function
{
@autoreleasepool {
[NSApplicationAWT logMessage:message
callStackSymbols:[NSThread callStackSymbols]
withEnv:[ThreadUtilities getJNIEnvUncached]
file:file line:line function:function];
}
}
+ (void) logMessage:(NSString *)message callStackSymbols:(NSArray<NSString *> *)callStackSymbols withEnv:(JNIEnv *)env
file:(const char*)file line:(int)line function:(const char*)function
{
NSMutableString *info = [[[NSMutableString alloc] init] autorelease];
[NSApplicationAWT toString:message callStackSymbols:callStackSymbols to:info
file:file line:line function:function];
[NSApplicationAWT logMessage:info withEnv:env];
}
+ (void) logMessage:(NSString *)info withEnv:(JNIEnv *)env {
// Always log to the console first:
NSLog(@"%@", info);
// Send to PlatformLogger too:
lwc_plog(env, "%s", info.UTF8String);
}
+ (void) toString:(NSException *)exception uncaught:(BOOL)uncaught prefix:(NSString *)prefix to:(NSMutableString *)info
file:(const char*)file line:(int)line function:(const char*)function
{
const char* uncaughtMark = (uncaught) ? "Uncaught " : "";
NSString *header = (file != nil) ?
[NSString stringWithFormat: @"%@%sException (%s:%d %s):\n%@\n", prefix, uncaughtMark, file, line, function, exception]
: [NSString stringWithFormat: @"%@%sException (unknown):\n%@\n", prefix, uncaughtMark, exception];
[info appendString:header];
[NSApplicationAWT toString:[exception callStackSymbols] to:info];
}
+ (void) toString:(NSString *)message callStackSymbols:(NSArray<NSString *> *)callStackSymbols to:(NSMutableString *)info
file:(const char*)file line:(int)line function:(const char*)function
{
NSString *header = (file != nil) ?
[NSString stringWithFormat: @"%@ (%s:%d %s):\n", message, file, line, function]
: [NSString stringWithFormat: @"%@ (unknown):\n", message];
[info appendString:header];
[NSApplicationAWT toString:callStackSymbols to:info];
}
+ (void) toString:(NSArray<NSString *> *)callStackSymbols to:(NSMutableString *)info
{
for (NSUInteger i = 0; i < callStackSymbols.count; i++) {
[info appendFormat:@" %@\n", callStackSymbols[i]];
}
}
// --- NSExceptionHandlerDelegate category to handle all exceptions ---
- (BOOL) exceptionHandler:(NSExceptionHandler *)sender
shouldHandleException:(NSException *)exception mask:(NSUInteger)aMask {
/* handle all exception types to invoke reportException:exception */
return YES;
}
- (BOOL) exceptionHandler:(NSExceptionHandler *)sender
shouldLogException:(NSException *)exception mask:(NSUInteger)aMask {
/* disable default logging (stderr) */
return NO;
}
@end

View File

@@ -130,30 +130,6 @@ do { \
/* bit flag to coalesce CGDisplayReconfigureCallbacks */
#define MAIN_CALLBACK_CGDISPLAY_RECONFIGURE 1
/* log given message (with thread call stack) */
#define NSAPP_AWT_LOG_MESSAGE(message) \
[ThreadUtilities logMessage:message file:__FILE__ line:__LINE__ function:__FUNCTION__]
/* log given exception (ignored or explicitely muted) */
#define NSAPP_AWT_LOG_EXCEPTION(exception) \
[ThreadUtilities logException:exception file:__FILE__ line:__LINE__ function:__FUNCTION__]
#define NSAPP_AWT_LOG_EXCEPTION_PREFIX(exception, prefixValue) \
[ThreadUtilities logException:exception prefix:prefixValue file:__FILE__ line:__LINE__ function:__FUNCTION__]
/* report the given exception (ignored or explicitely muted), may crash the JVM (JNU_Fatal) */
#define NSAPP_AWT_REPORT_EXCEPTION(exception, uncaughtFlag) \
[ThreadUtilities reportException:exception uncaught:uncaughtFlag file:__FILE__ line:__LINE__ function:__FUNCTION__]
/* CFRelease wrapper that ignores NULL argument */
JNIEXPORT void CFRelease_even_NULL(CFTypeRef cf);
/* Return true if uncaught exceptions should crash JVM (JNU_Fatal) */
BOOL shouldCrashOnException();
/* Get AWT's NSUncaughtExceptionHandler */
JNIEXPORT NSUncaughtExceptionHandler* GetAWTUncaughtExceptionHandler(void);
@interface RunLoopCallbackQueue : NSObject
@property(readwrite, atomic) u_long coalesingflags;
@@ -204,25 +180,8 @@ __attribute__((visibility("default")))
*/
@property (class, nonatomic, readonly) BOOL blockingEventDispatchThread;
+ (void (^)()) GetEmptyBlock;
+ (void) reportException:(NSException *)exception;
+ (void) reportException:(NSException *)exception uncaught:(BOOL)uncaught
file:(const char*)file line:(int)line function:(const char*)function;
+ (void) logException:(NSException *)exception;
+ (void) logException:(NSException *)exception
file:(const char*)file line:(int)line function:(const char*)function;
+ (void) logException:(NSException *)exception prefix:(NSString *)prefix
file:(const char*)file line:(int)line function:(const char*)function;
+ (void) logMessage:(NSString *)message;
+ (void) logMessage:(NSString *)message
file:(const char*)file line:(int)line function:(const char*)function;
+ (JNIEnv*)getJNIEnv;
+ (JNIEnv*)getJNIEnvUncached;
+ (void)detachCurrentThread;
+ (void)setAppkitThreadGroup:(jobject)group;
+ (void)setApplicationOwner:(BOOL)owner;

View File

@@ -29,7 +29,6 @@
#import "JNIUtilities.h"
#import "PropertiesUtilities.h"
#import "ThreadUtilities.h"
#import "NSApplicationAWT.h"
#define RUN_BLOCK_IF(COND, block) \
@@ -41,45 +40,6 @@
/* See LWCToolkit.APPKIT_THREAD_NAME */
#define MAIN_THREAD_NAME "AppKit Thread"
void CFRelease_even_NULL(CFTypeRef cf) {
if (cf != NULL) {
CFRelease(cf);
}
}
// Global CrashOnException handling flags used by:
// - UncaughtExceptionHandler
// - NSApplicationAWT _crashOnException:(NSException *)exception
static BOOL isAWTCrashOnException() {
static int awtCrashOnException = -1;
if (awtCrashOnException == -1) {
JNIEnv *env = [ThreadUtilities getJNIEnvUncached];
if (env == NULL) return NO;
NSString* awtCrashOnExceptionProp = [PropertiesUtilities javaSystemPropertyForKey:@"apple.awt.crashOnException"
withEnv:env];
awtCrashOnException = [@"true" isCaseInsensitiveLike:awtCrashOnExceptionProp] ? YES : NO;
}
return (BOOL)awtCrashOnException;
}
BOOL shouldCrashOnException() {
static int crashOnException = -1;
if (crashOnException == -1) {
BOOL shouldCrashOnException = NO;
#if defined(DEBUG)
shouldCrashOnException = YES;
#endif
if (!shouldCrashOnException) {
shouldCrashOnException = isAWTCrashOnException();
}
crashOnException = shouldCrashOnException;
if (crashOnException) {
NSLog(@"WARNING: shouldCrashOnException ENABLED");
}
}
return (BOOL)crashOnException;
}
/* Returns the MainThread latency threshold in milliseconds
* used to detect slow operations that may cause high latencies or delays.
* If negative, the MainThread monitor is disabled */
@@ -129,24 +89,6 @@ static const int TRACE_BLOCKING_FLAGS = 0;
/* RunLoop traceability identifier generators */
static atomic_long mainThreadActionId = 0L;
// --- AWT's NSUncaughtExceptionHandler ---
static void AWT_NSUncaughtExceptionHandler(NSException *exception) {
// report exception to the NSApplicationAWT exception handler:
NSAPP_AWT_REPORT_EXCEPTION(exception, YES);
}
/* Get AWT's NSUncaughtExceptionHandler */
NSUncaughtExceptionHandler* GetAWTUncaughtExceptionHandler(void) {
static NSUncaughtExceptionHandler* _awtUncaughtExceptionHandler;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_awtUncaughtExceptionHandler = AWT_NSUncaughtExceptionHandler;
NSSetUncaughtExceptionHandler(_awtUncaughtExceptionHandler);
});
return _awtUncaughtExceptionHandler;
}
static inline void doLog(JNIEnv* env, const char *formatMsg, ...) {
if (enableTracingNSLog) {
va_list args;
@@ -189,78 +131,6 @@ static long eventDispatchThreadPtr = (long)nil;
static BOOL _blockingEventDispatchThread = NO;
static BOOL _blockingMainThread = NO;
// Empty block optimization using 1 single instance and avoid Block_copy macro
+ (void (^)()) GetEmptyBlock {
static id _emptyBlock = nil;
if (_emptyBlock == nil) {
_emptyBlock = ^(){};
}
return _emptyBlock;
}
+ (BOOL) IsEmptyBlock:(void (^)())block {
return (block == [ThreadUtilities GetEmptyBlock]);
}
#define Custom_Block_copy(block) ( ([ThreadUtilities IsEmptyBlock:block]) ? block : Block_copy(block) )
/*
* When running a block where either we don't wait, or it needs to run on another thread
* we need to copy it from stack to heap, use the copy in the call and release after use.
* Do this only when we must because it could be expensive.
* Note : if waiting cross-thread, possibly the stack allocated copy is accessible ?
*/
+ (void)invokeBlockCopy:(void (^)(void))blockCopy {
if (![ThreadUtilities IsEmptyBlock:blockCopy]) {
@try {
blockCopy();
} @finally {
Block_release(blockCopy);
#if (CHECK_PENDING_EXCEPTION == 1)
__JNI_CHECK_PENDING_EXCEPTION([ThreadUtilities getJNIEnvUncached]);
#endif
}
}
}
// Exception handling bridge
+ (void) reportException:(NSException *)exception {
[[NSApplicationAWT sharedApplicationAWT] reportException:exception];
}
+ (void) reportException:(NSException *)exception uncaught:(BOOL)uncaught
file:(const char*)file line:(int)line function:(const char*)function
{
[[NSApplicationAWT sharedApplicationAWT] reportException:exception uncaught:uncaught file:file line:line function:function];
}
+ (void) logException:(NSException *)exception {
[NSApplicationAWT logException:exception];
}
+ (void) logException:(NSException *)exception
file:(const char*)file line:(int)line function:(const char*)function
{
[NSApplicationAWT logException:exception file:file line:line function:function];
}
+ (void) logException:(NSException *)exception prefix:(NSString *)prefix
file:(const char*)file line:(int)line function:(const char*)function
{
[NSApplicationAWT logException:exception prefix:prefix file:file line:line function:function];
}
+ (void) logMessage:(NSString *)message {
[NSApplicationAWT logMessage:message];
}
+ (void) logMessage:(NSString *)message
file:(const char*)file line:(int)line function:(const char*)function
{
[NSApplicationAWT logMessage:message file:file line:line function:function];
}
static BOOL isEventDispatchThread() {
return (long)[NSThread currentThread] == eventDispatchThreadPtr;
}
@@ -325,13 +195,9 @@ AWT_ASSERT_APPKIT_THREAD;
}
+ (JNIEnv*)getJNIEnvUncached {
if ([NSThread isMainThread] && (appKitEnv != NULL)) {
return appKitEnv;
} else {
JNIEnv *env = NULL;
attachCurrentThread((void **)&env);
return env;
}
JNIEnv *env = NULL;
attachCurrentThread((void **)&env);
return env;
}
+ (void)detachCurrentThread {
@@ -379,7 +245,17 @@ AWT_ASSERT_APPKIT_THREAD;
[ThreadUtilities resetTraceContext];
}
}
doLog([ThreadUtilities getJNIEnvUncached], "setAppkitThreadGroup: exit");
}
/*
* When running a block where either we don't wait, or it needs to run on another thread
* we need to copy it from stack to heap, use the copy in the call and release after use.
* Do this only when we must because it could be expensive.
* Note : if waiting cross-thread, possibly the stack allocated copy is accessible ?
*/
+ (void)invokeBlockCopy:(void (^)(void))blockCopy {
blockCopy();
Block_release(blockCopy);
}
+ (NSString*)getCaller:(NSString*)prefixSymbol {
@@ -423,7 +299,7 @@ AWT_ASSERT_APPKIT_THREAD;
{
RUN_BLOCK_IF([NSThread isMainThread], block);
[ThreadUtilities performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Custom_Block_copy(block)
[ThreadUtilities performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block)
waitUntilDone:NO useJavaModes:useJavaModes];
}
@@ -445,7 +321,7 @@ AWT_ASSERT_APPKIT_THREAD;
{
RUN_BLOCK_IF([NSThread isMainThread] && wait, block);
[ThreadUtilities performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Custom_Block_copy(block)
[ThreadUtilities performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:Block_copy(block)
waitUntilDone:wait useJavaModes:useJavaModes];
}
@@ -815,7 +691,7 @@ JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
if (midWarn != NULL) {
va_list args;
va_start(args, formatMsg);
/* formatted message can be large (stack trace) => 16 kb buffer size */
/* formatted message can be large (stack trace ?) => 16 kb */
const int bufSize = 16 * 1024;
char buf[bufSize];
#pragma clang diagnostic push
@@ -824,29 +700,17 @@ JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
#pragma clang diagnostic pop
va_end(args);
BOOL logged = NO;
const jstring javaString = (*env)->NewStringUTF(env, buf);
if ((javaString != NULL) && (*env)->ExceptionCheck(env) == JNI_FALSE) {
// call PlatformLogger.warning(javaString):
if ((*env)->ExceptionCheck(env)) {
// fallback:
NSLog(@"%s\n", buf); \
} else {
JNU_CHECK_EXCEPTION(env);
(*env)->CallVoidMethod(env, loggerObject, midWarn, javaString);
// derived from CHECK_EXCEPTION but NO NSException raised:
if ((*env)->ExceptionCheck(env)) {
// fallback:
(*(env))->ExceptionDescribe(env);
// note: [NSApplicationAWT logMessage:message] is not used
// to avoid reentrancy issues.
NSLog(@"%@", [NSThread callStackSymbols]);
} else {
logged = YES;
}
CHECK_EXCEPTION();
return;
}
(*env)->DeleteLocalRef(env, javaString);
if (!logged) {
// fallback:
NSLog(@"%s\n", buf);
}
}
}
@@ -915,22 +779,10 @@ JNIEXPORT void lwc_plog(JNIEnv* env, const char *formatMsg, ...) {
- (void)processQueuedCallbacks {
const NSUInteger count = [self.queue count];
if (count != 0) {
#if (CHECK_PENDING_EXCEPTION == 1)
JNIEnv *env = [ThreadUtilities getJNIEnv];
#endif
for (NSUInteger i = 0; i < count; i++) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
@try {
void (^blockCopy)(void) = (void (^)()) [self.queue objectAtIndex:i];
// invoke callback:
[ThreadUtilities invokeBlockCopy:blockCopy];
} @catch (NSException *exception) {
// report exception to the NSApplicationAWT exception handler:
NSAPP_AWT_REPORT_EXCEPTION(exception, NO);
} @finally {
__JNI_CHECK_PENDING_EXCEPTION(env);
[pool drain];
}
void (^blockCopy)(void) = (void (^)())[self.queue objectAtIndex: i];
// invoke callback:
[ThreadUtilities invokeBlockCopy:blockCopy];
}
// reset queue anyway:
[self reset];