This fixes some issues with the kqueue selector. In brief:

  - We make KqueueSelectionKeyImpl a subclass of AbstractSelectionKey,
which handles tracking canceled state.
  - We ensure that we deregister canceled keys with their channel, and
ignore keys attached to a closed channel.
  - Don't keep native state per key; now we just figure out which keys
need to be added, and which deleted, and build the entire native state
for that on the fly.

This now seems to work really well. I'm able to run Azureus (with some
random hangs that I haven't figured out yet) on jamvm on OS X, and it
runs nice out-of-the-box.

I'll make some similar fixes to the epoll selector once I'm able to test
on Linux again.

2006-09-27  Casey Marshall  <[EMAIL PROTECTED]>

        * gnu/java/nio/KqueueSelectionKeyImpl.java: extend
        AbstractSelectionKey.
        (nstate, valid, readEverEnabled, writeEverEnabled): removed.
        (activeOps, fd): new fields.
        (cancel): removed.
        (interestOps): just call `selector.setInterestOps.'
        (isValid): removed.
        (toString): include native fd in output.
        (hashCode, equals, isReadActive, isReadInterested, isWriteActive,
        isWriteInterested, needCommitRead, needCommitWrite): new methods.
        * gnu/java/nio/KqueueSelectorImpl.java (MAX_DOUBLING_CAPACITY,
        CAP_INCREMENT, INITIAL_CAPACITY): new constants.
        (cancelled): removed.
        (events): new field.
        (OP_ACCEPT, OP_CONNECT, OP_READ, OP_WRITE): new constants.
        (toString, equals): new methods.
        (doSelect): get cancelled keys from superclass; fix synchronization;
        initialize events that need to be added/deleted only when selecting;
        ignore keys attached to closed channels.
        (register): fix key initialization; synchronize adding keys.
        (setInterestOps): new method.
        (updateOps, updateOps): removed.
        (reallocateBuffer): new method.
        (doCancel): removed.
        (kevent_set): add index, active ops parameters; remove delete
        parameter.
        (kevent): add output space size parameter.
        * include/gnu_java_nio_KqueueSelectorImpl.h: regenerated.
        * native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c
        (Java_gnu_java_nio_KqueueSelectorImpl_kevent_1set): only fill in
        one filter, at the given index.
        (Java_gnu_java_nio_KqueueSelectorImpl_kevent): separate incoming
        event count and outgoing event count.
### Eclipse Workspace Patch 1.0
#P classpath
Index: native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c
===================================================================
RCS file: 
/cvsroot/classpath/classpath/native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c,v
retrieving revision 1.1
diff -u -r1.1 gnu_java_nio_KqueueSelectorImpl.c
--- native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c       17 Sep 2006 
07:31:43 -0000      1.1
+++ native/jni/java-nio/gnu_java_nio_KqueueSelectorImpl.c       27 Sep 2006 
21:03:24 -0000
@@ -66,6 +66,8 @@
 /* #define TRACE(fmt, ...) */
 /* #endif */
 
+/* #define TRACE_KQUEUE 1 */
+
 
 #define throw_not_supported(env) JCL_ThrowException (env, 
"java/lang/UnsupportedOperationException", "kqueue/kevent support not 
available")
 
@@ -157,53 +159,67 @@
 JNIEXPORT void JNICALL
 Java_gnu_java_nio_KqueueSelectorImpl_kevent_1set (JNIEnv *env,
                                                   jclass clazz 
__attribute__((unused)),
-                                                  jobject nstate, jint fd,
-                                                  jint ops, jint key, jboolean 
delete)
+                                                  jobject nstate, jint i, jint 
fd,
+                                                  jint ops, jint active, jint 
key)
 {
 #if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
-  struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, 
nstate);
-  short ident = kev->ident;
+  struct kevent *kev;
+  short ident;
+
+  kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, nstate);
+
+#ifdef TRACE_KQUEUE
+  printf ("kevent_set fd:%d p:%p i:%d ops:%x active:%x key:%x\n",
+          fd, (void *) kev, i, ops, active, key);
+#endif /* TRACE_KQUEUE */
+
+  if (kev == NULL)
+    {
+      JCL_ThrowException (env, "java/lang/InternalError",
+                          "GetDirectBufferAddress returned NULL!");
+      return;
+    }
 
-  if (fd != 0)
-    ident = fd;
+  ident = fd;
+  memset (&kev[i], 0, sizeof (struct kevent));
 
   if ((ops & KEY_OP_READ) || (ops & KEY_OP_ACCEPT))
     {
-      /* Add the event if we never added it before. */
-      if (kev[0].flags == 0 && JNI_FALSE == delete)
-        EV_SET(&kev[0], ident, EVFILT_READ, EV_ADD, 0, 0, (void *) key);
-      /* Otherwise, delete or reenable it. */
-      else if (kev[0].flags != 0)
-        EV_SET(&kev[0], ident, EVFILT_READ, (JNI_TRUE == delete) ? EV_DELETE : 
EV_ENABLE,
-               0, 0, (void *) key);
+      /* Add event if it wasn't previously added. */
+      if (!(active & KEY_OP_READ) && !(active & KEY_OP_ACCEPT))
+        EV_SET(&kev[i], ident, EVFILT_READ, EV_ADD, 0, 0, (void *) key);
     }
   else
     {
-      /* Means we've added this event before, and need to disable it. */
-      if (kev[0].flags != 0)
-        EV_SET(&kev[0], ident, EVFILT_READ, EV_DISABLE, 0, 0, (void *) key);
+      /* Delete event if it was previously added */
+      if ((active & KEY_OP_READ) || (active & KEY_OP_ACCEPT))
+        EV_SET(&kev[i], ident, EVFILT_READ, EV_DELETE, 0, 0, (void *) key);
     }
 
   /* Do the same thing for the write filter. */
   if ((ops & KEY_OP_WRITE) || (ops & KEY_OP_CONNECT))
     {
-      if (kev[1].flags == 0 && JNI_FALSE == delete)
-        EV_SET(&kev[1], ident, EVFILT_WRITE, EV_ADD, 0, 0, (void *) key);
-      else if (kev[1].flags != 0)
-        EV_SET(&kev[1], ident, EVFILT_WRITE, (JNI_TRUE == delete) ? EV_DELETE 
: EV_ENABLE,
-               0, 0, (void *) key);
+      if (!(active & KEY_OP_WRITE) && !(active & KEY_OP_CONNECT))
+        EV_SET(&kev[i], ident, EVFILT_WRITE, EV_ADD, 0, 0, (void *) key);
     }
   else
     {
-      if (kev[1].flags != 0)
-        EV_SET(&kev[1], ident, EVFILT_WRITE, EV_DISABLE, 0, 0, (void *) key);
+      if ((active & KEY_OP_WRITE) || (active & KEY_OP_CONNECT))
+        EV_SET(&kev[i], ident, EVFILT_WRITE, EV_DELETE, 0, 0, (void *) key);
     }
+
+#ifdef TRACE_KQUEUE
+  printf (" set kevent %2d:  ident:%u filter:%x flags:%o fflags:%o data:%p 
udata:%p\n",
+          i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, 
kev[i].fflags,
+          (void *) kev[i].data, kev[i].udata);
+#endif /* TRACE_KQUEUE */
 #else
   (void) nstate;
+  (void) i;
   (void) fd;
   (void) ops;
   (void) key;
-  (void) delete;
+  (void) active;
   throw_not_supported (env);
 #endif /* HAVE_KQUEUE && HAVE_KEVENT */
 }
@@ -218,7 +234,7 @@
 Java_gnu_java_nio_KqueueSelectorImpl_kevent (JNIEnv *env,
                                              jobject this 
__attribute__((unused)),
                                              jint kq, jobject nstate, jint 
nevents,
-                                             jlong timeout)
+                                             jint maxevents, jlong timeout)
 {
 #if defined(HAVE_KQUEUE) && defined(HAVE_KEVENT)
   struct timespec tv;
@@ -228,10 +244,13 @@
 
 #ifdef TRACE_KQUEUE
   int i;
+
+  printf ("[%d] kevent nevents:%d maxevents:%d timeout:%lld\n", kq, nevents, 
maxevents, timeout);
+  printf ("[%d] addding/deleting %d events\n", kq, nevents);
   for (i = 0; i < nevents; i++)
     {
-      printf ("kevent [%d]: ident:%u filter:%x flags:%o fflags:%o data:%p 
udata:%p\n",
-              i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, 
kev[i].fflags,
+      printf ("[%d] kevent input [%d]: ident:%u filter:%x flags:%o fflags:%o 
data:%p udata:%p\n",
+              kq, i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, 
kev[i].fflags,
               (void *) kev[i].data, kev[i].udata);
     }
 #endif
@@ -245,7 +264,7 @@
       t = &tv;
     }
 
-  ret = kevent (kq, (const struct kevent *) kev, nevents, kev, nevents, t);
+  ret = kevent (kq, (const struct kevent *) kev, nevents, kev, maxevents, t);
 
   if (ret == -1)
     {
@@ -258,8 +277,8 @@
 #ifdef TRACE_KQUEUE
   for (i = 0; i < ret; i++)
     {
-      printf ("kevent [%d]: ident:%u filter:%x flags:%o fflags:%o data:%p 
udata:%p\n",
-              i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, 
kev[i].fflags,
+      printf ("[%d] kevent output [%d]: ident:%u filter:%x flags:%o fflags:%o 
data:%p udata:%p\n",
+              kq, i, (unsigned) kev[i].ident, kev[i].filter, kev[i].flags, 
kev[i].fflags,
               (void *) kev[i].data, kev[i].udata);
     }
 #endif
@@ -269,6 +288,7 @@
   (void) kq;
   (void) nstate;
   (void) nevents;
+  (void) maxevents;
   (void) timeout;
   throw_not_supported (env);
   return -1;
@@ -312,6 +332,12 @@
   struct kevent *kev = (struct kevent *) (*env)->GetDirectBufferAddress (env, 
nstate);
   jint ready = 0;
 
+  if ((kev->flags & EV_ERROR) == EV_ERROR)
+    {
+      printf ("!!! error selecting fd %d: %s", (int) (kev->ident), strerror 
((int) (kev->data)));
+      return 0;
+    }
+
   /* We poll for READ for OP_READ and OP_ACCEPT. */
   if (kev->filter == EVFILT_READ)
     {
Index: gnu/java/nio/KqueueSelectorImpl.java
===================================================================
RCS file: /cvsroot/classpath/classpath/gnu/java/nio/KqueueSelectorImpl.java,v
retrieving revision 1.1
diff -u -r1.1 KqueueSelectorImpl.java
--- gnu/java/nio/KqueueSelectorImpl.java        17 Sep 2006 07:31:41 -0000      
1.1
+++ gnu/java/nio/KqueueSelectorImpl.java        27 Sep 2006 21:03:23 -0000
@@ -43,6 +43,7 @@
 import java.nio.ByteBuffer;
 import java.nio.ByteOrder;
 import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectableChannel;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
 import java.nio.channels.spi.AbstractSelectableChannel;
@@ -63,7 +64,10 @@
 public class KqueueSelectorImpl extends AbstractSelector
 {
   private static final int sizeof_struct_kevent;
-  
+  private static final int MAX_DOUBLING_CAPACITY = 16384;
+  private static final int CAP_INCREMENT = 1024;
+  private static final int INITIAL_CAPACITY;
+    
   static
   {
     try
@@ -79,6 +83,7 @@
       sizeof_struct_kevent = sizeof_struct_kevent();
     else
       sizeof_struct_kevent = -1;
+    INITIAL_CAPACITY = 16 * sizeof_struct_kevent;
   }
   
   /**
@@ -94,15 +99,20 @@
   
   private HashMap/*<Integer,KqueueSelectionKeyImpl>*/ keys;
   private HashSet/*<KqueueSelectionKeyImpl>*/ selected;
-  private HashSet/*<KqueueSelectionKeyImpl>*/ cancelled;
   private Thread blockedThread;
+  private ByteBuffer events;
+  
+  private static final int OP_ACCEPT  = SelectionKey.OP_ACCEPT;
+  private static final int OP_CONNECT = SelectionKey.OP_CONNECT;
+  private static final int OP_READ    = SelectionKey.OP_READ;
+  private static final int OP_WRITE   = SelectionKey.OP_WRITE;
 
   public KqueueSelectorImpl(SelectorProvider provider) throws IOException
   {
     super(provider);
     kq = implOpen();
     keys = new HashMap/*<KqueueSelectionKeyImpl>*/();
-    cancelled = new HashSet();
+    events = ByteBuffer.allocateDirect(INITIAL_CAPACITY);
   }
 
   protected void implCloseSelector() throws IOException
@@ -169,103 +179,140 @@
     return this;
   }
   
-  synchronized int doSelect(long timeout) throws IOException
+  public String toString()
   {
-    // FIXME -- I'm unclear on how we should synchronize this; and how to
-    // handle cancelled keys.
-    for (Iterator it = cancelled.iterator(); it.hasNext(); )
-      {
-        KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
-        updateOps(key, 0, true);
-      }
-    int events_size = 0;
-    for (Iterator it = keys.values().iterator(); it.hasNext(); )
+    return super.toString() + " [ fd: " + kq + " ]";
+  }
+  
+  public boolean equals(Object o)
+  {
+    if (!(o instanceof KqueueSelectorImpl))
+      return false;
+    
+    return ((KqueueSelectorImpl) o).kq == kq;
+  }
+  
+  int doSelect(long timeout) throws IOException
+  {
+    Set cancelled = cancelledKeys();
+    synchronized (cancelled)
+    {
+      synchronized (keys)
       {
-        KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
-        if ((key.interestOps & SelectionKey.OP_ACCEPT) != 0
-            || (key.interestOps & SelectionKey.OP_READ) != 0)
-          key.readEverEnabled = true;
-        if ((key.interestOps & SelectionKey.OP_CONNECT) != 0
-            || (key.interestOps & SelectionKey.OP_WRITE) != 0)
-          key.writeEverEnabled = true;
+        for (Iterator it = cancelled.iterator(); it.hasNext(); )
+          {
+            KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
+            key.interestOps = 0;
+          }
         
-        if (key.readEverEnabled)
-          events_size += sizeof_struct_kevent;
-        if (key.writeEverEnabled)
-          events_size += sizeof_struct_kevent;
-      }
+        int events_size = (2 * sizeof_struct_kevent) * keys.size();
+        int num_events = 0;
 
-    // We handle native events a little strangely here; per selection key,
-    // we allocate enough space for two struct kevents, the first in the
-    // list will be our EVFILT_READ filter, the second our EVFILT_WRITE
-    // one. If only one of the two needs enabling, though, we don't want
-    // to pass the other to kevent, because that would result in spurious
-    // events. We can break down our handling as follows:
-    //
-    //   - READ enabled, WRITE never enabled. We pass only the first structure
-    //     to kevent.
-    //   - WRITE enabled, READ never enabled. Likewise, but only pass the
-    //     second structure.
-    //   - READ and WRITE enabled. Pass both.
-    //   - READ enabled, WRITE enabled in the past. Pass both, with the
-    //     first structure's flag set to EV_ADD or EV_ENABLE, and the second
-    //     with EV_DISABLE. It seems OK to keep sending events with the
-    //     EV_DISABLE flag.
-    //   - WRITE enabled, READ enabled in the past. Likewise, but flipped.
-    //
-    // We handle these states with the readEverEnabled and writeEverEnabled
-    // flags of selection keys; they start off as false, and become true
-    // the first time we select() with READ or WRITE enabled. They never
-    // become false.
-    ByteBuffer events = ByteBuffer.allocateDirect(events_size);
+        for (Iterator it = keys.entrySet().iterator(); it.hasNext(); )
+          {
+            Map.Entry e = (Map.Entry) it.next();
+            KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) e.getValue();
+            
+            SelectableChannel ch = key.channel();
+            if (ch instanceof VMChannelOwner)
+              {
+                if (!((VMChannelOwner) ch).getVMChannel().getState().isValid())
+                  {
+                    // closed channel; removed from kqueue automatically.
+                    it.remove();
+                    continue;
+                  }
+              }
+            
+            // If this key is registering a read filter, add it to the buffer.
+            if (key.needCommitRead())
+              {
+                kevent_set(events, num_events, key.fd,
+                           key.interestOps & (OP_READ | OP_ACCEPT),
+                           key.activeOps & (OP_READ | OP_ACCEPT), key.key);
+                num_events++;
+              }
+            
+            // If this key is registering a write filter, add it to the buffer.
+            if (key.needCommitWrite())
+              {
+                kevent_set(events, num_events, key.fd,
+                           key.interestOps & (OP_WRITE | OP_CONNECT),
+                           key.activeOps & (OP_WRITE | OP_CONNECT), key.key);
+                num_events++;
+              }
+          }
+        events.rewind().limit(events.capacity());
+
+        //System.out.println("dump of keys to select:");
+        //dump_selection_keys(events.duplicate());
+
+        int n = 0;
+        try
+          {
+            //System.out.println("[" + kq + "] kevent enter selecting from " + 
keys.size());
+            begin();
+            blockedThread = Thread.currentThread();
+            if (blockedThread.isInterrupted())
+              timeout = 0;
+            n = kevent(kq, events, num_events,
+                       events.capacity() / sizeof_struct_kevent, timeout);
+          }
+        finally
+          {
+            end();
+            blockedThread = null;
+            Thread.interrupted();
+            //System.out.println("[" + kq + "kevent exit selected " + n);
+          }
 
-    for (Iterator it = keys.entrySet().iterator(); it.hasNext(); )
-      {
-        Map.Entry e = (Map.Entry) it.next();
-        KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) e.getValue();
+        //System.out.println("dump of keys selected:");
+        //dump_selection_keys((ByteBuffer) events.duplicate().limit(n * 
sizeof_struct_kevent));
         
-        if (key.readEverEnabled)
-          events.put((ByteBuffer) key.nstate.duplicate().limit
-                     (sizeof_struct_kevent));
-        if (key.writeEverEnabled)
-          events.put((ByteBuffer) key.nstate.duplicate().position
-                     (sizeof_struct_kevent).limit(2 * sizeof_struct_kevent));
-      }
-    events.rewind();
-    
-    //System.out.println("dump of keys to select:");
-    //dump_selection_keys(events.duplicate());
-    
-    blockedThread = Thread.currentThread();
-    if (blockedThread.isInterrupted())
-      timeout = 0;
-    final int n = kevent(kq, events, events_size / sizeof_struct_kevent,
-                         timeout);
-    Thread.interrupted();
-    
-    //System.out.println("dump of keys selected:");
-    //dump_selection_keys((ByteBuffer) events.duplicate().limit(n * 
sizeof_struct_kevent));
+        // Commit the operations we've just added in the call to kevent.
+        for (Iterator it = keys.values().iterator(); it.hasNext(); )
+          {
+            KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
+            key.activeOps = key.interestOps;
+          }
+
+        selected = new HashSet/*<KqueueSelectionKeyImpl>*/(n);
+        int x = 0;
+        for (int i = 0; i < n; i++)
+          {
+            events.position(x).limit(x + sizeof_struct_kevent);
+            x += sizeof_struct_kevent;
+            int y = fetch_key(events.slice());
+            KqueueSelectionKeyImpl key =
+              (KqueueSelectionKeyImpl) keys.get(new Integer(y));
+            
+            if (key == null)
+              {
+                System.out.println("WARNING! no key found for selected key " + 
y);
+                continue;
+              }
+            // Keys that have been cancelled may be returned here; don't
+            // add them to the selected set.
+            if (!key.isValid())
+              continue;
+            key.readyOps = ready_ops(events.slice(), key.interestOps);
+            selected.add(key);
+          }
+        
+        // Finally, remove the cancelled keys.
+        for (Iterator it = cancelled.iterator(); it.hasNext(); )
+          {
+            KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
+            keys.remove(new Integer(key.key));
+            deregister(key);
+            it.remove();
+          }
 
-    selected = new HashSet/*<KqueueSelectionKeyImpl>*/(n);
-    int x = 0;
-    for (int i = 0; i < n; i++)
-      {
-        events.position(x).limit(x + sizeof_struct_kevent);
-        x += sizeof_struct_kevent;
-        int y = fetch_key(events.slice());
-        KqueueSelectionKeyImpl key =
-          (KqueueSelectionKeyImpl) keys.get(new Integer(y));
-        key.readyOps = ready_ops(events.slice(), key.interestOps);
-        selected.add(key);
-      }
-    for (Iterator it = cancelled.iterator(); it.hasNext(); )
-      {
-        KqueueSelectionKeyImpl key = (KqueueSelectionKeyImpl) it.next();
-        keys.remove(new Integer(key.key));
-        it.remove();
-      }
+        reallocateBuffer();
 
-    return selected.size();
+        return selected.size();
+      }
+    }
   }
   
   protected SelectionKey register(AbstractSelectableChannel channel,
@@ -290,36 +337,78 @@
     KqueueSelectionKeyImpl result = new KqueueSelectionKeyImpl(this, channel);
     result.interestOps = interestOps;
     result.attach(attachment);
-    int k = System.identityHashCode(result);
-    while (keys.containsKey(new Integer(k)))
-      k++;
-    result.key = k;
-    keys.put(new Integer(k), result);
-    result.nstate = ByteBuffer.allocateDirect(2 * sizeof_struct_kevent);
-    updateOps(result, native_fd, false);
+    result.fd = native_fd;
+    result.key = System.identityHashCode(result);
+    synchronized (keys)
+    {
+      while (keys.containsKey(new Integer(result.key)))
+        result.key++;
+      keys.put(new Integer(result.key), result);
+      reallocateBuffer();
+    }
     return result;
   }
   
-  synchronized void updateOps(KqueueSelectionKeyImpl key)
+  void setInterestOps(KqueueSelectionKeyImpl key, int ops)
   {
-    updateOps(key, 0, false);
+    synchronized (keys)
+    {
+      key.interestOps = ops;
+    }
   }
   
-  synchronized void updateOps(KqueueSelectionKeyImpl key, int fd, boolean 
delete)
+  /**
+   * Reallocate the events buffer. This is the destination buffer for
+   * events returned by kevent. This method will:
+   * 
+   *   * Grow the buffer if there is insufficent space for all registered
+   *     events.
+   *   * Shrink the buffer if it is more than twice the size needed.
+   *
+   */
+  private void reallocateBuffer()
+  {
+    synchronized (keys)
+    {
+      if (events.capacity() < (2 * sizeof_struct_kevent) * keys.size())
+        {
+          int cap = events.capacity();
+          if (cap >= MAX_DOUBLING_CAPACITY)
+            cap += CAP_INCREMENT;
+          else
+            cap = cap << 1;
+          
+          events = ByteBuffer.allocateDirect(cap);
+        }
+      else if (events.capacity() > 4 * (sizeof_struct_kevent) * keys.size() + 1
+               && events.capacity() > INITIAL_CAPACITY)
+        {
+          int cap = events.capacity();
+          cap = cap >>> 1;
+          events = ByteBuffer.allocateDirect(cap);
+        }
+    }
+  }
+  
+  //synchronized void updateOps(KqueueSelectionKeyImpl key, int interestOps)
+  //{
+  //  updateOps(key, interestOps, 0, false);
+  //}
+  
+  /*void updateOps(KqueueSelectionKeyImpl key, int interestOps,
+                 int activeOps, int fd)
   {
     //System.out.println(">> updating kqueue selection key:");
     //dump_selection_keys(key.nstate.duplicate());
     //System.out.println("<<");
-    kevent_set(key.nstate, fd, key.interestOps, key.key, delete);
+    synchronized (keys)
+    {
+      kevent_set(key.nstate, fd, interestOps, activeOps, key.key);
+    }
     //System.out.println(">> updated kqueue selection key:");
     //dump_selection_keys(key.nstate.duplicate());
     //System.out.println("<<");
-  }
-  
-  synchronized void doCancel(KqueueSelectionKeyImpl key)
-  {
-    cancelled.add(key);
-  }
+  }*/
 
   private void dump_selection_keys(ByteBuffer keys)
   {
@@ -380,8 +469,8 @@
    * @param delete Set to true if this event should be deleted from the
    *  kqueue (if false, this event is added/updated).
    */
-  private static native void kevent_set(ByteBuffer nstate, int fd, int 
interestOps,
-                                        int key, boolean delete);
+  private static native void kevent_set(ByteBuffer nstate, int i, int fd,
+                                        int interestOps, int activeOps, int 
key);
   
   /**
    * Poll for events. The source events are stored in <code>events</code>,
@@ -391,12 +480,13 @@
    *  for events read from the queue.
    * @param nevents The number of events to poll (that is, the number of
    *  events in the <code>events</code> buffer).
+   * @param nout The maximum number of events that may be returned.
    * @param timeout The timeout. A timeout of -1 returns immediately; a timeout
    *  of 0 waits indefinitely.
    * @return The number of events read.
    */
   private static native int kevent(int kq, ByteBuffer events, int nevents,
-                                   long timeout);
+                                   int nout, long timeout);
   
   /**
    * Fetch a polled key from a native state buffer. For each kevent key we
Index: gnu/java/nio/KqueueSelectionKeyImpl.java
===================================================================
RCS file: 
/cvsroot/classpath/classpath/gnu/java/nio/KqueueSelectionKeyImpl.java,v
retrieving revision 1.1
diff -u -r1.1 KqueueSelectionKeyImpl.java
--- gnu/java/nio/KqueueSelectionKeyImpl.java    17 Sep 2006 07:31:41 -0000      
1.1
+++ gnu/java/nio/KqueueSelectionKeyImpl.java    27 Sep 2006 21:03:23 -0000
@@ -44,19 +44,18 @@
 import java.nio.channels.SelectableChannel;
 import java.nio.channels.SelectionKey;
 import java.nio.channels.Selector;
+import java.nio.channels.spi.AbstractSelectionKey;
 
 /**
  * @author Casey Marshall ([EMAIL PROTECTED])
  */
-public class KqueueSelectionKeyImpl extends SelectionKey
+public class KqueueSelectionKeyImpl extends AbstractSelectionKey
 {
   int interestOps;
   int readyOps;
-  ByteBuffer nstate;
-  boolean valid;
+  int activeOps = 0;
   int key;
-  boolean readEverEnabled = false;
-  boolean writeEverEnabled = false;
+  int fd;
 
   /** The selector we were created for. */
   private final KqueueSelectorImpl selector;
@@ -74,17 +73,6 @@
     natChannel = (VMChannelOwner) channel;
     interestOps = 0;
     readyOps = 0;
-    valid = true;
-  }
-
-  /* (non-Javadoc)
-   * @see java.nio.channels.SelectionKey#cancel()
-   */
-  //@Override
-  public void cancel()
-  {
-    selector.doCancel(this);
-    valid = false;
   }
 
   /* (non-Javadoc)
@@ -112,33 +100,15 @@
   public SelectionKey interestOps(int ops)
   {
     if (!isValid())
-      throw new IllegalStateException();
+      throw new IllegalStateException("key is invalid");
     if ((ops & ~channel.validOps()) != 0)
-      throw new IllegalArgumentException();
-    this.interestOps = ops;
-    try
-      {
-        selector.updateOps(this,
-                           natChannel.getVMChannel().getState().getNativeFD(),
-                           false);
-      }
-    catch (IOException ioe)
-      {
-        throw new IllegalStateException("channel is invalid");
-      }
+      throw new IllegalArgumentException("channel does not support all 
operations");
+    
+    selector.setInterestOps(this, ops);
     return this;
   }
 
   /* (non-Javadoc)
-   * @see java.nio.channels.SelectionKey#isValid()
-   */
-  //@Override
-  public boolean isValid()
-  {
-    return valid && selector.isOpen();
-  }
-
-  /* (non-Javadoc)
    * @see java.nio.channels.SelectionKey#readyOps()
    */
   //@Override
@@ -159,8 +129,8 @@
   public String toString()
   {
     if (!isValid())
-      return super.toString() + " [ <<invalid>> ]";
-    return super.toString() + " [ interest ops: {"
+      return super.toString() + " [ fd: " + fd + " <<invalid>> ]";
+    return super.toString() + " [ fd: " + fd + " interest ops: {"
       + ((interestOps & OP_ACCEPT) != 0 ? " OP_ACCEPT" : "")
       + ((interestOps & OP_CONNECT) != 0 ? " OP_CONNECT" : "")
       + ((interestOps & OP_READ) != 0 ? " OP_READ" : "")
@@ -172,4 +142,48 @@
       + ((readyOps & OP_WRITE) != 0 ? " OP_WRITE" : "")
       + " } ]";
   }
+  
+  public int hashCode()
+  {
+    return fd;
+  }
+  
+  public boolean equals(Object o)
+  {
+    if (!(o instanceof KqueueSelectionKeyImpl))
+      return false;
+    KqueueSelectionKeyImpl that = (KqueueSelectionKeyImpl) o;
+    return that.fd == this.fd && that.channel.equals(this.channel);
+  }
+  
+  
+  boolean isReadActive()
+  {
+    return (activeOps & (OP_READ | OP_ACCEPT)) != 0;
+  }
+
+  boolean isReadInterested()
+  {
+    return (interestOps & (OP_READ | OP_ACCEPT)) != 0;
+  }
+  
+  boolean isWriteActive()
+  {
+    return (activeOps & (OP_WRITE | OP_CONNECT)) != 0;
+  }
+  
+  boolean isWriteInterested()
+  {
+    return (interestOps & (OP_WRITE | OP_CONNECT)) != 0;
+  }
+  
+  boolean needCommitRead()
+  {
+    return isReadActive() == (!isReadInterested());
+  }
+
+  boolean needCommitWrite()
+  {
+    return isWriteActive() == (!isWriteInterested());
+  }
 }
Index: include/gnu_java_nio_KqueueSelectorImpl.h
===================================================================
RCS file: 
/cvsroot/classpath/classpath/include/gnu_java_nio_KqueueSelectorImpl.h,v
retrieving revision 1.1
diff -u -r1.1 gnu_java_nio_KqueueSelectorImpl.h
--- include/gnu_java_nio_KqueueSelectorImpl.h   17 Sep 2006 07:31:42 -0000      
1.1
+++ include/gnu_java_nio_KqueueSelectorImpl.h   27 Sep 2006 21:03:23 -0000
@@ -7,6 +7,18 @@
 #ifdef __cplusplus
 extern "C" {
 #endif
+#undef gnu_java_nio_KqueueSelectorImpl_MAX_DOUBLING_CAPACITY
+#define gnu_java_nio_KqueueSelectorImpl_MAX_DOUBLING_CAPACITY 16384L
+#undef gnu_java_nio_KqueueSelectorImpl_CAP_INCREMENT
+#define gnu_java_nio_KqueueSelectorImpl_CAP_INCREMENT 1024L
+#undef gnu_java_nio_KqueueSelectorImpl_OP_ACCEPT
+#define gnu_java_nio_KqueueSelectorImpl_OP_ACCEPT 16L
+#undef gnu_java_nio_KqueueSelectorImpl_OP_CONNECT
+#define gnu_java_nio_KqueueSelectorImpl_OP_CONNECT 8L
+#undef gnu_java_nio_KqueueSelectorImpl_OP_READ
+#define gnu_java_nio_KqueueSelectorImpl_OP_READ 1L
+#undef gnu_java_nio_KqueueSelectorImpl_OP_WRITE
+#define gnu_java_nio_KqueueSelectorImpl_OP_WRITE 4L
 /*
  * Class:     gnu_java_nio_KqueueSelectorImpl
  * Method:    kqueue_supported
@@ -42,18 +54,18 @@
 /*
  * Class:     gnu_java_nio_KqueueSelectorImpl
  * Method:    kevent_set
- * Signature: (Ljava/nio/ByteBuffer;IIIZ)V
+ * Signature: (Ljava/nio/ByteBuffer;IIIII)V
  */
 JNIEXPORT void JNICALL Java_gnu_java_nio_KqueueSelectorImpl_kevent_1set
-  (JNIEnv *, jclass, jobject, jint, jint, jint, jboolean);
+  (JNIEnv *, jclass, jobject, jint, jint, jint, jint, jint);
 
 /*
  * Class:     gnu_java_nio_KqueueSelectorImpl
  * Method:    kevent
- * Signature: (ILjava/nio/ByteBuffer;IJ)I
+ * Signature: (ILjava/nio/ByteBuffer;IIJ)I
  */
 JNIEXPORT jint JNICALL Java_gnu_java_nio_KqueueSelectorImpl_kevent
-  (JNIEnv *, jclass, jint, jobject, jint, jlong);
+  (JNIEnv *, jclass, jint, jobject, jint, jint, jlong);
 
 /*
  * Class:     gnu_java_nio_KqueueSelectorImpl

Reply via email to