1 /* 2 * Copyright (c) 2011, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 #import <AppKit/AppKit.h> 27 #import <objc/message.h> 28 29 #import "ThreadUtilities.h" 30 31 32 // The following must be named "jvm", as there are extern references to it in AWT 33 JavaVM *jvm = NULL; 34 static JNIEnv *appKitEnv = NULL; 35 static jobject appkitThreadGroup = NULL; 36 static NSString* JavaRunLoopMode = @"javaRunLoopMode"; 37 static NSArray<NSString*> *javaModes = nil; 38 39 static inline void attachCurrentThread(void** env) { 40 if ([NSThread isMainThread]) { 41 JavaVMAttachArgs args; 42 args.version = JNI_VERSION_1_4; 43 args.name = "AppKit Thread"; 44 args.group = appkitThreadGroup; 45 (*jvm)->AttachCurrentThreadAsDaemon(jvm, env, &args); 46 } else { 47 (*jvm)->AttachCurrentThreadAsDaemon(jvm, env, NULL); 48 } 49 } 50 51 @implementation ThreadUtilities 52 53 + (void)initialize { 54 /* All the standard modes plus ours */ 55 javaModes = [[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, 56 NSModalPanelRunLoopMode, 57 NSEventTrackingRunLoopMode, 58 JavaRunLoopMode, 59 nil]; 60 } 61 62 + (JNIEnv*)getJNIEnv { 63 AWT_ASSERT_APPKIT_THREAD; 64 if (appKitEnv == NULL) { 65 attachCurrentThread((void **)&appKitEnv); 66 } 67 return appKitEnv; 68 } 69 70 + (JNIEnv*)getJNIEnvUncached { 71 JNIEnv *env = NULL; 72 attachCurrentThread((void **)&env); 73 return env; 74 } 75 76 + (void)detachCurrentThread { 77 (*jvm)->DetachCurrentThread(jvm); 78 } 79 80 + (void)setAppkitThreadGroup:(jobject)group { 81 appkitThreadGroup = group; 82 } 83 84 /* This is needed because we can't directly pass a block to 85 * performSelectorOnMainThreadWaiting .. since it expects a selector 86 */ 87 + (void)invokeBlock:(void (^)())block { 88 block(); 89 } 90 91 /* 92 * When running a block where either we don't wait, or it needs to run on another thread 93 * we need to copy it from stack to heap, use the copy in the call and release after use. 94 * Do this only when we must because it could be expensive. 95 * Note : if waiting cross-thread, possibly the stack allocated copy is accessible ? 96 */ 97 + (void)invokeBlockCopy:(void (^)(void))blockCopy { 98 blockCopy(); 99 Block_release(blockCopy); 100 } 101 102 + (void)performOnMainThreadWaiting:(BOOL)wait block:(void (^)())block { 103 if ([NSThread isMainThread] && wait == YES) { 104 block(); 105 } else { 106 if (wait == YES) { 107 [self performOnMainThread:@selector(invokeBlock:) on:self withObject:block waitUntilDone:YES]; 108 } else { 109 void (^blockCopy)(void) = Block_copy(block); 110 [self performOnMainThread:@selector(invokeBlockCopy:) on:self withObject:blockCopy waitUntilDone:NO]; 111 } 112 } 113 } 114 115 + (void)performOnMainThread:(SEL)aSelector on:(id)target withObject:(id)arg waitUntilDone:(BOOL)wait { 116 if ([NSThread isMainThread] && wait == YES) { 117 [target performSelector:aSelector withObject:arg]; 118 } else { 119 [target performSelectorOnMainThread:aSelector withObject:arg waitUntilDone:wait modes:javaModes]; 120 } 121 } 122 123 + (NSString*)javaRunLoopMode { 124 return JavaRunLoopMode; 125 } 126 127 @end 128 129 130 void OSXAPP_SetJavaVM(JavaVM *vm) 131 { 132 jvm = vm; 133 } 134