1 /* 2 * Copyright (c) 2011, 2015, 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 /* 27 * Must include this before JavaNativeFoundation.h to get jni.h from build 28 */ 29 #include "jni.h" 30 #include "jni_util.h" 31 32 #import "com_apple_concurrent_LibDispatchNative.h" 33 34 #import <dispatch/dispatch.h> 35 #import <JavaNativeFoundation/JavaNativeFoundation.h> 36 37 /* 38 * Declare library specific JNI_Onload entry if static build 39 */ 40 DEF_STATIC_JNI_OnLoad 41 42 /* 43 * Class: com_apple_concurrent_LibDispatchNative 44 * Method: nativeIsDispatchSupported 45 * Signature: ()Z 46 */ 47 JNIEXPORT jboolean JNICALL Java_com_apple_concurrent_LibDispatchNative_nativeIsDispatchSupported 48 (JNIEnv *env, jclass clazz) 49 { 50 return JNI_TRUE; 51 } 52 53 54 /* 55 * Class: com_apple_concurrent_LibDispatchNative 56 * Method: nativeGetMainQueue 57 * Signature: ()J 58 */ 59 JNIEXPORT jlong JNICALL Java_com_apple_concurrent_LibDispatchNative_nativeGetMainQueue 60 (JNIEnv *env, jclass clazz) 61 { 62 dispatch_queue_t queue = dispatch_get_main_queue(); 63 return ptr_to_jlong(queue); 64 } 65 66 67 /* 68 * Class: com_apple_concurrent_LibDispatchNative 69 * Method: nativeCreateConcurrentQueue 70 * Signature: (I)J 71 */ 72 JNIEXPORT jlong JNICALL Java_com_apple_concurrent_LibDispatchNative_nativeCreateConcurrentQueue 73 (JNIEnv *env, jclass clazz, jint priority) 74 { 75 dispatch_queue_t queue = dispatch_get_global_queue((long)priority, 0); 76 return ptr_to_jlong(queue); 77 } 78 79 80 /* 81 * Class: com_apple_concurrent_LibDispatchNative 82 * Method: nativeCreateSerialQueue 83 * Signature: (Ljava/lang/String;)J 84 */ 85 JNIEXPORT jlong JNICALL Java_com_apple_concurrent_LibDispatchNative_nativeCreateSerialQueue 86 (JNIEnv *env, jclass clazz, jstring name) 87 { 88 if (name == NULL) return 0L; 89 90 jboolean isCopy; 91 const char *queue_name = (*env)->GetStringUTFChars(env, name, &isCopy); 92 dispatch_queue_t queue = dispatch_queue_create(queue_name, NULL); 93 (*env)->ReleaseStringUTFChars(env, name, queue_name); 94 95 return ptr_to_jlong(queue); 96 } 97 98 99 /* 100 * Class: com_apple_concurrent_LibDispatchNative 101 * Method: nativeReleaseQueue 102 * Signature: (J)V 103 */ 104 JNIEXPORT void JNICALL Java_com_apple_concurrent_LibDispatchNative_nativeReleaseQueue 105 (JNIEnv *env, jclass clazz, jlong nativeQueue) 106 { 107 if (nativeQueue == 0L) return; 108 dispatch_release((dispatch_queue_t)jlong_to_ptr(nativeQueue)); 109 } 110 111 112 static JNF_CLASS_CACHE(jc_Runnable, "java/lang/Runnable"); 113 static JNF_MEMBER_CACHE(jm_run, jc_Runnable, "run", "()V"); 114 115 static void perform_dispatch(JNIEnv *env, jlong nativeQueue, jobject runnable, void (*dispatch_fxn)(dispatch_queue_t, dispatch_block_t)) 116 { 117 JNF_COCOA_ENTER(env); 118 dispatch_queue_t queue = (dispatch_queue_t)jlong_to_ptr(nativeQueue); 119 if (queue == NULL) return; // shouldn't happen 120 121 // create a global-ref around the Runnable, so it can be safely passed to the dispatch thread 122 JNFJObjectWrapper *wrappedRunnable = [[JNFJObjectWrapper alloc] initWithJObject:runnable withEnv:env]; 123 124 dispatch_fxn(queue, ^{ 125 // attach the dispatch thread to the JVM if necessary, and get an env 126 JNFThreadContext ctx = JNFThreadDetachOnThreadDeath | JNFThreadSetSystemClassLoaderOnAttach | JNFThreadAttachAsDaemon; 127 JNIEnv *blockEnv = JNFObtainEnv(&ctx); 128 129 JNF_COCOA_ENTER(blockEnv); 130 131 // call the user's runnable 132 JNFCallObjectMethod(blockEnv, [wrappedRunnable jObject], jm_run); 133 134 // explicitly clear object while we have an env (it's cheaper that way) 135 [wrappedRunnable setJObject:NULL withEnv:blockEnv]; 136 137 JNF_COCOA_EXIT(blockEnv); 138 139 // let the env go, but leave the thread attached as a daemon 140 JNFReleaseEnv(blockEnv, &ctx); 141 }); 142 143 // release this thread's interest in the Runnable, the block 144 // will have retained the it's own interest above 145 [wrappedRunnable release]; 146 147 JNF_COCOA_EXIT(env); 148 } 149 150 151 /* 152 * Class: com_apple_concurrent_LibDispatchNative 153 * Method: nativeExecuteAsync 154 * Signature: (JLjava/lang/Runnable;)V 155 */ 156 JNIEXPORT void JNICALL Java_com_apple_concurrent_LibDispatchNative_nativeExecuteAsync 157 (JNIEnv *env, jclass clazz, jlong nativeQueue, jobject runnable) 158 { 159 // enqueues and returns 160 perform_dispatch(env, nativeQueue, runnable, dispatch_async); 161 } 162 163 164 /* 165 * Class: com_apple_concurrent_LibDispatchNative 166 * Method: nativeExecuteSync 167 * Signature: (JLjava/lang/Runnable;)V 168 */ 169 JNIEXPORT void JNICALL Java_com_apple_concurrent_LibDispatchNative_nativeExecuteSync 170 (JNIEnv *env, jclass clazz, jlong nativeQueue, jobject runnable) 171 { 172 // blocks until the Runnable completes 173 perform_dispatch(env, nativeQueue, runnable, dispatch_sync); 174 }