On OS X, the test does not behave the same way: the session is created and the byte written, but the server does not have any managed session so the last assertion fails. To make this test fail as expected, I need to add the following calls to AbstractPollingIoAcceptor#unbind0
startupAcceptor(); wakeup(); I may have an explanation. In the unregisterHandles() method, the handle is closed and then there is a call to wakeup(). However, when the last bound socket is unregistered, the Acceptor#run() method will simply exit just after the call to unregisterHandles() because nHandles == 0. So I think the call to wakeup() has no effect at all, because the acceptor is not running anymore, thus no select() call is performed. I've also tried the following patch: Index: core/src/main/java/org/apache/mina/core/polling/AbstractPollingIoAcceptor.java =================================================================== --- core/src/main/java/org/apache/mina/core/polling/AbstractPollingIoAcceptor.java (revision 747700) +++ core/src/main/java/org/apache/mina/core/polling/AbstractPollingIoAcceptor.java (working copy) @@ -406,6 +406,7 @@ } // check to see if any cancellation request has been made. + int nbPreviousHandles = nHandles; nHandles -= unregisterHandles(); // Now, if the number of registred handles is 0, we can @@ -415,6 +416,9 @@ synchronized (lock) { if (registerQueue.isEmpty() && cancelQueue.isEmpty()) { + if (nbPreviousHandles > 0) { + select(); + } acceptor = null; break; } But I don't think it's very clean either. Note that the problem also happen with datagram sockets and none of the above solution seems to work in that case. 2009/2/25 Emmanuel Lecharny <elecha...@apache.org>: > Guillaume Nodet wrote: >> >> I've just spotted that the acceptor is not correctly disposed. >> I've managed to get the test running succesfully by adding the >> following code just after server.suspend() >> >> for (Listener listener : >> server.getServerContext().getListeners().values()) { >> if (listener instanceof NioListener) { >> Field field = >> listener.getClass().getDeclaredField("acceptor"); >> field.setAccessible(true); >> NioSocketAcceptor acceptor = (NioSocketAcceptor) >> field.get(listener); >> Method method = >> AbstractPollingIoAcceptor.class.getDeclaredMethod("dispose0"); >> method.setAccessible(true); >> method.invoke(acceptor); >> } >> } >> >> Which is about callling the dispose0() method of the NioSocketAcceptor. >> This method looks like: >> >> protected IoFuture dispose0() throws Exception { >> unbind(); >> if (!disposalFuture.isDone()) { >> startupAcceptor(); >> wakeup(); >> } >> return disposalFuture; >> } >> >> So I guess what we're missing is a call to: >> startupAcceptor(); >> wakeup(); >> somewhere. >> I'm not too familiar with mina internals, so I'm not sure where this >> methods should be called or if it makes any sense to call those after >> an unbind. >> > > The problem is that when you do an acceptor.unbind(), here is what MINA does : > > acceptor.unbind() --> > unbind(getLocalAddresses()) --> > unbind0(localAddressesCopy) with > > protected final void unbind0(List<? extends SocketAddress> localAddresses) > throws Exception { > AcceptorOperationFuture future = new AcceptorOperationFuture( > localAddresses); > > cancelQueue.add(future); > startupAcceptor(); > wakeup(); > ... > > There is obviously something wrong somewhere, if you consider the following > test : > org.apache.mina.transport.AbstractBindTest > > public void testUnbindDisconnectsClients() throws Exception { > bind(true); > IoConnector connector = newConnector(); > IoSession[] sessions = new IoSession[5]; > connector.setHandler(new IoHandlerAdapter()); > > // Create 5 sessions, and write when established > for (int i = 0; i < sessions.length; i++) { > ConnectFuture future = connector.connect(createSocketAddress(port)); > future.awaitUninterruptibly(); > sessions[i] = future.getSession(); > Assert.assertTrue(sessions[i].isConnected()); > > Assert.assertTrue(sessions[i].write(IoBuffer.allocate(1)).awaitUninterruptibly().isWritten()); > } > > // Wait for the server side sessions to be created. > Thread.sleep(500); > > Collection<IoSession> managedSessions = > acceptor.getManagedSessions().values(); > Assert.assertEquals(5, managedSessions.size()); > > // Now unbind > acceptor.unbind(); > > // Wait for the accessor to unbind > Thread.sleep(500); > > // The session must have been closed > Assert.assertEquals(0, managedSessions.size()); > for (IoSession element : managedSessions) { > Assert.assertFalse(element.isConnected()); > } > > // And now, try to create a session on a unbound acceptor !!! > ConnectFuture future = connector.connect(createSocketAddress(port)); > future.awaitUninterruptibly(); > IoSession session = future.getSession(); > Assert.assertTrue(session.isConnected()); > > Assert.assertTrue(session.write(IoBuffer.allocate(1)).awaitUninterruptibly().isWritten()); > > // Wait for the server side sessions to be created. > Thread.sleep(500); > > managedSessions = acceptor.getManagedSessions().values(); > Assert.assertEquals(1, managedSessions.size()); > } > > > On Linux, this tests passes, all lights green ! > > -- > -- > cordialement, regards, > Emmanuel Lécharny > www.iktek.com > directory.apache.org > > > -- Cheers, Guillaume Nodet ------------------------ Blog: http://gnodet.blogspot.com/ ------------------------ Open Source SOA http://fusesource.com