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 }