CancelledKeyException during channel registration

Alan Bateman Alan.Bateman at oracle.com
Tue May 31 15:00:21 UTC 2022


Moving to the nio-dev list.

Registration is not an atomic operation. The channel is registered (this 
creates the selection key) and then the key's interest set is changed. 
If I read your test case correctly, it is cancelling the key before the 
key's interest set is changed and this leads to the CancelledKeyException.

Yes, I agree this may be surprising. Can you submit a bug for this?

-Alan

On 31/05/2022 11:38, Gillespie, Oli wrote:
> Hi,
>
> I noticed this surprising (to me) behaviour, and wonder whether it's 
> expected or could be considered a bug. I'm not an expert in this area 
> so apologies if this is trivial.
>
> When registering a SocketChannel with a Selector for the first time, 
> it's possible to get a CancelledKeyException even though this is the 
> first register call.
>
> Exception in thread "main" java.nio.channels.CancelledKeyException
>     at 
> java.base/sun.nio.ch.SelectionKeyImpl.ensureValid(SelectionKeyImpl.java:75)
>     at 
> java.base/sun.nio.ch.SelectionKeyImpl.interestOps(SelectionKeyImpl.java:104)
>     at java.base/sun.nio.ch.SelectorImpl.register(SelectorImpl.java:222)
>     at 
> java.base/java.nio.channels.spi.AbstractSelectableChannel.register(AbstractSelectableChannel.java:236)
>     at 
> java.base/java.nio.channels.SelectableChannel.register(SelectableChannel.java:260)
>     at KeyCancelled.main(KeyCancelled.java:20)
>
> The javadoc states:
>
> @throws  CancelledKeyException
>     If this channel is currently registered with the given selector
>       but the corresponding key has already been cancelled
>
> However in this case the channel is _not_ registered, as shown by 
> SocketChannel.isRegistered() returning false.
>
> This following sequence triggers this issue:
>
> 1. Thread 1 starts SelectableChannel.register
> 2. A new SelectionKey becomes visible via Selector.keys()
> 3. Thread 2 iterates Selector.keys() and calls SelectorKey.cancel()
> 4. Thread 1 (still in the register() invocation) finds that the key is 
> cancelled and throws CancelledKeyException
>
> Below is a small reproducer which usually exhibits this issue:
>
> import java.nio.channels.SelectionKey;
> import java.nio.channels.Selector;
> import java.nio.channels.SocketChannel;
>
> public class KeyCancelled {
>     public static void main(String[] args) throws Exception {
>         Selector s = Selector.open();
>
>         new Thread(() -> {
>             for (int i = 0; i < 100_000; i++) {
>                 s.keys().forEach(SelectionKey::cancel);
>             }
>         }).start();
>
>         for (int i = 0; i < 10_000; i++) {
>             SocketChannel c = s.provider().openSocketChannel();
>             c.configureBlocking(false);
>             // Sometimes this throws CancelledKeyException, because 
> the key is cancelled by
>             // the other thread part-way through the register call.
>             c.register(s, SelectionKey.OP_READ);
>             // c.isRegistered() is false here after the exceptional case
>         }
>     }
> }
>
> So, is this expected, a bug, or a gap in documentation?
>
> Many thanks,
>
> Oli
>
>
>
> Amazon Development Centre (London) Ltd. Registered in England and 
> Wales with registration number 04543232 with its registered office at 
> 1 Principal Place, Worship Street, London EC2A 2FA, United Kingdom.
>
>



More information about the nio-dev mailing list