OpenJDK / bsd-port / bsd-port / jdk
changeset 4902:5599aa5a4a51
7131697: (se) Need AsynchronousChannelProvider implementation for Mac OS X
Reviewed-by: michaelm
author | alanb |
---|---|
date | Sat, 28 Jan 2012 11:37:15 +0000 |
parents | 5780795f381e |
children | 789287639365 |
files | make/java/nio/Makefile make/java/nio/mapfile-bsd src/solaris/classes/sun/nio/ch/BsdAsynchronousChannelProvider.java src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java src/solaris/classes/sun/nio/ch/KQueue.java src/solaris/classes/sun/nio/ch/KQueuePort.java src/solaris/native/sun/nio/ch/KQueue.c src/solaris/native/sun/nio/ch/KQueuePort.c |
diffstat | 8 files changed, 737 insertions(+), 1 deletions(-) [+] |
line wrap: on
line diff
--- a/make/java/nio/Makefile Fri Jan 27 21:59:22 2012 +0300 +++ b/make/java/nio/Makefile Sat Jan 28 11:37:15 2012 +0000 @@ -263,7 +263,10 @@ ifeq ($(PLATFORM), macosx) FILES_java += \ sun/nio/ch/AbstractPollSelectorImpl.java \ + sun/nio/ch/BsdAsynchronousChannelProvider.java \ sun/nio/ch/InheritedChannel.java \ + sun/nio/ch/KQueue.java \ + sun/nio/ch/KQueuePort.java \ sun/nio/ch/PollSelectorProvider.java \ sun/nio/ch/PollSelectorImpl.java \ sun/nio/ch/Port.java \ @@ -306,10 +309,15 @@ GnomeFileTypeDetector.c \ BsdNativeDispatcher.c \ UnixCopyFile.c \ - UnixNativeDispatcher.c + UnixNativeDispatcher.c \ + \ + KQueue.c \ + KQueuePort.c FILES_export += \ sun/nio/ch/InheritedChannel.java \ + sun/nio/ch/KQueue.java \ + sun/nio/ch/KQueuePort.java \ sun/nio/ch/NativeThread.java \ sun/nio/ch/UnixAsynchronousServerSocketChannelImpl.java \ sun/nio/ch/UnixAsynchronousSocketChannelImpl.java \
--- a/make/java/nio/mapfile-bsd Fri Jan 27 21:59:22 2012 +0300 +++ b/make/java/nio/mapfile-bsd Sat Jan 28 11:37:15 2012 +0000 @@ -73,6 +73,17 @@ Java_sun_nio_ch_IOUtil_makePipe; Java_sun_nio_ch_IOUtil_randomBytes; Java_sun_nio_ch_IOUtil_setfdVal; + Java_sun_nio_ch_KQueue_kqueue; + Java_sun_nio_ch_KQueue_keventRegister; + Java_sun_nio_ch_KQueue_keventPoll; + Java_sun_nio_ch_KQueue_keventSize; + Java_sun_nio_ch_KQueue_identOffset; + Java_sun_nio_ch_KQueue_filterOffset; + Java_sun_nio_ch_KQueue_flagsOffset; + Java_sun_nio_ch_KQueuePort_socketpair; + Java_sun_nio_ch_KQueuePort_interrupt; + Java_sun_nio_ch_KQueuePort_drain1; + Java_sun_nio_ch_KQueuePort_close0; Java_sun_nio_ch_NativeThread_current; Java_sun_nio_ch_NativeThread_init; Java_sun_nio_ch_NativeThread_signal;
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/solaris/classes/sun/nio/ch/BsdAsynchronousChannelProvider.java Sat Jan 28 11:37:15 2012 +0000 @@ -0,0 +1,90 @@ +/* + * Copyright (c) 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 sun.nio.ch; + +import java.nio.channels.*; +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ThreadFactory; +import java.io.IOException; + +public class BsdAsynchronousChannelProvider + extends AsynchronousChannelProvider +{ + private static volatile KQueuePort defaultPort; + + private KQueuePort defaultEventPort() throws IOException { + if (defaultPort == null) { + synchronized (BsdAsynchronousChannelProvider.class) { + if (defaultPort == null) { + defaultPort = new KQueuePort(this, ThreadPool.getDefault()).start(); + } + } + } + return defaultPort; + } + + public BsdAsynchronousChannelProvider() { + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory) + throws IOException + { + return new KQueuePort(this, ThreadPool.create(nThreads, factory)).start(); + } + + @Override + public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize) + throws IOException + { + return new KQueuePort(this, ThreadPool.wrap(executor, initialSize)).start(); + } + + private Port toPort(AsynchronousChannelGroup group) throws IOException { + if (group == null) { + return defaultEventPort(); + } else { + if (!(group instanceof KQueuePort)) + throw new IllegalChannelGroupException(); + return (Port)group; + } + } + + @Override + public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group) + throws IOException + { + return new UnixAsynchronousServerSocketChannelImpl(toPort(group)); + } + + @Override + public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group) + throws IOException + { + return new UnixAsynchronousSocketChannelImpl(toPort(group)); + } +}
--- a/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java Fri Jan 27 21:59:22 2012 +0300 +++ b/src/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java Sat Jan 28 11:37:15 2012 +0000 @@ -50,6 +50,8 @@ return new SolarisAsynchronousChannelProvider(); if (osname.equals("Linux")) return new LinuxAsynchronousChannelProvider(); + if (osname.startsWith("Mac OS")) + return new BsdAsynchronousChannelProvider(); throw new InternalError("platform not recognized"); }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/solaris/classes/sun/nio/ch/KQueue.java Sat Jan 28 11:37:15 2012 +0000 @@ -0,0 +1,120 @@ +/* + * Copyright (c) 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 sun.nio.ch; + +import java.io.IOException; +import sun.misc.Unsafe; + +/** + * Provides access to the BSD kqueue facility. + */ + +class KQueue { + private KQueue() { } + + private static final Unsafe unsafe = Unsafe.getUnsafe(); + + /** + * struct kevent { + * uintptr_t ident; // identifier for this event, usually the fd + * int16_t filter; // filter for event + * uint16_t flags; // general flags + * uint32_t fflags; // filter-specific flags + * intptr_t data; // filter-specific data + * void *udata; // opaque user data identifier + * }; + */ + private static final int SIZEOF_KQUEUEEVENT = keventSize(); + private static final int OFFSET_IDENT = identOffset(); + private static final int OFFSET_FILTER = filterOffset(); + private static final int OFFSET_FLAGS = flagsOffset(); + + // filters + static final int EVFILT_READ = -1; + static final int EVFILT_WRITE = -2; + + // flags + static final int EV_ADD = 0x0001; + static final int EV_ONESHOT = 0x0010; + static final int EV_CLEAR = 0x0020; + + /** + * Allocates a poll array to handle up to {@code count} events. + */ + static long allocatePollArray(int count) { + return unsafe.allocateMemory(count * SIZEOF_KQUEUEEVENT); + } + + /** + * Free a poll array + */ + static void freePollArray(long address) { + unsafe.freeMemory(address); + } + + /** + * Returns kevent[i]. + */ + static long getEvent(long address, int i) { + return address + (SIZEOF_KQUEUEEVENT*i); + } + + /** + * Returns the file descriptor from a kevent (assuming to be in ident field) + */ + static int getDescriptor(long address) { + return unsafe.getInt(address + OFFSET_IDENT); + } + + static int getFilter(long address) { + return unsafe.getShort(address + OFFSET_FILTER); + } + + static int getFlags(long address) { + return unsafe.getShort(address + OFFSET_FLAGS); + } + + // -- Native methods -- + + private static native int keventSize(); + + private static native int identOffset(); + + private static native int filterOffset(); + + private static native int flagsOffset(); + + static native int kqueue() throws IOException; + + static native int keventRegister(int kqpfd, int fd, int filter, int flags); + + static native int keventPoll(int kqpfd, long pollAddress, int nevents) + throws IOException; + + static { + Util.load(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/solaris/classes/sun/nio/ch/KQueuePort.java Sat Jan 28 11:37:15 2012 +0000 @@ -0,0 +1,331 @@ +/* + * Copyright (c) 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 sun.nio.ch; + +import java.nio.channels.spi.AsynchronousChannelProvider; +import java.io.IOException; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.RejectedExecutionException; +import java.util.concurrent.atomic.AtomicInteger; +import static sun.nio.ch.KQueue.*; + +/** + * AsynchronousChannelGroup implementation based on the BSD kqueue facility. + */ + +final class KQueuePort + extends Port +{ + // maximum number of events to poll at a time + private static final int MAX_KEVENTS_TO_POLL = 512; + + // kqueue file descriptor + private final int kqfd; + + // true if kqueue closed + private boolean closed; + + // socket pair used for wakeup + private final int sp[]; + + // number of wakeups pending + private final AtomicInteger wakeupCount = new AtomicInteger(); + + // address of the poll array passed to kqueue_wait + private final long address; + + // encapsulates an event for a channel + static class Event { + final PollableChannel channel; + final int events; + + Event(PollableChannel channel, int events) { + this.channel = channel; + this.events = events; + } + + PollableChannel channel() { return channel; } + int events() { return events; } + } + + // queue of events for cases that a polling thread dequeues more than one + // event + private final ArrayBlockingQueue<Event> queue; + private final Event NEED_TO_POLL = new Event(null, 0); + private final Event EXECUTE_TASK_OR_SHUTDOWN = new Event(null, 0); + + KQueuePort(AsynchronousChannelProvider provider, ThreadPool pool) + throws IOException + { + super(provider, pool); + + // open kqueue + this.kqfd = kqueue(); + + // create socket pair for wakeup mechanism + int[] sv = new int[2]; + try { + socketpair(sv); + + // register one end with kqueue + keventRegister(kqfd, sv[0], EVFILT_READ, EV_ADD); + } catch (IOException x) { + close0(kqfd); + throw x; + } + this.sp = sv; + + // allocate the poll array + this.address = allocatePollArray(MAX_KEVENTS_TO_POLL); + + // create the queue and offer the special event to ensure that the first + // threads polls + this.queue = new ArrayBlockingQueue<Event>(MAX_KEVENTS_TO_POLL); + this.queue.offer(NEED_TO_POLL); + } + + KQueuePort start() { + startThreads(new EventHandlerTask()); + return this; + } + + /** + * Release all resources + */ + private void implClose() { + synchronized (this) { + if (closed) + return; + closed = true; + } + freePollArray(address); + close0(sp[0]); + close0(sp[1]); + close0(kqfd); + } + + private void wakeup() { + if (wakeupCount.incrementAndGet() == 1) { + // write byte to socketpair to force wakeup + try { + interrupt(sp[1]); + } catch (IOException x) { + throw new AssertionError(x); + } + } + } + + @Override + void executeOnHandlerTask(Runnable task) { + synchronized (this) { + if (closed) + throw new RejectedExecutionException(); + offerTask(task); + wakeup(); + } + } + + @Override + void shutdownHandlerTasks() { + /* + * If no tasks are running then just release resources; otherwise + * write to the one end of the socketpair to wakeup any polling threads. + */ + int nThreads = threadCount(); + if (nThreads == 0) { + implClose(); + } else { + // send interrupt to each thread + while (nThreads-- > 0) { + wakeup(); + } + } + } + + // invoked by clients to register a file descriptor + @Override + void startPoll(int fd, int events) { + // We use a separate filter for read and write events. + // TBD: Measure cost of EV_ONESHOT vs. EV_CLEAR, either will do here. + int err = 0; + int flags = (EV_ADD|EV_ONESHOT); + if ((events & Port.POLLIN) > 0) + err = keventRegister(kqfd, fd, EVFILT_READ, flags); + if (err == 0 && (events & Port.POLLOUT) > 0) + err = keventRegister(kqfd, fd, EVFILT_WRITE, flags); + if (err != 0) + throw new InternalError("kevent failed: " + err); // should not happen + } + + /* + * Task to process events from kqueue and dispatch to the channel's + * onEvent handler. + * + * Events are retreived from kqueue in batch and offered to a BlockingQueue + * where they are consumed by handler threads. A special "NEED_TO_POLL" + * event is used to signal one consumer to re-poll when all events have + * been consumed. + */ + private class EventHandlerTask implements Runnable { + private Event poll() throws IOException { + try { + for (;;) { + int n = keventPoll(kqfd, address, MAX_KEVENTS_TO_POLL); + /* + * 'n' events have been read. Here we map them to their + * corresponding channel in batch and queue n-1 so that + * they can be handled by other handler threads. The last + * event is handled by this thread (and so is not queued). + */ + fdToChannelLock.readLock().lock(); + try { + while (n-- > 0) { + long keventAddress = getEvent(address, n); + int fd = getDescriptor(keventAddress); + + // wakeup + if (fd == sp[0]) { + if (wakeupCount.decrementAndGet() == 0) { + // no more wakeups so drain pipe + drain1(sp[0]); + } + + // queue special event if there are more events + // to handle. + if (n > 0) { + queue.offer(EXECUTE_TASK_OR_SHUTDOWN); + continue; + } + return EXECUTE_TASK_OR_SHUTDOWN; + } + + PollableChannel channel = fdToChannel.get(fd); + if (channel != null) { + int filter = getFilter(keventAddress); + int events = 0; + if (filter == EVFILT_READ) + events = Port.POLLIN; + else if (filter == EVFILT_WRITE) + events = Port.POLLOUT; + + Event ev = new Event(channel, events); + + // n-1 events are queued; This thread handles + // the last one except for the wakeup + if (n > 0) { + queue.offer(ev); + } else { + return ev; + } + } + } + } finally { + fdToChannelLock.readLock().unlock(); + } + } + } finally { + // to ensure that some thread will poll when all events have + // been consumed + queue.offer(NEED_TO_POLL); + } + } + + public void run() { + Invoker.GroupAndInvokeCount myGroupAndInvokeCount = + Invoker.getGroupAndInvokeCount(); + final boolean isPooledThread = (myGroupAndInvokeCount != null); + boolean replaceMe = false; + Event ev; + try { + for (;;) { + // reset invoke count + if (isPooledThread) + myGroupAndInvokeCount.resetInvokeCount(); + + try { + replaceMe = false; + ev = queue.take(); + + // no events and this thread has been "selected" to + // poll for more. + if (ev == NEED_TO_POLL) { + try { + ev = poll(); + } catch (IOException x) { + x.printStackTrace(); + return; + } + } + } catch (InterruptedException x) { + continue; + } + + // handle wakeup to execute task or shutdown + if (ev == EXECUTE_TASK_OR_SHUTDOWN) { + Runnable task = pollTask(); + if (task == null) { + // shutdown request + return; + } + // run task (may throw error/exception) + replaceMe = true; + task.run(); + continue; + } + + // process event + try { + ev.channel().onEvent(ev.events(), isPooledThread); + } catch (Error x) { + replaceMe = true; throw x; + } catch (RuntimeException x) { + replaceMe = true; throw x; + } + } + } finally { + // last handler to exit when shutdown releases resources + int remaining = threadExit(this, replaceMe); + if (remaining == 0 && isShutdown()) { + implClose(); + } + } + } + } + + // -- Native methods -- + + private static native void socketpair(int[] sv) throws IOException; + + private static native void interrupt(int fd) throws IOException; + + private static native void drain1(int fd) throws IOException; + + private static native void close0(int fd); + + static { + Util.load(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/solaris/native/sun/nio/ch/KQueue.c Sat Jan 28 11:37:15 2012 +0000 @@ -0,0 +1,98 @@ +/* + * Copyright (c) 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. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "nio_util.h" + +#include "sun_nio_ch_KQueue.h" + +#include <strings.h> +#include <sys/types.h> +#include <sys/event.h> +#include <sys/time.h> + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_KQueue_keventSize(JNIEnv* env, jclass this) +{ + return sizeof(struct kevent); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_KQueue_identOffset(JNIEnv* env, jclass this) +{ + return offsetof(struct kevent, ident); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_KQueue_filterOffset(JNIEnv* env, jclass this) +{ + return offsetof(struct kevent, filter); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_KQueue_flagsOffset(JNIEnv* env, jclass this) +{ + return offsetof(struct kevent, flags); +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_KQueue_kqueue(JNIEnv *env, jclass c) { + int kqfd = kqueue(); + if (kqfd < 0) { + JNU_ThrowIOExceptionWithLastError(env, "kqueue failed"); + } + return kqfd; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_KQueue_keventRegister(JNIEnv *env, jclass c, jint kqfd, + jint fd, jint filter, jint flags) + +{ + struct kevent changes[1]; + struct timespec timeout = {0, 0}; + int res; + + EV_SET(&changes[0], fd, filter, flags, 0, 0, 0); + RESTARTABLE(kevent(kqfd, &changes[0], 1, NULL, 0, &timeout), res); + return (res == -1) ? errno : 0; +} + +JNIEXPORT jint JNICALL +Java_sun_nio_ch_KQueue_keventPoll(JNIEnv *env, jclass c, + jint kqfd, jlong address, jint nevents) +{ + struct kevent *events = jlong_to_ptr(address); + int res; + + RESTARTABLE(kevent(kqfd, NULL, 0, events, nevents, NULL), res); + if (res < 0) { + JNU_ThrowIOExceptionWithLastError(env, "kqueue failed"); + } + return res; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/solaris/native/sun/nio/ch/KQueuePort.c Sat Jan 28 11:37:15 2012 +0000 @@ -0,0 +1,76 @@ +/* + * Copyright (c) 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. + */ + +#include "jni.h" +#include "jni_util.h" +#include "jvm.h" +#include "jlong.h" +#include "nio_util.h" + +#include "sun_nio_ch_KQueuePort.h" + +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> + +JNIEXPORT void JNICALL +Java_sun_nio_ch_KQueuePort_socketpair(JNIEnv* env, jclass clazz, jintArray sv) { + int sp[2]; + if (socketpair(PF_UNIX, SOCK_STREAM, 0, sp) == -1) { + JNU_ThrowIOExceptionWithLastError(env, "socketpair failed"); + } else { + jint res[2]; + res[0] = (jint)sp[0]; + res[1] = (jint)sp[1]; + (*env)->SetIntArrayRegion(env, sv, 0, 2, &res[0]); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_KQueuePort_interrupt(JNIEnv *env, jclass c, jint fd) { + int res; + int buf[1]; + buf[0] = 1; + RESTARTABLE(write(fd, buf, 1), res); + if (res < 0) { + JNU_ThrowIOExceptionWithLastError(env, "write failed"); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_KQueuePort_drain1(JNIEnv *env, jclass cl, jint fd) { + int res; + char buf[1]; + RESTARTABLE(read(fd, buf, 1), res); + if (res < 0) { + JNU_ThrowIOExceptionWithLastError(env, "drain1 failed"); + } +} + +JNIEXPORT void JNICALL +Java_sun_nio_ch_KQueuePort_close0(JNIEnv *env, jclass c, jint fd) { + int res; + RESTARTABLE(close(fd), res); +}