1adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/* Licensed to the Apache Software Foundation (ASF) under one or more
2adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * contributor license agreements.  See the NOTICE file distributed with
3adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * this work for additional information regarding copyright ownership.
4adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * The ASF licenses this file to You under the Apache License, Version 2.0
5adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * (the "License"); you may not use this file except in compliance with
6adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * the License.  You may obtain a copy of the License at
7eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson *
8adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
9eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson *
10adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * See the License for the specific language governing permissions and
14adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * limitations under the License.
15adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
16ae704b984c10a63883cc366e823d53902d6ac7a9Elliott Hughespackage java.nio;
17adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
185d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.ErrnoException;
195d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport android.system.StructPollfd;
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileDescriptor;
21f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fullerimport java.io.InterruptedIOException;
225d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport java.io.IOException;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.ClosedSelectorException;
24adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.IllegalSelectorException;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.SelectionKey;
26adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.Selector;
27adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.spi.AbstractSelectableChannel;
28adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.spi.AbstractSelectionKey;
29adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.spi.AbstractSelector;
30adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.spi.SelectorProvider;
31adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Collection;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Collections;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashSet;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Iterator;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Set;
3670c820401677ca251ad09ac64cc23c760764e75dElliott Hughesimport java.util.UnsafeArrayList;
370b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport libcore.io.IoBridge;
3810959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilsonimport libcore.io.IoUtils;
3941f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughesimport libcore.io.Libcore;
40f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller
415d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport static android.system.OsConstants.EINTR;
428806710d7a5cd6a168f2463de21498c58f70948aPrzemyslaw Jakwertimport static android.system.OsConstants.POLLERR;
435d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport static android.system.OsConstants.POLLHUP;
445d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport static android.system.OsConstants.POLLIN;
455d930cadc8f62aee5f18e7921296fe66a54f18abElliott Hughesimport static android.system.OsConstants.POLLOUT;
46f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fullerimport static java.nio.channels.SelectionKey.OP_ACCEPT;
47f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fullerimport static java.nio.channels.SelectionKey.OP_CONNECT;
48f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fullerimport static java.nio.channels.SelectionKey.OP_READ;
49f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fullerimport static java.nio.channels.SelectionKey.OP_WRITE;
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
51adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
52adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Default implementation of java.nio.channels.Selector
53adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
54adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectfinal class SelectorImpl extends AbstractSelector {
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
56eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    /**
57eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * Used to synchronize when a key's interest ops change.
58eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     */
595e23b687ef8b3c696d54d1880b454942875665b7Elliott Hughes    final Object keysLock = new Object();
60adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
61eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private final Set<SelectionKeyImpl> mutableKeys = new HashSet<SelectionKeyImpl>();
62adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
63eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    /**
64eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * The unmodifiable set of keys as exposed to the user. This object is used
65eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * for synchronization.
66eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     */
676b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    private final Set<SelectionKey> unmodifiableKeys = Collections
68eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            .<SelectionKey>unmodifiableSet(mutableKeys);
69adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
70eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private final Set<SelectionKey> mutableSelectedKeys = new HashSet<SelectionKey>();
71adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
72eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    /**
73eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * The unmodifiable set of selectable keys as seen by the user. This object
74eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * is used for synchronization.
75eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     */
76eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private final Set<SelectionKey> selectedKeys
77eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            = new UnaddableSet<SelectionKey>(mutableSelectedKeys);
78eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
79eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    /**
8010959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson     * The wakeup pipe. To trigger a wakeup, write a byte to wakeupOut. Each
8110959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson     * time select returns, wakeupIn is drained.
8260a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes     */
8310959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson    private final FileDescriptor wakeupIn;
8410959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson    private final FileDescriptor wakeupOut;
8560a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes
8670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    private final UnsafeArrayList<StructPollfd> pollFds = new UnsafeArrayList<StructPollfd>(StructPollfd.class, 8);
87adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
886b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    public SelectorImpl(SelectorProvider selectorProvider) throws IOException {
89adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(selectorProvider);
9010959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson
9110959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson        /*
92ed3322f25d79b6607fc314d75f96d46b7c783f43Elliott Hughes         * Create a pipe to trigger wakeup. We can't use a NIO pipe because it
9310959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson         * would be closed if the selecting thread is interrupted. Also
9410959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson         * configure the pipe so we can fully drain it without blocking.
9510959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson         */
9641f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        try {
9741f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            FileDescriptor[] pipeFds = Libcore.os.pipe();
9841f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            wakeupIn = pipeFds[0];
9941f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            wakeupOut = pipeFds[1];
10041f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            IoUtils.setBlocking(wakeupIn, false);
10170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            pollFds.add(new StructPollfd());
10270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            setPollFd(0, wakeupIn, POLLIN, null);
10341f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        } catch (ErrnoException errnoException) {
10441f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            throw errnoException.rethrowAsIOException();
10541f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        }
106adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
107adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1086b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override protected void implCloseSelector() throws IOException {
109adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        wakeup();
110eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        synchronized (this) {
111eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            synchronized (unmodifiableKeys) {
112eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                synchronized (selectedKeys) {
11310959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson                    IoUtils.close(wakeupIn);
11410959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson                    IoUtils.close(wakeupOut);
115eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    doCancel();
116eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    for (SelectionKey sk : mutableKeys) {
117eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                        deregister((AbstractSelectionKey) sk);
118eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    }
119eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                }
120eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            }
121eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        }
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1246b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override protected SelectionKey register(AbstractSelectableChannel channel,
125adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int operations, Object attachment) {
126adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!provider().equals(channel.provider())) {
127adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalSelectorException();
128adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
129adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
130eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            synchronized (unmodifiableKeys) {
13170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                SelectionKeyImpl selectionKey = new SelectionKeyImpl(channel, operations,
13270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                        attachment, this);
133eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                mutableKeys.add(selectionKey);
13470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                ensurePollFdsCapacity();
135eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                return selectionKey;
136adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1406b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override public synchronized Set<SelectionKey> keys() {
14110959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson        checkClosed();
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return unmodifiableKeys;
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
14510959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson    private void checkClosed() {
146adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!isOpen()) {
147adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ClosedSelectorException();
148adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1516b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override public int select() throws IOException {
15270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        // Blocks until some fd is ready.
15370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        return selectInternal(-1);
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
155adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1566b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override public int select(long timeout) throws IOException {
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (timeout < 0) {
158126ab1b546c71137a97cef68cc89267e7f7be634Elliott Hughes            throw new IllegalArgumentException("timeout < 0: " + timeout);
159adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
16070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        // Our timeout is interpreted differently to Unix's --- 0 means block. See selectNow.
16170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        return selectInternal((timeout == 0) ? -1 : timeout);
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1646b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override public int selectNow() throws IOException {
16570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        return selectInternal(0);
166adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int selectInternal(long timeout) throws IOException {
16910959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson        checkClosed();
170adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
171eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            synchronized (unmodifiableKeys) {
172adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                synchronized (selectedKeys) {
173adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    doCancel();
174318d6de23bec3024a85eb211f5843d925774622aElliott Hughes                    boolean isBlocking = (timeout != 0);
175eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    synchronized (keysLock) {
17670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                        preparePollFds();
177eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    }
178f7bd2a99f6f4024e9034300b30a13a2ea871aa97Elliott Hughes                    int rc = -1;
179adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    try {
180318d6de23bec3024a85eb211f5843d925774622aElliott Hughes                        if (isBlocking) {
181adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            begin();
182adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
1839b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes                        try {
1849b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes                            rc = Libcore.os.poll(pollFds.array(), (int) timeout);
1859b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes                        } catch (ErrnoException errnoException) {
186f7bd2a99f6f4024e9034300b30a13a2ea871aa97Elliott Hughes                            if (errnoException.errno != EINTR) {
187f7bd2a99f6f4024e9034300b30a13a2ea871aa97Elliott Hughes                                throw errnoException.rethrowAsIOException();
188f7bd2a99f6f4024e9034300b30a13a2ea871aa97Elliott Hughes                            }
1899b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes                        }
190adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } finally {
191318d6de23bec3024a85eb211f5843d925774622aElliott Hughes                        if (isBlocking) {
192adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            end();
193adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
195eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
19670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    int readyCount = (rc > 0) ? processPollFds() : 0;
19770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    readyCount -= doCancel();
19870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    return readyCount;
199adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
200adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
201adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
202adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
203adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    private void setPollFd(int i, FileDescriptor fd, int events, Object object) {
20570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        StructPollfd pollFd = pollFds.get(i);
20670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        pollFd.fd = fd;
20770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        pollFd.events = (short) events;
20870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        pollFd.userData = object;
20970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    }
210adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
21170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    private void preparePollFds() {
21270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        int i = 1; // Our wakeup pipe comes before all the user's fds.
213eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        for (SelectionKeyImpl key : mutableKeys) {
214eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            int interestOps = key.interestOpsNoCheck();
21570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            short eventMask = 0;
216a7bb29434692e01aed843b88cd042628bab74a23Elliott Hughes            if (((OP_ACCEPT | OP_READ) & interestOps) != 0) {
21770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                eventMask |= POLLIN;
218eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            }
219a7bb29434692e01aed843b88cd042628bab74a23Elliott Hughes            if (((OP_CONNECT | OP_WRITE) & interestOps) != 0) {
22070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                eventMask |= POLLOUT;
22170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            }
22270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            if (eventMask != 0) {
22370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                setPollFd(i++, ((FileDescriptorChannel) key.channel()).getFD(), eventMask, key);
224adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
225adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
226adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
227adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
22870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    private void ensurePollFdsCapacity() {
22970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        // We need one slot for each element of mutableKeys, plus one for the wakeup pipe.
23070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        while (pollFds.size() < mutableKeys.size() + 1) {
23170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            pollFds.add(new StructPollfd());
23270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        }
23370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    }
23470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
235eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    /**
23670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes     * Updates the key ready ops and selected key set.
237eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     */
23870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    private int processPollFds() throws IOException {
23970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        if (pollFds.get(0).revents == POLLIN) {
24026c7025a7a919044771fb89031161bd26fe03032Elliott Hughes            // Read bytes from the wakeup pipe until the pipe is empty.
24110959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson            byte[] buffer = new byte[8];
2420b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            while (IoBridge.read(wakeupIn, buffer, 0, 1) > 0) {
243adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
244adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
245eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
24670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        int readyKeyCount = 0;
24770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        for (int i = 1; i < pollFds.size(); ++i) {
24870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            StructPollfd pollFd = pollFds.get(i);
24970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            if (pollFd.revents == 0) {
250adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                continue;
251adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
25270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            if (pollFd.fd == null) {
25370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                break;
25470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            }
25570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
25670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            SelectionKeyImpl key = (SelectionKeyImpl) pollFd.userData;
25770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
25870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            pollFd.fd = null;
25970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            pollFd.userData = null;
260eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
261eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            int ops = key.interestOpsNoCheck();
26257656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes            int selectedOps = 0;
2638806710d7a5cd6a168f2463de21498c58f70948aPrzemyslaw Jakwert            if ((pollFd.revents & POLLHUP) != 0 || (pollFd.revents & POLLERR) != 0) {
264ed3322f25d79b6607fc314d75f96d46b7c783f43Elliott Hughes                // If there was an error condition, we definitely want to wake listeners,
265ed3322f25d79b6607fc314d75f96d46b7c783f43Elliott Hughes                // regardless of what they're waiting for. Failure is always interesting.
266ed3322f25d79b6607fc314d75f96d46b7c783f43Elliott Hughes                selectedOps |= ops;
267ed3322f25d79b6607fc314d75f96d46b7c783f43Elliott Hughes            }
26870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            if ((pollFd.revents & POLLIN) != 0) {
26957656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes                selectedOps |= ops & (OP_ACCEPT | OP_READ);
27057656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes            }
27157656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes            if ((pollFd.revents & POLLOUT) != 0) {
27270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                if (key.isConnected()) {
27357656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes                    selectedOps |= ops & OP_WRITE;
27470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                } else {
27557656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes                    selectedOps |= ops & OP_CONNECT;
27670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                }
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
27957656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes            if (selectedOps != 0) {
280eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                boolean wasSelected = mutableSelectedKeys.contains(key);
28157656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes                if (wasSelected && key.readyOps() != selectedOps) {
28257656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes                    key.setReadyOps(key.readyOps() | selectedOps);
28370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    ++readyKeyCount;
284eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                } else if (!wasSelected) {
28557656d21f772aacbe0d05e54b1274f4c58993a52Elliott Hughes                    key.setReadyOps(selectedOps);
286eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    mutableSelectedKeys.add(key);
28770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    ++readyKeyCount;
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
289adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
290adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
291eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
29270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        return readyKeyCount;
293adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
294adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2956b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override public synchronized Set<SelectionKey> selectedKeys() {
29610959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson        checkClosed();
297eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        return selectedKeys;
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
300eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    /**
301eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * Removes cancelled keys from the key set and selected key set, and
302ed3322f25d79b6607fc314d75f96d46b7c783f43Elliott Hughes     * unregisters the corresponding channels. Returns the number of keys
303eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * removed from the selected key set.
304eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     */
305eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private int doCancel() {
306eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        int deselected = 0;
307eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Set<SelectionKey> cancelledKeys = cancelledKeys();
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (cancelledKeys) {
310adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (cancelledKeys.size() > 0) {
31160a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes                for (SelectionKey currentKey : cancelledKeys) {
31260a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes                    mutableKeys.remove(currentKey);
31360a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes                    deregister((AbstractSelectionKey) currentKey);
31460a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes                    if (mutableSelectedKeys.remove(currentKey)) {
315eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                        deselected++;
316eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    }
317adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
318eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                cancelledKeys.clear();
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
321eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
322eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        return deselected;
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
324adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3256b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override public Selector wakeup() {
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
32778c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes            Libcore.os.write(wakeupOut, new byte[] { 1 }, 0, 1);
32878c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes        } catch (ErrnoException ignored) {
329f0d40d662d9dfdb04215c718961765837d2cf00cNeil Fuller        } catch (InterruptedIOException ignored) {
330adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this;
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static class UnaddableSet<E> implements Set<E> {
335adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
336eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        private final Set<E> set;
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        UnaddableSet(Set<E> set) {
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.set = set;
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
342eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        @Override
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean equals(Object object) {
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.equals(object);
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
347eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        @Override
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int hashCode() {
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.hashCode();
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean add(E object) {
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new UnsupportedOperationException();
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean addAll(Collection<? extends E> c) {
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new UnsupportedOperationException();
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public void clear() {
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            set.clear();
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean contains(Object object) {
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.contains(object);
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean containsAll(Collection<?> c) {
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.containsAll(c);
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean isEmpty() {
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.isEmpty();
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public Iterator<E> iterator() {
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.iterator();
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean remove(Object object) {
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.remove(object);
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean removeAll(Collection<?> c) {
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.removeAll(c);
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean retainAll(Collection<?> c) {
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.retainAll(c);
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int size() {
393adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.size();
394adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
395adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
396adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public Object[] toArray() {
397adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.toArray();
398adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
399adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
400adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public <T> T[] toArray(T[] a) {
401adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.toArray(a);
402adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
403adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
404adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
405