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