| /* |
| * Copyright (c) 2011, 2012, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. Oracle designates this |
| * particular file as subject to the "Classpath" exception as provided |
| * by Oracle in the LICENSE file that accompanied this code. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| package com.apple.concurrent; |
| |
| import java.util.concurrent.*; |
| |
| /** |
| * Factory for {@link Executor}s and {@link ExecutorService}s backed by |
| * libdispatch. |
| * |
| * Access is controlled through the Dispatch.getInstance() method, because |
| * performed tasks occur on threads owned by libdispatch. These threads are |
| * not owned by any particular AppContext or have any specific context |
| * classloader installed. |
| * |
| * @since Java for Mac OS X 10.6 Update 2 |
| */ |
| public final class Dispatch { |
| /** |
| * The priorities of the three default asynchronous queues. |
| */ |
| public enum Priority { |
| LOW(-2), NORMAL(0), HIGH(2); // values from <dispatch/queue.h> |
| |
| final int nativePriority; |
| Priority(final int nativePriority) { this.nativePriority = nativePriority; } |
| }; |
| |
| final static Dispatch instance = new Dispatch(); |
| |
| /** |
| * Factory method returns an instnace of Dispatch if supported by the |
| * underlying operating system, and if the caller's security manager |
| * permits "canInvokeInSystemThreadGroup". |
| * |
| * @return a factory instance of Dispatch, or null if not available |
| */ |
| public static Dispatch getInstance() { |
| checkSecurity(); |
| if (!LibDispatchNative.nativeIsDispatchSupported()) return null; |
| |
| return instance; |
| } |
| |
| private static void checkSecurity() { |
| final SecurityManager security = System.getSecurityManager(); |
| if (security != null) security.checkPermission(new RuntimePermission("canInvokeInSystemThreadGroup")); |
| } |
| |
| private Dispatch() { } |
| |
| /** |
| * Creates an {@link Executor} that performs tasks asynchronously. The {@link Executor} |
| * cannot be shutdown, and enqueued {@link Runnable}s cannot be canceled. Passing null |
| * returns the {@link Priority.NORMAL} {@link Executor}. |
| * |
| * @param priority - the priority of the returned {@link Executor} |
| * @return an asynchronous {@link Executor} |
| */ |
| public Executor getAsyncExecutor(Priority priority) { |
| if (priority == null) priority = Priority.NORMAL; |
| final long nativeQueue = LibDispatchNative.nativeCreateConcurrentQueue(priority.nativePriority); |
| if (nativeQueue == 0L) return null; |
| return new LibDispatchConcurrentQueue(nativeQueue); |
| } |
| |
| int queueIndex = 0; |
| /** |
| * Creates an {@link ExecutorService} that performs tasks synchronously in FIFO order. |
| * Useful to protect a resource against concurrent modification, in lieu of a lock. |
| * Passing null returns an {@link ExecutorService} with a uniquely labeled queue. |
| * |
| * @param label - a label to name the queue, shown in several debugging tools |
| * @return a synchronous {@link ExecutorService} |
| */ |
| public ExecutorService createSerialExecutor(String label) { |
| if (label == null) label = ""; |
| if (label.length() > 256) label = label.substring(0, 256); |
| String queueName = "com.apple.java.concurrent."; |
| if ("".equals(label)) { |
| synchronized (this) { |
| queueName += queueIndex++; |
| } |
| } else { |
| queueName += label; |
| } |
| |
| final long nativeQueue = LibDispatchNative.nativeCreateSerialQueue(queueName); |
| if (nativeQueue == 0) return null; |
| return new LibDispatchSerialQueue(nativeQueue); |
| } |
| |
| Executor nonBlockingMainQueue = null; |
| /** |
| * Returns an {@link Executor} that performs the provided Runnables on the main queue of the process. |
| * Runnables submitted to this {@link Executor} will not run until the AWT is started or another native toolkit is running a CFRunLoop or NSRunLoop on the main thread. |
| * |
| * Submitting a Runnable to this {@link Executor} does not wait for the Runnable to complete. |
| * @return an asynchronous {@link Executor} that is backed by the main queue |
| */ |
| public synchronized Executor getNonBlockingMainQueueExecutor() { |
| if (nonBlockingMainQueue != null) return nonBlockingMainQueue; |
| return nonBlockingMainQueue = new LibDispatchMainQueue.ASync(); |
| } |
| |
| Executor blockingMainQueue = null; |
| /** |
| * Returns an {@link Executor} that performs the provided Runnables on the main queue of the process. |
| * Runnables submitted to this {@link Executor} will not run until the AWT is started or another native toolkit is running a CFRunLoop or NSRunLoop on the main thread. |
| * |
| * Submitting a Runnable to this {@link Executor} will block until the Runnable has completed. |
| * @return an {@link Executor} that is backed by the main queue |
| */ |
| public synchronized Executor getBlockingMainQueueExecutor() { |
| if (blockingMainQueue != null) return blockingMainQueue; |
| return blockingMainQueue = new LibDispatchMainQueue.Sync(); |
| } |
| } |