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
18adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.FileDescriptor;
19adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.io.IOException;
20adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.ClosedSelectorException;
21adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.IllegalSelectorException;
227365de1056414750d0a7d1fdd26025fd247f0d04Jesse Wilsonimport java.nio.channels.SelectableChannel;
23adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.SelectionKey;
24eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilsonimport static java.nio.channels.SelectionKey.*;
25adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.nio.channels.Selector;
26b960e1a9d80af9536f77172cbe3932c3afc7e7e4Marc Petit-Hugueninimport java.nio.channels.SocketChannel;
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;
31eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilsonimport java.util.Arrays;
32adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Collection;
33adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Collections;
34adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.HashSet;
35adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Iterator;
36adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectimport java.util.Set;
3770c820401677ca251ad09ac64cc23c760764e75dElliott Hughesimport java.util.UnsafeArrayList;
3841f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughesimport libcore.io.ErrnoException;
390b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughesimport libcore.io.IoBridge;
4010959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilsonimport libcore.io.IoUtils;
4141f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughesimport libcore.io.Libcore;
4270c820401677ca251ad09ac64cc23c760764e75dElliott Hughesimport libcore.io.StructPollfd;
436186821cb13f4ac7ff50950c813394367e021eaeJesse Wilsonimport libcore.util.EmptyArray;
4470c820401677ca251ad09ac64cc23c760764e75dElliott Hughesimport static libcore.io.OsConstants.*;
45adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
46adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project/*
47adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project * Default implementation of java.nio.channels.Selector
48adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project */
49adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Projectfinal class SelectorImpl extends AbstractSelector {
50adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
51eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    /**
52eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * Used to synchronize when a key's interest ops change.
53eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     */
545e23b687ef8b3c696d54d1880b454942875665b7Elliott Hughes    final Object keysLock = new Object();
55adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
56eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private final Set<SelectionKeyImpl> mutableKeys = new HashSet<SelectionKeyImpl>();
57adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
58eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    /**
59eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * The unmodifiable set of keys as exposed to the user. This object is used
60eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * for synchronization.
61eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     */
626b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    private final Set<SelectionKey> unmodifiableKeys = Collections
63eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            .<SelectionKey>unmodifiableSet(mutableKeys);
64adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
65eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private final Set<SelectionKey> mutableSelectedKeys = new HashSet<SelectionKey>();
66adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
67eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    /**
68eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * The unmodifiable set of selectable keys as seen by the user. This object
69eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * is used for synchronization.
70eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     */
71eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private final Set<SelectionKey> selectedKeys
72eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            = new UnaddableSet<SelectionKey>(mutableSelectedKeys);
73eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
74eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    /**
7510959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson     * The wakeup pipe. To trigger a wakeup, write a byte to wakeupOut. Each
7610959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson     * time select returns, wakeupIn is drained.
7760a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes     */
7810959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson    private final FileDescriptor wakeupIn;
7910959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson    private final FileDescriptor wakeupOut;
8060a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes
8170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    private final UnsafeArrayList<StructPollfd> pollFds = new UnsafeArrayList<StructPollfd>(StructPollfd.class, 8);
82adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
836b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    public SelectorImpl(SelectorProvider selectorProvider) throws IOException {
84adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        super(selectorProvider);
8510959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson
8610959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson        /*
8710959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson         * Create a pipes to trigger wakeup. We can't use a NIO pipe because it
8810959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson         * would be closed if the selecting thread is interrupted. Also
8910959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson         * configure the pipe so we can fully drain it without blocking.
9010959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson         */
9141f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        try {
9241f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            FileDescriptor[] pipeFds = Libcore.os.pipe();
9341f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            wakeupIn = pipeFds[0];
9441f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            wakeupOut = pipeFds[1];
9541f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            IoUtils.setBlocking(wakeupIn, false);
9670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            pollFds.add(new StructPollfd());
9770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            setPollFd(0, wakeupIn, POLLIN, null);
9841f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        } catch (ErrnoException errnoException) {
9941f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes            throw errnoException.rethrowAsIOException();
10041f0605d2c809bd9bc1c0fb68d86b49a0f59b6c5Elliott Hughes        }
101adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
102adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1036b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override protected void implCloseSelector() throws IOException {
104adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        wakeup();
105eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        synchronized (this) {
106eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            synchronized (unmodifiableKeys) {
107eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                synchronized (selectedKeys) {
10810959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson                    IoUtils.close(wakeupIn);
10910959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson                    IoUtils.close(wakeupOut);
110eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    doCancel();
111eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    for (SelectionKey sk : mutableKeys) {
112eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                        deregister((AbstractSelectionKey) sk);
113eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    }
114eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                }
115eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            }
116eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        }
117adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
118adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1196b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override protected SelectionKey register(AbstractSelectableChannel channel,
120adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int operations, Object attachment) {
121adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!provider().equals(channel.provider())) {
122adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new IllegalSelectorException();
123adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
124adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
125eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            synchronized (unmodifiableKeys) {
12670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                SelectionKeyImpl selectionKey = new SelectionKeyImpl(channel, operations,
12770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                        attachment, this);
128eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                mutableKeys.add(selectionKey);
12970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                ensurePollFdsCapacity();
130eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                return selectionKey;
131adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
132adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
133adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
134adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1356b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override public synchronized Set<SelectionKey> keys() {
13610959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson        checkClosed();
137adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return unmodifiableKeys;
138adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
139adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
14010959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson    private void checkClosed() {
141adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (!isOpen()) {
142adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new ClosedSelectorException();
143adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
144adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
145adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1466b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override public int select() throws IOException {
14770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        // Blocks until some fd is ready.
14870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        return selectInternal(-1);
149adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
150adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1516b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override public int select(long timeout) throws IOException {
152adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        if (timeout < 0) {
153126ab1b546c71137a97cef68cc89267e7f7be634Elliott Hughes            throw new IllegalArgumentException("timeout < 0: " + timeout);
154adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
15570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        // Our timeout is interpreted differently to Unix's --- 0 means block. See selectNow.
15670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        return selectInternal((timeout == 0) ? -1 : timeout);
157adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
158adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
1596b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override public int selectNow() throws IOException {
16070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        return selectInternal(0);
161adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
162adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
163adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private int selectInternal(long timeout) throws IOException {
16410959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson        checkClosed();
165adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (this) {
166eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            synchronized (unmodifiableKeys) {
167adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                synchronized (selectedKeys) {
168adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    doCancel();
16970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    boolean isBlock = (timeout != 0);
170eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    synchronized (keysLock) {
17170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                        preparePollFds();
172eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    }
173f7bd2a99f6f4024e9034300b30a13a2ea871aa97Elliott Hughes                    int rc = -1;
174adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    try {
175adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (isBlock) {
176adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            begin();
177adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
1789b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes                        try {
1799b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes                            rc = Libcore.os.poll(pollFds.array(), (int) timeout);
1809b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes                        } catch (ErrnoException errnoException) {
181f7bd2a99f6f4024e9034300b30a13a2ea871aa97Elliott Hughes                            if (errnoException.errno != EINTR) {
182f7bd2a99f6f4024e9034300b30a13a2ea871aa97Elliott Hughes                                throw errnoException.rethrowAsIOException();
183f7bd2a99f6f4024e9034300b30a13a2ea871aa97Elliott Hughes                            }
1849b510df35b57946d843ffc34cf23fdcfc84c5220Elliott Hughes                        }
185adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    } finally {
186adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        if (isBlock) {
187adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                            end();
188adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                        }
189adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    }
190eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
19170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    int readyCount = (rc > 0) ? processPollFds() : 0;
19270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    readyCount -= doCancel();
19370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    return readyCount;
194adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
195adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
196adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
197adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
198adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
19970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    private void setPollFd(int i, FileDescriptor fd, int events, Object object) {
20070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        StructPollfd pollFd = pollFds.get(i);
20170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        pollFd.fd = fd;
20270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        pollFd.events = (short) events;
20370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        pollFd.userData = object;
20470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    }
205adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
20670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    private void preparePollFds() {
20770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        int i = 1; // Our wakeup pipe comes before all the user's fds.
208eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        for (SelectionKeyImpl key : mutableKeys) {
209eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            int interestOps = key.interestOpsNoCheck();
21070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            short eventMask = 0;
211a7bb29434692e01aed843b88cd042628bab74a23Elliott Hughes            if (((OP_ACCEPT | OP_READ) & interestOps) != 0) {
21270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                eventMask |= POLLIN;
213eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            }
214a7bb29434692e01aed843b88cd042628bab74a23Elliott Hughes            if (((OP_CONNECT | OP_WRITE) & interestOps) != 0) {
21570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                eventMask |= POLLOUT;
21670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            }
21770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            if (eventMask != 0) {
21870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                setPollFd(i++, ((FileDescriptorChannel) key.channel()).getFD(), eventMask, key);
219adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
220adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
221adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
222adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
22370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    private void ensurePollFdsCapacity() {
22470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        // We need one slot for each element of mutableKeys, plus one for the wakeup pipe.
22570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        while (pollFds.size() < mutableKeys.size() + 1) {
22670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            pollFds.add(new StructPollfd());
22770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        }
22870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    }
22970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
230eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    /**
23170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes     * Updates the key ready ops and selected key set.
232eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     */
23370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes    private int processPollFds() throws IOException {
23470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        if (pollFds.get(0).revents == POLLIN) {
23526c7025a7a919044771fb89031161bd26fe03032Elliott Hughes            // Read bytes from the wakeup pipe until the pipe is empty.
23610959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson            byte[] buffer = new byte[8];
2370b736ebc4efef64f2db1999aea90297ad8196146Elliott Hughes            while (IoBridge.read(wakeupIn, buffer, 0, 1) > 0) {
238adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
239adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
240eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
24170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        int readyKeyCount = 0;
24270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        for (int i = 1; i < pollFds.size(); ++i) {
24370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            StructPollfd pollFd = pollFds.get(i);
24470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            if (pollFd.revents == 0) {
245adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                continue;
246adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
24770c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            if (pollFd.fd == null) {
24870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                break;
24970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            }
25070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
25170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            SelectionKeyImpl key = (SelectionKeyImpl) pollFd.userData;
25270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes
25370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            pollFd.fd = null;
25470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            pollFd.userData = null;
255eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
256eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson            int ops = key.interestOpsNoCheck();
257adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            int selectedOp = 0;
25870c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            if ((pollFd.revents & POLLIN) != 0) {
25970c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                selectedOp = ops & (OP_ACCEPT | OP_READ);
26070c820401677ca251ad09ac64cc23c760764e75dElliott Hughes            } else if ((pollFd.revents & POLLOUT) != 0) {
26170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                if (key.isConnected()) {
26270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    selectedOp = ops & OP_WRITE;
26370c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                } else {
26470c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    selectedOp = ops & OP_CONNECT;
26570c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                }
266adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
267adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
26860a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes            if (selectedOp != 0) {
269eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                boolean wasSelected = mutableSelectedKeys.contains(key);
270eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                if (wasSelected && key.readyOps() != selectedOp) {
271adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    key.setReadyOps(key.readyOps() | selectedOp);
27270c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    ++readyKeyCount;
273eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                } else if (!wasSelected) {
274adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                    key.setReadyOps(selectedOp);
275eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    mutableSelectedKeys.add(key);
27670c820401677ca251ad09ac64cc23c760764e75dElliott Hughes                    ++readyKeyCount;
277adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
278adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
279adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
280eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
28170c820401677ca251ad09ac64cc23c760764e75dElliott Hughes        return readyKeyCount;
282adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
283adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
2846b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override public synchronized Set<SelectionKey> selectedKeys() {
28510959ae7eb41e8ceecb16378c25395eb2f29106cJesse Wilson        checkClosed();
286eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        return selectedKeys;
287adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
288adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
289eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    /**
290eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * Removes cancelled keys from the key set and selected key set, and
291eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * deregisters the corresponding channels. Returns the number of keys
292eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     * removed from the selected key set.
293eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson     */
294eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson    private int doCancel() {
295eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        int deselected = 0;
296eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
297adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        Set<SelectionKey> cancelledKeys = cancelledKeys();
298adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        synchronized (cancelledKeys) {
299adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            if (cancelledKeys.size() > 0) {
30060a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes                for (SelectionKey currentKey : cancelledKeys) {
30160a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes                    mutableKeys.remove(currentKey);
30260a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes                    deregister((AbstractSelectionKey) currentKey);
30360a0a96f334f159418763cab17c48a09c97cbd2fElliott Hughes                    if (mutableSelectedKeys.remove(currentKey)) {
304eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                        deselected++;
305eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                    }
306adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project                }
307eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson                cancelledKeys.clear();
308adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            }
309adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
310eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson
311eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        return deselected;
312adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
313adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
3146b739231f8985f33f20672fe727fde0d0f023eadJesse Wilson    @Override public Selector wakeup() {
315adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        try {
31678c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes            Libcore.os.write(wakeupOut, new byte[] { 1 }, 0, 1);
31778c7cc547101002b9f9043cf3845970719d1bda8Elliott Hughes        } catch (ErrnoException ignored) {
318adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
319adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        return this;
320adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
321adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
322adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    private static class UnaddableSet<E> implements Set<E> {
323adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
324eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        private final Set<E> set;
325adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
326adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        UnaddableSet(Set<E> set) {
327adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            this.set = set;
328adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
329adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
330eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        @Override
331adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean equals(Object object) {
332adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.equals(object);
333adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
334adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
335eaa2ff09069424b0f7a95c7cd831cef1b744fe67Jesse Wilson        @Override
336adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int hashCode() {
337adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.hashCode();
338adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
339adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
340adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean add(E object) {
341adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new UnsupportedOperationException();
342adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
343adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
344adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean addAll(Collection<? extends E> c) {
345adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            throw new UnsupportedOperationException();
346adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
347adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
348adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public void clear() {
349adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            set.clear();
350adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
351adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
352adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean contains(Object object) {
353adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.contains(object);
354adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
355adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
356adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean containsAll(Collection<?> c) {
357adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.containsAll(c);
358adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
359adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
360adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean isEmpty() {
361adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.isEmpty();
362adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
363adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
364adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public Iterator<E> iterator() {
365adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.iterator();
366adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
367adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
368adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean remove(Object object) {
369adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.remove(object);
370adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
371adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
372adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean removeAll(Collection<?> c) {
373adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.removeAll(c);
374adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
375adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
376adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public boolean retainAll(Collection<?> c) {
377adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.retainAll(c);
378adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
379adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
380adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public int size() {
381adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.size();
382adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
383adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
384adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public Object[] toArray() {
385adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.toArray();
386adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
387adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project
388adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        public <T> T[] toArray(T[] a) {
389adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project            return set.toArray(a);
390adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project        }
391adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project    }
392adc854b798c1cfe3bfd4c27d68d5cee38ca617daThe Android Open Source Project}
393