Index: modules/nio/src/main/java/org/apache/harmony/nio/internal/EpollSelectorProviderImpl.java =================================================================== --- modules/nio/src/main/java/org/apache/harmony/nio/internal/EpollSelectorProviderImpl.java (revision 0) +++ modules/nio/src/main/java/org/apache/harmony/nio/internal/EpollSelectorProviderImpl.java (revision 0) @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.nio.internal; + +import java.io.IOException; +import java.nio.channels.DatagramChannel; +import java.nio.channels.Pipe; +import java.nio.channels.ServerSocketChannel; +import java.nio.channels.SocketChannel; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.SelectorProvider; + + +/* + * Internal implementation of SelectorProvider. + * + */ +public class EpollSelectorProviderImpl extends SelectorProvider { + + /* + * Constructor for this class. + */ + public EpollSelectorProviderImpl() { + super(); + System.out.println("Now using EpollSelectorProvider"); + } + + /* + * + * @see java.nio.channels.spi.SelectorProvider#openDatagramChannel() + */ + public DatagramChannel openDatagramChannel() throws IOException { + return new DatagramChannelImpl(this); + } + + /* + * + * @see java.nio.channels.spi.SelectorProvider#openPipe() + */ + public Pipe openPipe() throws IOException { + return new PipeImpl(); + } + + /* + * + * @see java.nio.channels.spi.SelectorProvider#openSelector() + */ + public AbstractSelector openSelector() throws IOException { + return new EpollSelectorImpl(this); + } + + /* + * + * @see java.nio.channels.spi.SelectorProvider#openServerSocketChannel() + */ + public ServerSocketChannel openServerSocketChannel() throws IOException { + return new ServerSocketChannelImpl(this); + } + + /* + * + * @see java.nio.channels.spi.SelectorProvider#openSocketChannel() + */ + public SocketChannel openSocketChannel() throws IOException { + return new SocketChannelImpl(this); + } + +} Index: modules/nio/src/main/java/org/apache/harmony/nio/internal/EpollSelectionKeyImpl.java =================================================================== --- modules/nio/src/main/java/org/apache/harmony/nio/internal/EpollSelectionKeyImpl.java (revision 0) +++ modules/nio/src/main/java/org/apache/harmony/nio/internal/EpollSelectionKeyImpl.java (revision 0) @@ -0,0 +1,125 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.harmony.nio.internal; + +import java.nio.channels.CancelledKeyException; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.AbstractSelectionKey; + +/* + * Default implementation of SelectionKey + */ +final class EpollSelectionKeyImpl extends AbstractSelectionKey { + + private AbstractSelectableChannel channel; + + private int interestOps; + + private int readyOps; + + private EpollSelectorImpl selector; + + private int index; + + static int stHash; + + private int hashCode; + + public int hashCode() { + return hashCode; + } + + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + final EpollSelectionKeyImpl other = (EpollSelectionKeyImpl) obj; + if (hashCode != other.hashCode) + return false; + return true; + } + + public EpollSelectionKeyImpl(AbstractSelectableChannel channel, int operations, + Object attachment, EpollSelectorImpl selector) { + super(); + this.channel = channel; + interestOps = operations; + this.selector = selector; + this.hashCode = stHash++; + attach(attachment); + } + + public SelectableChannel channel() { + return channel; + } + + public int interestOps() { + checkValid(); + synchronized (selector.keysLock) { + return interestOps; + } + } + + public SelectionKey interestOps(int operations) { + checkValid(); + if ((operations & ~(channel().validOps())) != 0) { + throw new IllegalArgumentException(); + } + synchronized (selector.keysLock) { + interestOps = operations; + selector.modKey(this); + } + return this; + } + + public int readyOps() { + checkValid(); + return readyOps; + } + + public Selector selector() { + return selector; + } + + /* + * package private method for setting the ready operation by selector + */ + void setReadyOps(int readyOps) { + this.readyOps = readyOps; + } + + int getIndex() { + return index; + } + + void setIndex(int index) { + this.index = index; + } + + private void checkValid() { + if (!isValid()) { + throw new CancelledKeyException(); + } + } + +} \ No newline at end of file Index: modules/nio/src/main/java/org/apache/harmony/nio/internal/EpollSelectorImpl.java =================================================================== --- modules/nio/src/main/java/org/apache/harmony/nio/internal/EpollSelectorImpl.java (revision 0) +++ modules/nio/src/main/java/org/apache/harmony/nio/internal/EpollSelectorImpl.java (revision 0) @@ -0,0 +1,646 @@ +/* Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.harmony.nio.internal; + +import java.io.FileDescriptor; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.ClosedSelectorException; +import java.nio.channels.IllegalSelectorException; +import java.nio.channels.Pipe; +import java.nio.channels.SelectableChannel; +import java.nio.channels.SelectionKey; +import java.nio.channels.Selector; +import java.nio.channels.SocketChannel; +import java.nio.channels.spi.AbstractSelectableChannel; +import java.nio.channels.spi.AbstractSelectionKey; +import java.nio.channels.spi.AbstractSelector; +import java.nio.channels.spi.SelectorProvider; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.lang.Class; + +import org.apache.harmony.luni.platform.FileDescriptorHandler; +import org.apache.harmony.luni.platform.Platform; + +/* + * Default implementation of java.nio.channels.Selector + * + */ +final class EpollSelectorImpl extends AbstractSelector { + + private static final int MOCK_WRITEBUF_SIZE = 1; + + private static final int MOCK_READBUF_SIZE = 8; + + private static final int NA = 0; + + private static final int READABLE = 1; + + private static final int WRITABLE = 2; + + private static final int SELECT_BLOCK = -1; + + private static final int SELECT_NOW = 0; + + // keysLock is used to brief synchronization when get selectionKeys snapshot + // before selection + final Object keysLock = new Object(); + + boolean keySetChanged = true; + + private SelectionKey[] keys = new SelectionKey[1]; + + private final Set keysSet = new HashSet(); + + private Set unmodifiableKeys = Collections + .unmodifiableSet(keysSet); + + private final Set selectedKeys = new HashSet(); + + private Set unaddableSelectedKeys = new UnaddableSet( + selectedKeys); + + // sink and source are used by wakeup() + private Pipe.SinkChannel sink; + + private Pipe.SourceChannel source; + + private FileDescriptor sourcefd; + + private int[] keyFDs; + + private int[] readyFDs; + + private int[] readyOps; + + private int keysCount = 0; + + private long epollFD; + + private int countReady; + + public Class fileDescriptorClass; + + static native int resolveFD(Class cfd, FileDescriptor ofd); + + static native long prepare(); + + static native long addFileDescriptor(long epollFD, int mode, int fd); + + static native long delFileDescriptor(long epollFD, long fd); + + static native int epoll(long epollFD, int count, int[] FDs, int[] ops, long timeout); + + private internalKeyMap quickMap = new internalKeyMap(); + + public EpollSelectorImpl(SelectorProvider selectorProvider) { + super(selectorProvider); + try { + Pipe mockSelector = selectorProvider.openPipe(); + sink = mockSelector.sink(); + source = mockSelector.source(); + sourcefd = ((FileDescriptorHandler)source).getFD(); + source.configureBlocking(false); + + fileDescriptorClass = sourcefd.getClass(); + + keyFDs = new int[1]; + readyFDs = new int[1]; + readyOps = new int[1]; + + // register sink channel + keyFDs[0] = resolveFD(fileDescriptorClass, sourcefd); + keys[0] = source.keyFor(this); + epollFD = prepare(); + + keysCount = 1; + + addFileDescriptor(epollFD, 1, keyFDs[0]); + + } catch (IOException e) { + // do nothing + } + } + + /* + * @see java.nio.channels.spi.AbstractSelector#implCloseSelector() + */ + protected void implCloseSelector() throws IOException { + synchronized (this) { + synchronized (keysSet) { + synchronized (selectedKeys) { + doCancel(); + for(int c = 0; c < keysCount; c++) { + if (keys[c] != null) { + deregister((AbstractSelectionKey) keys[c]); + } + } + wakeup(); + } + } + } + } + + private void ensureCapacity(int c) { + // TODO: rewrite array handling as some internal class + if(c >= keys.length) { + SelectionKey[] t = new SelectionKey[(keys.length + 1) << 1]; + System.arraycopy(keys, 0, t, 0, keys.length); + keys = t; + } + + if(c >= readyFDs.length) { + int[] t = new int[(readyFDs.length + 1) << 1]; + System.arraycopy(readyFDs, 0, t, 0, readyFDs.length); + readyFDs = t; + } + + if (c >= keyFDs.length) { + int[] t = new int[(keyFDs.length + 1) << 1]; + System.arraycopy(keyFDs, 0, t, 0, keyFDs.length); + keyFDs = t; + } + + if (c >= readyOps.length) { + int[] t = new int[(readyOps.length + 1) << 1]; + System.arraycopy(readyOps, 0, t, 0, readyOps.length); + readyOps = t; + } + } + + private void limitCapacity() { + // TODO: implement array squeezing + } + + /** + * Adds the specified key to storage and updates the indexes accordingly + * @param sk key to add + * @return index in the storage + */ + private int addKey(SelectionKey sk) { + + // make sure that enough space is available + ensureCapacity(keysCount); + + // get channel params + int ops = sk.interestOps(); + int fd = resolveFD(fileDescriptorClass, ((FileDescriptorHandler) sk.channel()).getFD()); + + int eops = 0; + if (((SelectionKey.OP_READ | SelectionKey.OP_ACCEPT) & ops) != 0) { eops = eops + READABLE; }; + if (((SelectionKey.OP_WRITE | SelectionKey.OP_CONNECT) & ops) != 0) { eops = eops + WRITABLE; }; + + keys[keysCount] = sk; + keyFDs[keysCount] = fd; + + quickMap.put(fd, (EpollSelectionKeyImpl)sk); + addFileDescriptor(epollFD, eops, fd); + + return keysCount++; + } + + /** + * Deletes the key from the internal storage and updates the indexes accordingly + * @param sk key to delete + */ + private void delKey(SelectionKey sk) { + + // get the key index in the internal storage + int index = ((EpollSelectionKeyImpl)sk).getIndex(); + + // deregister FD in native + delFileDescriptor(epollFD, keyFDs[index]); + + // key is null now + keys[index] = null; + + // key compaction to ensure lack of holes + // we can simply exchange latest and current keys + if (keys[keysCount-1] != null) { + keys[index] = keys[keysCount-1]; + keys[keysCount-1] = null; + + keyFDs[index] = keyFDs[keysCount-1]; + keyFDs[keysCount-1] = -1; + + // update key index + ((EpollSelectionKeyImpl)keys[index]).setIndex(index); + } + keysCount--; + } + + /** + * + * @param sk + */ + void modKey(SelectionKey sk) { + // TODO: update indexes rather than recreate the key + synchronized(keysSet) { + delKey(sk); + addKey(sk); + } + } + + /* + * @see java.nio.channels.spi.AbstractSelector#register(java.nio.channels.spi.AbstractSelectableChannel, + * int, java.lang.Object) + */ + protected SelectionKey register(AbstractSelectableChannel channel, + int operations, Object attachment) { + if (!provider().equals(channel.provider())) { + throw new IllegalSelectorException(); + } + synchronized (this) { + synchronized (keysSet) { + + // create the key + SelectionKey sk = new EpollSelectionKeyImpl(channel, operations, attachment, this); + + int index = addKey(sk); + ((EpollSelectionKeyImpl)sk).setIndex(index); + + return sk; + } + } + } + + /* + * @see java.nio.channels.Selector#keys() + */ + public synchronized Set keys() { + closeCheck(); + + keysSet.clear(); + + if (keys.length != keysCount) { + SelectionKey[] chompedKeys = new SelectionKey[keysCount]; + System.arraycopy(keys, 0, chompedKeys, 0, keysCount); + keysSet.addAll(Arrays.asList(chompedKeys)); + } else { + keysSet.addAll(Arrays.asList(keys)); + } + + keysSet.remove(source.keyFor(this)); + return unmodifiableKeys; + } + + private void closeCheck() { + if (!isOpen()) { + throw new ClosedSelectorException(); + } + } + + /* + * @see java.nio.channels.Selector#select() + */ + public int select() throws IOException { + return selectInternal(SELECT_BLOCK); + } + + /* + * @see java.nio.channels.Selector#select(long) + */ + public int select(long timeout) throws IOException { + if (timeout < 0) { + throw new IllegalArgumentException(); + } + return selectInternal((0 == timeout) ? SELECT_BLOCK : timeout); + } + + /* + * @see java.nio.channels.Selector#selectNow() + */ + public int selectNow() throws IOException { + return selectInternal(SELECT_NOW); + } + + private int selectInternal(long timeout) throws IOException { + closeCheck(); + synchronized (this) { + synchronized (keysSet) { + synchronized (selectedKeys) { + doCancel(); + boolean isBlock = (SELECT_NOW != timeout); + try { + if (isBlock) { + begin(); + } + countReady = epoll(epollFD, keysCount, readyFDs, readyOps, timeout); + } finally { + if (isBlock) { + end(); + } + } + return processSelectResult(); + } + } + } + } + + private boolean isConnected(EpollSelectionKeyImpl key) { + SelectableChannel channel = key.channel(); + if (channel instanceof SocketChannel) { + return ((SocketChannel) channel).isConnected(); + } + return true; + } + + /* + * Analyses selected channels and adds keys of ready channels to + * selectedKeys list. + * + * readyChannels are encoded as concatenated array of flags for readable + * channels followed by writable channels. + */ + private int processSelectResult() throws IOException { + if (0 == countReady) { + return 0; + } + if (-1 == countReady) { + return 0; + } + // if the mock channel is selected, read the content. + if (READABLE == readyOps[0]) { + ByteBuffer readbuf = ByteBuffer.allocate(MOCK_READBUF_SIZE); + while (source.read(readbuf) > 0) { + readbuf.flip(); + } + } + int selected = 0; + + EpollSelectionKeyImpl key = null; + for (int i = 0; i < countReady; i++) { + + // Lookup the key, map the index in readyFDs to real key + key = (EpollSelectionKeyImpl)quickMap.get(readyFDs[i]); + + if (null == key) { + continue; + } + + int ops = key.interestOps(); + int selectedOp = 0; + + if ( (readyOps[i] & READABLE) != 0 ) { + selectedOp = (SelectionKey.OP_READ | SelectionKey.OP_ACCEPT) & ops; + } + + if ( (readyOps[i] & WRITABLE) != 0 ) { + if (isConnected(key)) { + selectedOp = SelectionKey.OP_WRITE & ops; + } else { + selectedOp = SelectionKey.OP_CONNECT & ops; + } + } + + if (0 != selectedOp) { + if (selectedKeys.contains(key)) { + if (key.readyOps() != selectedOp) { + key.setReadyOps(key.readyOps() | selectedOp); + selected++; + } + } else { + key.setReadyOps(selectedOp); + selectedKeys.add(key); + selected++; + } + } + + } + + return selected; + } + + /* + * @see java.nio.channels.Selector#selectedKeys() + */ + public synchronized Set selectedKeys() { + closeCheck(); + return unaddableSelectedKeys; + } + + private void doCancel() { + Set cancelledKeys = cancelledKeys(); + synchronized (cancelledKeys) { + if (cancelledKeys.size() > 0) { + for (SelectionKey currentkey : cancelledKeys) { + delKey(currentkey); + deregister((AbstractSelectionKey) currentkey); + selectedKeys.remove(currentkey); + } + } + cancelledKeys.clear(); + limitCapacity(); + } + } + + /* + * @see java.nio.channels.Selector#wakeup() + */ + public Selector wakeup() { + try { + sink.write(ByteBuffer.allocate(MOCK_WRITEBUF_SIZE)); + } catch (IOException e) { + // do nothing + } + return this; + } + + private static class internalKeyMap { + + Entry[] storage; + + int size; + + Entry deleted = new Entry(-1, null); + + final int threshRatio = 4; + + public internalKeyMap() { + this(1); + } + + public internalKeyMap(int initialSize) { + storage = new Entry[initialSize]; + size = 0; + } + + private E putEntryNoCheck(Entry[] storage, int key, Entry entry) { + + for(int tryCount = 0; tryCount < storage.length ; tryCount++) { + + int hash = hash(key, tryCount); + int index = hash % storage.length; + +// System.out.println("hash: " + hash + ", index: " + index + ", key: " + key + ", size: " + size + ", tryCount: " + tryCount + ", storage.length=" + storage.length); + + if ( storage[index] == null ) { + storage[index] = entry; + size++; + return null; + } else if ( storage[index].key == key || storage[index] == deleted){ + E t = storage[index].value; + storage[index] = entry; + return t; + } + } + + throw new ArrayIndexOutOfBoundsException(); + } + + private E putEntry(int key, Entry entry) { + if ( size >= storage.length || (storage.length / (storage.length - size)) >= threshRatio) { + rehash(); + } + + return putEntryNoCheck(storage, key, entry); + } + + public void put(int key, E value) { + Entry t = new Entry(key, value); + putEntry(key, t); + } + + public E get(int key) { + for(int tryCount = 0; tryCount < storage.length ; tryCount++) { + int hash = hash(key, tryCount); + int index = hash % storage.length; + if ( storage[index].key == key ) { + return storage[index].value; + } + + if ( storage[index] == null ) { + return null; + } + } + return null; + } + + public E remove(int key) { + size--; + return putEntry(key, deleted); + } + + private void rehash() { + Entry[] newStorage = new Entry[storage.length << 1]; + int newSize = 0; + for(int c = 0; c < storage.length; c++) { + if(storage[c] == null) continue; + if(storage[c] == deleted) continue; + putEntryNoCheck(newStorage, storage[c].key, storage[c]); + newSize++; + } + storage = newStorage; + size = newSize; + } + + private int hash(int key, int tryCount) { + int t1 = key*31 + 1; + int t2 = 2*key + 1; + return (t1+(t2*tryCount)) & 0x7FFFFFFF; + } + + private static class Entry { + + final int key; + final E value; + + public Entry(int iKey, E iValue) { + key = iKey; + value = iValue; + } + + } + + } + + private static class UnaddableSet implements Set { + + private Set set; + + UnaddableSet(Set set) { + this.set = set; + } + + public boolean equals(Object object) { + return set.equals(object); + } + + public int hashCode() { + return set.hashCode(); + } + + public boolean add(E object) { + throw new UnsupportedOperationException(); + } + + public boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public void clear() { + set.clear(); + } + + public boolean contains(Object object) { + return set.contains(object); + } + + public boolean containsAll(Collection c) { + return set.containsAll(c); + } + + public boolean isEmpty() { + return set.isEmpty(); + } + + public Iterator iterator() { + return set.iterator(); + } + + public boolean remove(Object object) { + return set.remove(object); + } + + public boolean removeAll(Collection c) { + return set.removeAll(c); + } + + public boolean retainAll(Collection c) { + return set.retainAll(c); + } + + public int size() { + return set.size(); + } + + public Object[] toArray() { + return set.toArray(); + } + + public T[] toArray(T[] a) { + return set.toArray(a); + } + } + + +} + Index: modules/nio/src/main/native/nio/unix/EpollSelectorImpl.c =================================================================== --- modules/nio/src/main/native/nio/unix/EpollSelectorImpl.c (revision 0) +++ modules/nio/src/main/native/nio/unix/EpollSelectorImpl.c (revision 0) @@ -0,0 +1,212 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include "hysock.h" +#include "hyport.h" +#include "EpollSelectorImpl.h" +/* Header for class org_apache_harmony_nio_internal_EPollSelectorImpl */ + +//#define EPOLL_DEBUG +//#define EPOLL_DEBUG_EXTENSIVE + +/* + * Class: org_apache_harmony_nio_internal_EpollSelectorImpl + * Method: resolveFD + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_apache_harmony_nio_internal_EpollSelectorImpl_resolveFD + (JNIEnv * env, jclass clazz, jclass cfd, jobject ofd) +{ + jfieldID descriptorFID = (*env)->GetFieldID(env, cfd, "descriptor", "J"); + return ((hysocket_t) ((IDATA)((*env)->GetLongField (env, ofd, descriptorFID))))->sock; +} + +/* + * Class: org_apache_harmony_nio_internal_EpollSelectorImpl + * Method: prepare + * Signature: ()I + */ +JNIEXPORT jlong JNICALL Java_org_apache_harmony_nio_internal_EpollSelectorImpl_prepare + (JNIEnv * jniEnv, jclass clazz) +{ + int fd; + +#ifdef EPOLL_DEBUG + printf("epoll(): initializing epoll\n"); +#endif + + fd = epoll_create(256); + +#ifdef EPOLL_DEBUG + printf("epoll(): epoll_create finished with %d\n", fd); +#endif + + // let the Java code handle the exceptions + return fd; +} + + +/* + * Class: org_apache_harmony_nio_internal_EpollSelectorImpl + * Method: addFileDescriptor + * Signature: (L)I + */ +JNIEXPORT jlong JNICALL Java_org_apache_harmony_nio_internal_EpollSelectorImpl_addFileDescriptor + (JNIEnv * env, jclass clazz, jlong epollfd, jint mode, jint fd) +{ + int op; + struct epoll_event ev; + int result; + + ev.events = 0; + if((mode & SOCKET_READ_OP) != 0) { + ev.events = ev.events | EPOLLIN | EPOLLPRI; + } + + if((mode & SOCKET_WRITE_OP) != 0) { + ev.events = ev.events | EPOLLOUT; + } + + ev.data.fd = fd; + +#ifdef EPOLL_DEBUG + printf("epoll(): fd=%d, adding %d to filedescriptor list with mode %d and event mask %d\n", epollfd, fd, mode, ev.events); +#endif + + result = epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev); + +#ifdef EPOLL_DEBUG + if(result == -1) { + printf("epoll(): result=%d errno=%d EBADF=%d EPERM=%d EINVAL=%d ENOMEM=%d\n", result, errno, EBADF, EPERM, EINVAL, ENOMEM); + } +#endif + + // let the java layer handle exceptions + return result; +} + + +/* + * Class: org_apache_harmony_nio_internal_EpollSelectorImpl + * Method: delFileDescriptor + * Signature: (L)I + */ +JNIEXPORT jlong JNICALL Java_org_apache_harmony_nio_internal_EpollSelectorImpl_delFileDescriptor + (JNIEnv * jniEnv, jclass clazz, jlong epollfd, jlong fd) +{ + int result; + struct epoll_event ev; + + ev.data.fd = fd; + +#ifdef EPOLL_DEBUG + printf("epoll(): deletin %ld from filedescriptor list\n", fd); +#endif + + result = epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev); + +#ifdef EPOLL_DEBUG + if (result == -1) { + printf("epoll(): result=%d errno=%d EBADF=%d EPERM=%d EINVAL=%d ENOMEM=%d\n", result, errno, EBADF, EPERM, EINVAL, ENOMEM); + } +#endif + + // let the Java layer handle exceptions + return result; +} + + +/* + * Class: org_apache_harmony_nio_internal_EpollSelectorImpl + * Method: epoll + * Signature: (L)I + */ +JNIEXPORT jint JNICALL Java_org_apache_harmony_nio_internal_EpollSelectorImpl_epoll + (JNIEnv * env, jclass clazz, jlong epollfd, jint count, jintArray fds, jintArray ops, jlong timeout) +{ + struct epoll_event * evs; + jint * fdsArray; + jint * opsArray; + int result; + int isCopy; + int c; + int temp; + + evs = malloc(sizeof(struct epoll_event)*count); + if (!evs) { + printf("epoll(): error on memory allocation\n"); + return -1; + + } + +#ifdef EPOLL_DEBUG +#ifdef EPOLL_DEBUG_EXTENSIVE + printf("epoll(): waiting on %d channels for %d msecs\n", count, timeout); +#endif +#endif + + // wait! + result = epoll_wait(epollfd, evs, count, timeout); + +#ifdef EPOLL_DEBUG +#ifdef EPOLL_DEBUG_EXTENSIVE + printf("epoll(): %d channels up, %d total\n", result, count); +#endif +#endif + +#ifdef EPOLL_DEBUG +#ifdef EPOLL_DEBUG_EXTENSIVE + printf("epoll(): Start parsing epoll() results\n"); +#endif +#endif + + // copying out the results, pinning might help here... + isCopy = NULL; + fdsArray = (*env)->GetIntArrayElements(env, fds, &isCopy); + + isCopy = NULL; + opsArray = (*env)->GetIntArrayElements(env, ops, &isCopy); + + for(c = 0; c < result; c++) { + fdsArray[c] = evs[c].data.fd; + + temp = SOCKET_NONE_OP; + if (evs[c].events & (EPOLLIN | EPOLLPRI)) { + temp = temp + SOCKET_READ_OP; + } + + if (evs[c].events & (EPOLLOUT)) { + temp = temp + SOCKET_WRITE_OP; + } + opsArray[c] = temp; + } + (*env)->ReleaseIntArrayElements(env, ops, opsArray, 0); + (*env)->ReleaseIntArrayElements(env, fds, fdsArray, 0); + +#ifdef EPOLL_DEBUG +#ifdef EPOLL_DEBUG_EXTENSIVE + printf("epoll(): End parsing epoll() results\n"); +#endif +#endif + + free(evs); + + // let the Java code handle the exceptions + return result; +} Index: modules/nio/src/main/native/nio/unix/exports.txt =================================================================== --- modules/nio/src/main/native/nio/unix/exports.txt (revision 576670) +++ modules/nio/src/main/native/nio/unix/exports.txt (working copy) @@ -2,3 +2,8 @@ GetDirectBufferAddress GetDirectBufferCapacity Java_org_apache_harmony_nio_AddressUtil_getFDAddress +Java_org_apache_harmony_nio_internal_EpollSelectorImpl_resolveFD +Java_org_apache_harmony_nio_internal_EpollSelectorImpl_prepare +Java_org_apache_harmony_nio_internal_EpollSelectorImpl_addFileDescriptor +Java_org_apache_harmony_nio_internal_EpollSelectorImpl_delFileDescriptor +Java_org_apache_harmony_nio_internal_EpollSelectorImpl_epoll Index: modules/nio/src/main/native/nio/unix/EpollSelectorImpl.h =================================================================== --- modules/nio/src/main/native/nio/unix/EpollSelectorImpl.h (revision 0) +++ modules/nio/src/main/native/nio/unix/EpollSelectorImpl.h (revision 0) @@ -0,0 +1,64 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +/* Header for class org_apache_harmony_nio_internal_EPollSelectorImpl */ +#define SOCKET_NONE_OP 0 +#define SOCKET_READ_OP 1 +#define SOCKET_WRITE_OP 2 + + +/* + * Class: org_apache_harmony_nio_internal_EpollSelectorImpl + * Method: resolveFD + * Signature: ()I + */ +JNIEXPORT jint JNICALL Java_org_apache_harmony_nio_internal_EpollSelectorImpl_resolveFD + (JNIEnv *, jclass, jclass, jobject); + +/* + * Class: org_apache_harmony_nio_internal_EpollSelectorImpl + * Method: prepare + * Signature: ()I + */ +JNIEXPORT jlong JNICALL Java_org_apache_harmony_nio_internal_EpollSelectorImpl_prepare + (JNIEnv *, jclass); + + +/* + * Class: org_apache_harmony_nio_internal_EpollSelectorImpl + * Method: addFileDescriptor + * Signature: (L)I + */ +JNIEXPORT jlong JNICALL Java_org_apache_harmony_nio_internal_EpollSelectorImpl_addFileDescriptor + (JNIEnv *, jclass, jlong, jint, jint); + +/* + * Class: org_apache_harmony_nio_internal_EpollSelectorImpl + * Method: delFileDescriptor + * Signature: (L)I + */ +JNIEXPORT jlong JNICALL Java_org_apache_harmony_nio_internal_EpollSelectorImpl_delFileDescriptor + (JNIEnv *, jclass, jlong, jlong); + +/* + * Class: org_apache_harmony_nio_internal_EpollSelectorImpl + * Method: epoll + * Signature: (L)I + */ +JNIEXPORT jint JNICALL Java_org_apache_harmony_nio_internal_EpollSelectorImpl_epoll + (JNIEnv *, jclass, jlong, jint, jlongArray, jintArray, jlong); Index: modules/nio/src/main/native/nio/unix/makefile =================================================================== --- modules/nio/src/main/native/nio/unix/makefile (revision 576670) +++ modules/nio/src/main/native/nio/unix/makefile (working copy) @@ -22,7 +22,7 @@ CFLAGS += -fpic BUILDFILES = \ - ../shared/DirectBufferUtil.o ../shared/AddressUtil.o + ../shared/DirectBufferUtil.o ../shared/AddressUtil.o ../unix/EpollSelectorImpl.o ifneq ($(HY_ZIP_API),true) MDLLIBFILES += $(LIBPATH)libhyzip.a