提交 386cccc3 编写于 作者: P pchelko

8006634: Unify LWCToolkit.invokeAndWait() and sun.awt.datatransfer.ToolkitThreadBlockedHandler

Summary: Changed the logic for the nested event loops and deleted deadlock detection
Reviewed-by: art, denis
上级 eb2c4ec7
...@@ -30,6 +30,7 @@ import java.awt.Dialog.ModalityType; ...@@ -30,6 +30,7 @@ import java.awt.Dialog.ModalityType;
import java.awt.event.*; import java.awt.event.*;
import java.awt.peer.WindowPeer; import java.awt.peer.WindowPeer;
import java.beans.*; import java.beans.*;
import java.lang.reflect.InvocationTargetException;
import java.util.List; import java.util.List;
import javax.swing.*; import javax.swing.*;
...@@ -861,7 +862,16 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo ...@@ -861,7 +862,16 @@ public class CPlatformWindow extends CFRetainedResource implements PlatformWindo
private void flushBuffers() { private void flushBuffers() {
if (isVisible() && !nativeBounds.isEmpty()) { if (isVisible() && !nativeBounds.isEmpty()) {
LWCToolkit.getLWCToolkit().flushPendingEventsOnAppkit(target); try {
LWCToolkit.invokeAndWait(new Runnable() {
@Override
public void run() {
//Posting an empty to flush the EventQueue without blocking the main thread
}
}, target);
} catch (InterruptedException | InvocationTargetException e) {
e.printStackTrace();
}
} }
} }
......
...@@ -25,27 +25,33 @@ ...@@ -25,27 +25,33 @@
package sun.lwawt.macosx; package sun.lwawt.macosx;
import sun.awt.Mutex;
import sun.awt.datatransfer.ToolkitThreadBlockedHandler; import sun.awt.datatransfer.ToolkitThreadBlockedHandler;
final class CToolkitThreadBlockedHandler implements ToolkitThreadBlockedHandler { final class CToolkitThreadBlockedHandler extends Mutex implements ToolkitThreadBlockedHandler {
private final LWCToolkit toolkit = (LWCToolkit)java.awt.Toolkit.getDefaultToolkit(); private long awtRunLoopMediator = 0;
private final boolean processEvents;
public void lock() { CToolkitThreadBlockedHandler() {
} super();
this.processEvents = true;
public void unlock() {
}
protected boolean isOwned() {
return false;
} }
public void enter() { public void enter() {
// Execute the next AppKit event while we are waiting for system to if (!isOwned()) {
// finish our request - this will save us from biting our own tail throw new IllegalMonitorStateException();
toolkit.executeNextAppKitEvent(); }
awtRunLoopMediator = LWCToolkit.createAWTRunLoopMediator();
unlock();
LWCToolkit.doAWTRunLoop(awtRunLoopMediator, processEvents);
lock();
} }
public void exit() { public void exit() {
if (!isOwned()) {
throw new IllegalMonitorStateException();
}
LWCToolkit.stopAWTRunLoop(awtRunLoopMediator);
awtRunLoopMediator = 0;
} }
} }
...@@ -63,8 +63,6 @@ public final class LWCToolkit extends LWToolkit { ...@@ -63,8 +63,6 @@ public final class LWCToolkit extends LWToolkit {
private static native void initIDs(); private static native void initIDs();
static native void executeNextAppKitEvent();
private static CInputMethodDescriptor sInputMethodDescriptor; private static CInputMethodDescriptor sInputMethodDescriptor;
static { static {
...@@ -502,30 +500,6 @@ public final class LWCToolkit extends LWToolkit { ...@@ -502,30 +500,6 @@ public final class LWCToolkit extends LWToolkit {
synchronized(ret) { return ret[0]; } synchronized(ret) { return ret[0]; }
} }
/**
* Just a wrapper for LWCToolkit.invokeAndWait. Posts an empty event to the
* appropriate event queue and waits for it to finish.
*/
public static void flushPendingEventsOnAppkit(final Component component) {
try {
invokeAndWait(new Runnable() {
@Override
public void run() {
}
}, component);
} catch (Exception e) {
e.printStackTrace();
}
}
// Kicks an event over to the appropriate eventqueue and waits for it to finish
// To avoid deadlocking, we manually run the NSRunLoop while waiting
// Any selector invoked using ThreadUtilities performOnMainThread will be processed in doAWTRunLoop
// The CInvocationEvent will call LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual runloop
public static void invokeAndWait(Runnable event, Component component) throws InterruptedException, InvocationTargetException {
invokeAndWait(event, component, true);
}
public static <T> T invokeAndWait(final Callable<T> callable, Component component) throws Exception { public static <T> T invokeAndWait(final Callable<T> callable, Component component) throws Exception {
final CallableWrapper<T> wrapper = new CallableWrapper<T>(callable); final CallableWrapper<T> wrapper = new CallableWrapper<T>(callable);
invokeAndWait(wrapper, component); invokeAndWait(wrapper, component);
...@@ -555,10 +529,27 @@ public final class LWCToolkit extends LWToolkit { ...@@ -555,10 +529,27 @@ public final class LWCToolkit extends LWToolkit {
} }
} }
public static void invokeAndWait(Runnable event, Component component, boolean detectDeadlocks) throws InterruptedException, InvocationTargetException { // Kicks an event over to the appropriate eventqueue and waits for it to finish
long mediator = createAWTRunLoopMediator(); // To avoid deadlocking, we manually run the NSRunLoop while waiting
// Any selector invoked using ThreadUtilities performOnMainThread will be processed in doAWTRunLoop
// The InvocationEvent will call LWCToolkit.stopAWTRunLoop() when finished, which will stop our manual runloop
// Does not dispatch native events while in the loop
public static void invokeAndWait(Runnable event, Component component) throws InterruptedException, InvocationTargetException {
final long mediator = createAWTRunLoopMediator();
InvocationEvent invocationEvent = new CPeerEvent(event, mediator); InvocationEvent invocationEvent =
new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), event) {
@Override
public void dispatch() {
try {
super.dispatch();
} finally {
if (mediator != 0) {
stopAWTRunLoop(mediator);
}
}
}
};
if (component != null) { if (component != null) {
AppContext appContext = SunToolkit.targetToAppContext(component); AppContext appContext = SunToolkit.targetToAppContext(component);
...@@ -571,7 +562,7 @@ public final class LWCToolkit extends LWToolkit { ...@@ -571,7 +562,7 @@ public final class LWCToolkit extends LWToolkit {
((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent); ((LWCToolkit)Toolkit.getDefaultToolkit()).getSystemEventQueueForInvokeAndWait().postEvent(invocationEvent);
} }
doAWTRunLoop(mediator, true, detectDeadlocks); doAWTRunLoop(mediator, false);
Throwable eventException = invocationEvent.getException(); Throwable eventException = invocationEvent.getException();
if (eventException != null) { if (eventException != null) {
...@@ -583,7 +574,8 @@ public final class LWCToolkit extends LWToolkit { ...@@ -583,7 +574,8 @@ public final class LWCToolkit extends LWToolkit {
} }
public static void invokeLater(Runnable event, Component component) throws InvocationTargetException { public static void invokeLater(Runnable event, Component component) throws InvocationTargetException {
final InvocationEvent invocationEvent = new CPeerEvent(event, 0); final InvocationEvent invocationEvent =
new InvocationEvent(component != null ? component : Toolkit.getDefaultToolkit(), event);
if (component != null) { if (component != null) {
final AppContext appContext = SunToolkit.targetToAppContext(component); final AppContext appContext = SunToolkit.targetToAppContext(component);
...@@ -688,31 +680,6 @@ public final class LWCToolkit extends LWToolkit { ...@@ -688,31 +680,6 @@ public final class LWCToolkit extends LWToolkit {
return false; return false;
} }
// Extends PeerEvent because we want to pass long an ObjC mediator object and because we want these events to be posted early
// Typically, rather than relying on the notifier to call notifyAll(), we use the mediator to stop the runloop
public static class CPeerEvent extends PeerEvent {
private long _mediator = 0;
public CPeerEvent(Runnable runnable, long mediator) {
super(Toolkit.getDefaultToolkit(), runnable, null, true, 0);
_mediator = mediator;
}
public void dispatch() {
try {
super.dispatch();
} finally {
if (_mediator != 0) {
LWCToolkit.stopAWTRunLoop(_mediator);
}
}
}
}
// Call through to native methods
public static void doAWTRunLoop(long mediator, boolean awtMode) { doAWTRunLoop(mediator, awtMode, true); }
public static void doAWTRunLoop(long mediator) { doAWTRunLoop(mediator, true); }
private static Boolean sunAwtDisableCALayers = null; private static Boolean sunAwtDisableCALayers = null;
/** /**
...@@ -737,12 +704,20 @@ public final class LWCToolkit extends LWToolkit { ...@@ -737,12 +704,20 @@ public final class LWCToolkit extends LWToolkit {
* Native methods section * Native methods section
************************/ ************************/
// These are public because they are accessed from WebKitPluginObject in JavaDeploy static native long createAWTRunLoopMediator();
// Basic usage: /**
// createAWTRunLoopMediator. Start client code on another thread. doAWTRunLoop. When client code is finished, stopAWTRunLoop. * Method to run a nested run-loop. The nested loop is spinned in the javaRunLoop mode, so selectors sent
public static native long createAWTRunLoopMediator(); * by [JNFRunLoop performOnMainThreadWaiting] are processed.
public static native void doAWTRunLoop(long mediator, boolean awtMode, boolean detectDeadlocks); * @param mediator a native pointer to the mediator object created by createAWTRunLoopMediator
public static native void stopAWTRunLoop(long mediator); * @param processEvents if true - dispatches event while in the nested loop. Used in DnD.
* Additional attention is needed when using this feature as we short-circuit normal event
* processing which could break Appkit.
* (One known example is when the window is resized with the mouse)
*
* if false - all events come after exit form the nested loop
*/
static native void doAWTRunLoop(long mediator, boolean processEvents);
static native void stopAWTRunLoop(long mediator);
private native boolean nativeSyncQueue(long timeout); private native boolean nativeSyncQueue(long timeout);
......
...@@ -668,7 +668,7 @@ AWT_ASSERT_APPKIT_THREAD; ...@@ -668,7 +668,7 @@ AWT_ASSERT_APPKIT_THREAD;
- (void) setDropTarget:(CDropTarget *)target { - (void) setDropTarget:(CDropTarget *)target {
self._dropTarget = target; self._dropTarget = target;
[ThreadUtilities performOnMainThread:@selector(controlModelControlValid) onObject:self._dropTarget withObject:nil waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(controlModelControlValid) on:self._dropTarget withObject:nil waitUntilDone:YES];
} }
/******************************** BEGIN NSDraggingSource Interface ********************************/ /******************************** BEGIN NSDraggingSource Interface ********************************/
...@@ -1215,7 +1215,7 @@ JNF_CLASS_CACHE(jc_CInputMethod, "sun/lwawt/macosx/CInputMethod"); ...@@ -1215,7 +1215,7 @@ JNF_CLASS_CACHE(jc_CInputMethod, "sun/lwawt/macosx/CInputMethod");
fprintf(stderr, "AWTView InputMethod Selector Called : [abandonInput]\n"); fprintf(stderr, "AWTView InputMethod Selector Called : [abandonInput]\n");
#endif // IM_DEBUG #endif // IM_DEBUG
[ThreadUtilities performOnMainThread:@selector(markedTextAbandoned:) onObject:[NSInputManager currentInputManager] withObject:self waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(markedTextAbandoned:) on:[NSInputManager currentInputManager] withObject:self waitUntilDone:YES];
[self unmarkText]; [self unmarkText];
} }
......
...@@ -567,10 +567,9 @@ JNIEXPORT void JNICALL Java_com_apple_eawt__1AppEventHandler_nativeRegisterForNo ...@@ -567,10 +567,9 @@ JNIEXPORT void JNICALL Java_com_apple_eawt__1AppEventHandler_nativeRegisterForNo
{ {
JNF_COCOA_ENTER(env); JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(_registerForNotification:) [ThreadUtilities performOnMainThread:@selector(_registerForNotification:)
onObject:[ApplicationDelegate class] on:[ApplicationDelegate class]
withObject:[NSNumber numberWithInt:notificationType] withObject:[NSNumber numberWithInt:notificationType]
waitUntilDone:NO waitUntilDone:NO]; // AWT_THREADING Safe (non-blocking)
awtMode:NO]; // AWT_THREADING Safe (non-blocking)
JNF_COCOA_EXIT(env); JNF_COCOA_EXIT(env);
} }
......
...@@ -120,7 +120,7 @@ static CClipboard *sClipboard = nil; ...@@ -120,7 +120,7 @@ static CClipboard *sClipboard = nil;
fClipboardOwner = JNFNewGlobalRef(inEnv, inClipboard); fClipboardOwner = JNFNewGlobalRef(inEnv, inClipboard);
} }
} }
[ThreadUtilities performOnMainThread:@selector(_nativeDeclareTypes:) onObject:self withObject:inTypes waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(_nativeDeclareTypes:) on:self withObject:inTypes waitUntilDone:YES];
} }
- (void) _nativeDeclareTypes:(NSArray *)inTypes { - (void) _nativeDeclareTypes:(NSArray *)inTypes {
...@@ -135,7 +135,7 @@ static CClipboard *sClipboard = nil; ...@@ -135,7 +135,7 @@ static CClipboard *sClipboard = nil;
- (NSArray *) javaGetTypes { - (NSArray *) javaGetTypes {
NSMutableArray *args = [NSMutableArray arrayWithCapacity:1]; NSMutableArray *args = [NSMutableArray arrayWithCapacity:1];
[ThreadUtilities performOnMainThread:@selector(_nativeGetTypes:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(_nativeGetTypes:) on:self withObject:args waitUntilDone:YES];
//NSLog(@"CClipboard getTypes returns %@", [args lastObject]); //NSLog(@"CClipboard getTypes returns %@", [args lastObject]);
return [args lastObject]; return [args lastObject];
...@@ -152,7 +152,7 @@ static CClipboard *sClipboard = nil; ...@@ -152,7 +152,7 @@ static CClipboard *sClipboard = nil;
- (void) javaSetData:(NSData *)inData forType:(NSString *) inFormat { - (void) javaSetData:(NSData *)inData forType:(NSString *) inFormat {
CClipboardUpdate *newUpdate = [[CClipboardUpdate alloc] initWithData:inData withFormat:inFormat]; CClipboardUpdate *newUpdate = [[CClipboardUpdate alloc] initWithData:inData withFormat:inFormat];
[ThreadUtilities performOnMainThread:@selector(_nativeSetData:) onObject:self withObject:newUpdate waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(_nativeSetData:) on:self withObject:newUpdate waitUntilDone:YES];
[newUpdate release]; [newUpdate release];
//NSLog(@"CClipboard javaSetData forType %@", inFormat); //NSLog(@"CClipboard javaSetData forType %@", inFormat);
...@@ -170,7 +170,7 @@ static CClipboard *sClipboard = nil; ...@@ -170,7 +170,7 @@ static CClipboard *sClipboard = nil;
- (NSData *) javaGetDataForType:(NSString *) inFormat { - (NSData *) javaGetDataForType:(NSString *) inFormat {
NSMutableArray *args = [NSMutableArray arrayWithObject:inFormat]; NSMutableArray *args = [NSMutableArray arrayWithObject:inFormat];
[ThreadUtilities performOnMainThread:@selector(_nativeGetDataForType:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(_nativeGetDataForType:) on:self withObject:args waitUntilDone:YES];
//NSLog(@"CClipboard javaGetDataForType %@ returns an NSData", inFormat); //NSLog(@"CClipboard javaGetDataForType %@ returns an NSData", inFormat);
return [args lastObject]; return [args lastObject];
......
...@@ -390,8 +390,7 @@ extern JNFClassInfo jc_CDropTargetContextPeer; ...@@ -390,8 +390,7 @@ extern JNFClassInfo jc_CDropTargetContextPeer;
// Release dragging data if any when Java's AWT event thread is all finished. // Release dragging data if any when Java's AWT event thread is all finished.
// Make sure dragging data is released on the native event thread. // Make sure dragging data is released on the native event thread.
[ThreadUtilities performOnMainThread:@selector(safeReleaseDraggingData:) onObject:self [ThreadUtilities performOnMainThread:@selector(safeReleaseDraggingData:) on:self withObject:draggingSequenceNumberID waitUntilDone:NO];
withObject:draggingSequenceNumberID waitUntilDone:NO awtMode:NO];
} }
- (jint)currentJavaActions { - (jint)currentJavaActions {
......
...@@ -55,11 +55,11 @@ AWT_ASSERT_APPKIT_THREAD; ...@@ -55,11 +55,11 @@ AWT_ASSERT_APPKIT_THREAD;
//- (void)finalize { [super finalize]; } //- (void)finalize { [super finalize]; }
- (void)addJavaSubmenu:(CMenu *)submenu { - (void)addJavaSubmenu:(CMenu *)submenu {
[ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) onObject:self withObject:submenu waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) on:self withObject:submenu waitUntilDone:YES];
} }
- (void)addJavaMenuItem:(CMenuItem *)theMenuItem { - (void)addJavaMenuItem:(CMenuItem *)theMenuItem {
[ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) onObject:self withObject:theMenuItem waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(addNativeItem_OnAppKitThread:) on:self withObject:theMenuItem waitUntilDone:YES];
} }
- (void)addNativeItem_OnAppKitThread:(CMenuItem *)itemModified { - (void)addNativeItem_OnAppKitThread:(CMenuItem *)itemModified {
...@@ -70,7 +70,7 @@ AWT_ASSERT_APPKIT_THREAD; ...@@ -70,7 +70,7 @@ AWT_ASSERT_APPKIT_THREAD;
- (void)setJavaMenuTitle:(NSString *)title { - (void)setJavaMenuTitle:(NSString *)title {
if (title) { if (title) {
[ThreadUtilities performOnMainThread:@selector(setNativeMenuTitle_OnAppKitThread:) onObject:self withObject:title waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(setNativeMenuTitle_OnAppKitThread:) on:self withObject:title waitUntilDone:YES];
} }
} }
...@@ -93,7 +93,7 @@ AWT_ASSERT_APPKIT_THREAD; ...@@ -93,7 +93,7 @@ AWT_ASSERT_APPKIT_THREAD;
- (void)deleteJavaItem:(jint)index { - (void)deleteJavaItem:(jint)index {
[ThreadUtilities performOnMainThread:@selector(deleteNativeJavaItem_OnAppKitThread:) onObject:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(deleteNativeJavaItem_OnAppKitThread:) on:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES];
} }
- (void)deleteNativeJavaItem_OnAppKitThread:(NSNumber *)number { - (void)deleteNativeJavaItem_OnAppKitThread:(NSNumber *)number {
...@@ -139,7 +139,7 @@ CMenu * createCMenu (jobject cPeerObjGlobal) { ...@@ -139,7 +139,7 @@ CMenu * createCMenu (jobject cPeerObjGlobal) {
// We use an array here only to be able to get a return value // We use an array here only to be able to get a return value
NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], nil]; NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], nil];
[ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) onObject:[CMenu alloc] withObject:args waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) on:[CMenu alloc] withObject:args waitUntilDone:YES];
aCMenu = (CMenu *)[args objectAtIndex: 0]; aCMenu = (CMenu *)[args objectAtIndex: 0];
......
...@@ -197,7 +197,7 @@ static BOOL sSetupHelpMenu = NO; ...@@ -197,7 +197,7 @@ static BOOL sSetupHelpMenu = NO;
if (self == sActiveMenuBar) { if (self == sActiveMenuBar) {
NSArray *args = [[NSArray alloc] initWithObjects:theMenu, [NSNumber numberWithInt:-1], nil]; NSArray *args = [[NSArray alloc] initWithObjects:theMenu, [NSNumber numberWithInt:-1], nil];
[ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) on:self withObject:args waitUntilDone:YES];
[args release]; [args release];
} }
} }
...@@ -216,7 +216,7 @@ static BOOL sSetupHelpMenu = NO; ...@@ -216,7 +216,7 @@ static BOOL sSetupHelpMenu = NO;
if (self == sActiveMenuBar) { if (self == sActiveMenuBar) {
NSArray *args = [[NSArray alloc] initWithObjects:theMenu, [NSNumber numberWithInt:index], nil]; NSArray *args = [[NSArray alloc] initWithObjects:theMenu, [NSNumber numberWithInt:index], nil];
[ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) onObject:self withObject:args waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(nativeAddMenuAtIndex_OnAppKitThread:) on:self withObject:args waitUntilDone:YES];
[args release]; [args release];
} }
} }
...@@ -286,7 +286,7 @@ static BOOL sSetupHelpMenu = NO; ...@@ -286,7 +286,7 @@ static BOOL sSetupHelpMenu = NO;
- (void) javaDeleteMenu: (jint)index { - (void) javaDeleteMenu: (jint)index {
if (self == sActiveMenuBar) { if (self == sActiveMenuBar) {
[ThreadUtilities performOnMainThread:@selector(nativeDeleteMenu_OnAppKitThread:) onObject:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(nativeDeleteMenu_OnAppKitThread:) on:self withObject:[NSNumber numberWithInt:index] waitUntilDone:YES];
} }
@synchronized(self) { @synchronized(self) {
...@@ -388,7 +388,7 @@ Java_sun_lwawt_macosx_CMenuBar_nativeCreateMenuBar ...@@ -388,7 +388,7 @@ Java_sun_lwawt_macosx_CMenuBar_nativeCreateMenuBar
// We use an array here only to be able to get a return value // We use an array here only to be able to get a return value
NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], nil]; NSMutableArray *args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], nil];
[ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) onObject:[CMenuBar alloc] withObject:args waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(_create_OnAppKitThread:) on:[CMenuBar alloc] withObject:args waitUntilDone:YES];
aCMenuBar = (CMenuBar *)[args objectAtIndex: 0]; aCMenuBar = (CMenuBar *)[args objectAtIndex: 0];
......
...@@ -386,7 +386,7 @@ JNF_COCOA_ENTER(env); ...@@ -386,7 +386,7 @@ JNF_COCOA_ENTER(env);
args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], [NSNumber numberWithBool:NO], nil]; args = [[NSMutableArray alloc] initWithObjects:[NSValue valueWithBytes:&cPeerObjGlobal objCType:@encode(jobject)], [NSNumber numberWithBool:NO], nil];
} }
[ThreadUtilities performOnMainThread:@selector(_createMenuItem_OnAppKitThread:) onObject:[CMenuItem alloc] withObject:args waitUntilDone:YES awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(_createMenuItem_OnAppKitThread:) on:[CMenuItem alloc] withObject:args waitUntilDone:YES];
aCMenuItem = (CMenuItem *)[args objectAtIndex: 0]; aCMenuItem = (CMenuItem *)[args objectAtIndex: 0];
......
...@@ -1113,20 +1113,12 @@ static NSObject *sAttributeNamesLOCK = nil; ...@@ -1113,20 +1113,12 @@ static NSObject *sAttributeNamesLOCK = nil;
JNIEnv *env = [ThreadUtilities getJNIEnv]; JNIEnv *env = [ThreadUtilities getJNIEnv];
id value = nil; id value = nil;
// This code frequently gets called indirectly by Java when VoiceOver is active.
// Basically, we just have to know when we going to be a bad state, and do something "special".
// Note that while NSApplication isn't technically correct, we post a focus changed notification
// (which will call this method, but with the correct codepath) shortly afterwards. See +postFocusChanged.
if (sInPerformFromJava) {
return [NSApplication sharedApplication];
} else {
jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop) jobject focused = JNFCallStaticObjectMethod(env, jm_getFocusOwner, fComponent); // AWT_THREADING Safe (AWTRunLoop)
if (focused != NULL) { if (focused != NULL) {
if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) { if (JNFIsInstanceOf(env, focused, &sjc_Accessible)) {
value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView]; value = [JavaComponentAccessibility createWithAccessible:focused withEnv:env withView:fView];
} }
} }
}
if (value == nil) { if (value == nil) {
value = self; value = self;
...@@ -1149,7 +1141,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged ...@@ -1149,7 +1141,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessibility_focusChanged
{ {
JNF_COCOA_ENTER(env); JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postFocusChanged:) onObject:[JavaComponentAccessibility class] withObject:nil waitUntilDone:NO awtMode:NO]; [ThreadUtilities performOnMainThread:@selector(postFocusChanged:) on:[JavaComponentAccessibility class] withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env); JNF_COCOA_EXIT(env);
} }
...@@ -1164,7 +1156,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_valueChanged ...@@ -1164,7 +1156,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_valueChanged
(JNIEnv *env, jclass jklass, jlong element) (JNIEnv *env, jclass jklass, jlong element)
{ {
JNF_COCOA_ENTER(env); JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postValueChanged) onObject:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO awtMode:NO]; [ThreadUtilities performOnMainThread:@selector(postValueChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env); JNF_COCOA_EXIT(env);
} }
...@@ -1177,7 +1169,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectionChanged ...@@ -1177,7 +1169,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_selectionChanged
(JNIEnv *env, jclass jklass, jlong element) (JNIEnv *env, jclass jklass, jlong element)
{ {
JNF_COCOA_ENTER(env); JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(postSelectionChanged) onObject:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO awtMode:NO]; [ThreadUtilities performOnMainThread:@selector(postSelectionChanged) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env); JNF_COCOA_EXIT(env);
} }
...@@ -1191,7 +1183,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_unregisterFromCocoaAXSy ...@@ -1191,7 +1183,7 @@ JNIEXPORT void JNICALL Java_sun_lwawt_macosx_CAccessible_unregisterFromCocoaAXSy
(JNIEnv *env, jclass jklass, jlong element) (JNIEnv *env, jclass jklass, jlong element)
{ {
JNF_COCOA_ENTER(env); JNF_COCOA_ENTER(env);
[ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) onObject:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO awtMode:NO]; [ThreadUtilities performOnMainThread:@selector(unregisterFromCocoaAXSystem) on:(JavaComponentAccessibility *)jlong_to_ptr(element) withObject:nil waitUntilDone:NO];
JNF_COCOA_EXIT(env); JNF_COCOA_EXIT(env);
} }
......
...@@ -332,7 +332,7 @@ AWT_ASSERT_APPKIT_THREAD; ...@@ -332,7 +332,7 @@ AWT_ASSERT_APPKIT_THREAD;
* Signature: (JZZ)V * Signature: (JZZ)V
*/ */
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_doAWTRunLoop JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_doAWTRunLoop
(JNIEnv *env, jclass clz, jlong mediator, jboolean awtMode, jboolean detectDeadlocks) (JNIEnv *env, jclass clz, jlong mediator, jboolean processEvents)
{ {
AWT_ASSERT_APPKIT_THREAD; AWT_ASSERT_APPKIT_THREAD;
JNF_COCOA_ENTER(env); JNF_COCOA_ENTER(env);
...@@ -341,25 +341,24 @@ JNF_COCOA_ENTER(env); ...@@ -341,25 +341,24 @@ JNF_COCOA_ENTER(env);
if (mediatorObject == nil) return; if (mediatorObject == nil) return;
if (!sInPerformFromJava || !detectDeadlocks) {
NSRunLoop *currentRunLoop = [NSRunLoop currentRunLoop];
NSDate *distantFuture = [NSDate distantFuture];
NSString *mode = (awtMode) ? [JNFRunLoop javaRunLoopMode] : NSDefaultRunLoopMode;
BOOL isRunning = YES;
while (isRunning && ![mediatorObject shouldEndRunLoop]) {
// Don't use acceptInputForMode because that doesn't setup autorelease pools properly // Don't use acceptInputForMode because that doesn't setup autorelease pools properly
isRunning = [currentRunLoop runMode:mode beforeDate:distantFuture]; BOOL isRunning = true;
while (![mediatorObject shouldEndRunLoop] && isRunning) {
isRunning = [[NSRunLoop currentRunLoop] runMode:[JNFRunLoop javaRunLoopMode]
beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.010]];
if (processEvents) {
//We do not spin a runloop here as date is nil, so does not matter which mode to use
NSEvent *event;
if ((event = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:nil
inMode:NSDefaultRunLoopMode
dequeue:YES]) != nil) {
[NSApp sendEvent:event];
} }
} }
#ifndef PRODUCT_BUILD
if (sInPerformFromJava) {
NSLog(@"Apple AWT: Short-circuiting CToolkit.invokeAndWait trampoline deadlock!!!!!");
NSLog(@"\tPlease file a bug report with this message and a reproducible test case.");
} }
#endif
CFRelease(mediatorObject); CFRelease(mediatorObject);
...@@ -379,7 +378,7 @@ JNF_COCOA_ENTER(env); ...@@ -379,7 +378,7 @@ JNF_COCOA_ENTER(env);
AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator); AWTRunLoopObject* mediatorObject = (AWTRunLoopObject*)jlong_to_ptr(mediator);
[ThreadUtilities performOnMainThread:@selector(endRunLoop) onObject:mediatorObject withObject:nil waitUntilDone:NO awtMode:YES]; [ThreadUtilities performOnMainThread:@selector(endRunLoop) on:mediatorObject withObject:nil waitUntilDone:NO];
CFRelease(mediatorObject); CFRelease(mediatorObject);
...@@ -463,20 +462,3 @@ Java_sun_font_FontManager_populateFontFileNameMap ...@@ -463,20 +462,3 @@ Java_sun_font_FontManager_populateFontFileNameMap
} }
/*
* Class: sun_lwawt_macosx_LWCToolkit
* Method: executeNextAppKitEvent
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_sun_lwawt_macosx_LWCToolkit_executeNextAppKitEvent
(JNIEnv *env, jclass cls)
{
// Simply get the next event in native loop and pass it to execution
// We'll be called repeatedly so there's no need to block here
NSRunLoop *theRL = [NSRunLoop currentRunLoop];
NSApplication * app = [NSApplication sharedApplication];
NSEvent * event = [app nextEventMatchingMask: 0xFFFFFFFF untilDate:nil inMode:NSDefaultRunLoopMode dequeue:YES];
if (event != nil) {
[app sendEvent: event];
}
}
...@@ -122,19 +122,12 @@ do { \ ...@@ -122,19 +122,12 @@ do { \
#endif /* AWT_THREAD_ASSERTS */ #endif /* AWT_THREAD_ASSERTS */
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// This tracks if we are current inside of a performOnMainThread that is both waiting and in the AWTRunLoopMode
extern BOOL sInPerformFromJava;
// This is an empty Obj-C object just so that -performSelectorOnMainThread
// can be used, and to use the Obj-C +initialize feature.
__attribute__((visibility("default"))) __attribute__((visibility("default")))
@interface ThreadUtilities : NSObject { } @interface ThreadUtilities { }
+ (JNIEnv*)getJNIEnv; + (JNIEnv*)getJNIEnv;
+ (JNIEnv*)getJNIEnvUncached; + (JNIEnv*)getJNIEnvUncached;
+ (void)performOnMainThread:(SEL)aSelector onObject:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait awtMode:(BOOL)inAWT;
//Wrappers for the corresponding JNFRunLoop methods with a check for main thread //Wrappers for the corresponding JNFRunLoop methods with a check for main thread
+ (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block; + (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block;
+ (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait; + (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait;
......
...@@ -34,85 +34,6 @@ ...@@ -34,85 +34,6 @@
JavaVM *jvm = NULL; JavaVM *jvm = NULL;
static JNIEnv *appKitEnv = NULL; static JNIEnv *appKitEnv = NULL;
static NSArray *sPerformModes = nil;
static NSArray *sAWTPerformModes = nil;
static BOOL sLoggingEnabled = YES;
#ifdef AWT_THREAD_ASSERTS_ENV_ASSERT
int sAWTThreadAsserts = 0;
#endif /* AWT_THREAD_ASSERTS_ENV_ASSERT */
BOOL sInPerformFromJava = NO;
// This class is used so that performSelectorOnMainThread can be
// controlled a little more easily by us. It has 2 roles.
// The first is to set/unset a flag (sInPerformFromJava) that code can
// check to see if we are in a synchronous perform initiated by a java thread.
// The second is to implement the CocoaComponent backward compatibility mode.
@interface CPerformer : NSObject {
id fTarget;
SEL fSelector;
id fArg;
BOOL fWait;
}
- (id) initWithTarget:(id)target selector:(SEL)selector arg:(id)arg wait:(BOOL)wait;
- (void) perform;
@end
@implementation CPerformer
- (id) initWithTarget:(id)target selector:(SEL)selector arg:(id)arg {
return [self initWithTarget:target selector:selector arg:arg wait:YES];
}
- (id) initWithTarget:(id)target selector:(SEL)selector arg:(id)arg wait:(BOOL)wait {
self = [super init];
if (self != nil) {
fTarget = [target retain];
fSelector = selector;
fArg = [arg retain];
// Only set sInPerformFromJava if this is a synchronous perform
fWait = wait;
}
return self;
}
- (void) dealloc {
[fTarget release];
[fArg release];
[super dealloc];
}
//- (void)finalize { [super finalize]; }
- (void) perform {
AWT_ASSERT_APPKIT_THREAD;
// If this is the first time we're going from java thread -> appkit thread,
// set sInPerformFromJava for the duration of the invocation
BOOL nestedPerform = sInPerformFromJava;
if (fWait) {
sInPerformFromJava = YES;
}
// Actually do the work (cheat to avoid a method call)
@try {
objc_msgSend(fTarget, fSelector, fArg);
//[fTarget performSelector:fSelector withObject:fArg];
} @catch (NSException *e) {
NSLog(@"*** CPerformer: ignoring exception '%@' raised during perform of selector '%@' on target '%@' with args '%@'", e, NSStringFromSelector(fSelector), fTarget, fArg);
} @finally {
// If we actually set sInPerformFromJava, unset it now
if (!nestedPerform && fWait) {
sInPerformFromJava = NO;
}
}
}
@end
@implementation ThreadUtilities @implementation ThreadUtilities
+ (JNIEnv*)getJNIEnv { + (JNIEnv*)getJNIEnv {
...@@ -129,36 +50,6 @@ AWT_ASSERT_APPKIT_THREAD; ...@@ -129,36 +50,6 @@ AWT_ASSERT_APPKIT_THREAD;
return env; return env;
} }
+ (void)initialize {
// Headless: BOTH
// Embedded: BOTH
// Multiple Calls: NO
// Caller: Obj-C class initialization
// Thread: ?
if (sPerformModes == nil) {
// Create list of Run Loop modes to perform on
// The default performSelector, with no mode argument, runs in Default,
// ModalPanel, and EventTracking modes
sPerformModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, NSModalPanelRunLoopMode, nil];
sAWTPerformModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, NSModalPanelRunLoopMode, NSEventTrackingRunLoopMode, [JNFRunLoop javaRunLoopMode], nil];
#ifdef AWT_THREAD_ASSERTS_ENV_ASSERT
sAWTThreadAsserts = (getenv("COCOA_AWT_DISABLE_THREAD_ASSERTS") == NULL);
#endif /* AWT_THREAD_ASSERTS_ENV_ASSERT */
}
}
// These methods can behave slightly differently than the normal
// performSelector... In particular, we define a special runloop mode
// (AWTRunLoopMode) so that we can "block" the main thread against the
// java event thread without deadlocking. See CToolkit.invokeAndWait.
+ (void)performOnMainThread:(SEL)aSelector onObject:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait awtMode:(BOOL)inAWT {
CPerformer *performer = [[CPerformer alloc] initWithTarget:target selector:aSelector arg:arg wait:wait];
[performer performSelectorOnMainThread:@selector(perform) withObject:nil waitUntilDone:wait modes:((inAWT) ? sAWTPerformModes : sPerformModes)]; // AWT_THREADING Safe (cover method)
[performer release];
}
+ (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block { + (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block {
if ([NSThread isMainThread] && wait == YES) { if ([NSThread isMainThread] && wait == YES) {
block(); block();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册