Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/solaris/classes/sun/nio/ch/SolarisEventPort.java
32288 views
/*1* Copyright (c) 2008, 2013, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package sun.nio.ch;2627import java.nio.channels.spi.AsynchronousChannelProvider;28import java.util.concurrent.RejectedExecutionException;29import java.io.IOException;30import sun.misc.Unsafe;3132/**33* Provides an AsynchronousChannelGroup implementation based on the Solaris 1034* event port framework and also provides direct access to that framework.35*/3637class SolarisEventPort38extends Port39{40private static final Unsafe unsafe = Unsafe.getUnsafe();41private static final int addressSize = unsafe.addressSize();4243private static int dependsArch(int value32, int value64) {44return (addressSize == 4) ? value32 : value64;45}4647/*48* typedef struct port_event {49* int portev_events;50* ushort_t portev_source;51* ushort_t portev_pad;52* uintptr_t portev_object;53* void *portev_user;54* } port_event_t;55*/56static final int SIZEOF_PORT_EVENT = dependsArch(16, 24);57static final int OFFSETOF_EVENTS = 0;58static final int OFFSETOF_SOURCE = 4;59static final int OFFSETOF_OBJECT = 8;6061// port sources62static final short PORT_SOURCE_USER = 3;63static final short PORT_SOURCE_FD = 4;6465// file descriptor to event port.66private final int port;6768// true when port is closed69private boolean closed;7071SolarisEventPort(AsynchronousChannelProvider provider, ThreadPool pool)72throws IOException73{74super(provider, pool);7576// create event port77this.port = port_create();78}7980SolarisEventPort start() {81startThreads(new EventHandlerTask());82return this;83}8485// releass resources86private void implClose() {87synchronized (this) {88if (closed)89return;90closed = true;91}92port_close(port);93}9495private void wakeup() {96try {97port_send(port, 0);98} catch (IOException x) {99throw new AssertionError(x);100}101}102103@Override104void executeOnHandlerTask(Runnable task) {105synchronized (this) {106if (closed)107throw new RejectedExecutionException();108offerTask(task);109wakeup();110}111}112113@Override114void shutdownHandlerTasks() {115/*116* If no tasks are running then just release resources; otherwise117* write to the one end of the socketpair to wakeup any polling threads..118*/119int nThreads = threadCount();120if (nThreads == 0) {121implClose();122} else {123// send user event to wakeup each thread124while (nThreads-- > 0) {125try {126port_send(port, 0);127} catch (IOException x) {128throw new AssertionError(x);129}130}131}132}133134@Override135void startPoll(int fd, int events) {136// (re-)associate file descriptor137// no need to translate events138try {139port_associate(port, PORT_SOURCE_FD, fd, events);140} catch (IOException x) {141throw new AssertionError(); // should not happen142}143}144145/*146* Task to read a single event from the port and dispatch it to the147* channel's onEvent handler.148*/149private class EventHandlerTask implements Runnable {150public void run() {151Invoker.GroupAndInvokeCount myGroupAndInvokeCount =152Invoker.getGroupAndInvokeCount();153final boolean isPooledThread = (myGroupAndInvokeCount != null);154boolean replaceMe = false;155long address = unsafe.allocateMemory(SIZEOF_PORT_EVENT);156try {157for (;;) {158// reset invoke count159if (isPooledThread)160myGroupAndInvokeCount.resetInvokeCount();161162// wait for I/O completion event163// A error here is fatal (thread will not be replaced)164replaceMe = false;165try {166port_get(port, address);167} catch (IOException x) {168x.printStackTrace();169return;170}171172// event source173short source = unsafe.getShort(address + OFFSETOF_SOURCE);174if (source != PORT_SOURCE_FD) {175// user event is trigger to invoke task or shutdown176if (source == PORT_SOURCE_USER) {177Runnable task = pollTask();178if (task == null) {179// shutdown request180return;181}182// run task (may throw error/exception)183replaceMe = true;184task.run();185}186// ignore187continue;188}189190// pe->portev_object is file descriptor191int fd = (int)unsafe.getAddress(address + OFFSETOF_OBJECT);192// pe->portev_events193int events = unsafe.getInt(address + OFFSETOF_EVENTS);194195// lookup channel196PollableChannel ch;197fdToChannelLock.readLock().lock();198try {199ch = fdToChannel.get(fd);200} finally {201fdToChannelLock.readLock().unlock();202}203204// notify channel205if (ch != null) {206replaceMe = true;207// no need to translate events208ch.onEvent(events, isPooledThread);209}210}211} finally {212// free per-thread resources213unsafe.freeMemory(address);214// last task to exit when shutdown release resources215int remaining = threadExit(this, replaceMe);216if (remaining == 0 && isShutdown())217implClose();218}219}220}221222/**223* Creates an event port224*/225static native int port_create() throws IOException;226227/**228* Associates specific events of a given object with a port229*/230static native boolean port_associate(int port, int source, long object, int events)231throws IOException;232233/**234* Removes the association of an object with a port.235*/236static native boolean port_dissociate(int port, int source, long object)237throws IOException;238239/**240* Retrieves a single event from a port241*/242static native void port_get(int port, long pe) throws IOException;243244/**245* Retrieves at most {@code max} events from a port.246*/247static native int port_getn(int port, long address, int max, long timeout)248throws IOException;249250/**251* Sends a user-defined eventto a specified port.252*/253static native void port_send(int port, int events) throws IOException;254255/**256* Closes a port.257*/258static native void port_close(int port);259260261static {262IOUtil.load();263}264}265266267