1/*
2 * Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package sun.nio.ch;
27
28import java.io.IOException;
29import java.nio.channels.*;
30import java.nio.channels.spi.*;
31import java.net.SocketException;
32import java.util.*;
33
34
35/**
36 * Base Selector implementation class.
37 */
38
39public abstract class SelectorImpl
40    extends AbstractSelector
41{
42
43    // The set of keys with data ready for an operation
44    protected Set<SelectionKey> selectedKeys;
45
46    // The set of keys registered with this Selector
47    protected HashSet<SelectionKey> keys;
48
49    // Public views of the key sets
50    private Set<SelectionKey> publicKeys;             // Immutable
51    private Set<SelectionKey> publicSelectedKeys;     // Removal allowed, but not addition
52
53    protected SelectorImpl(SelectorProvider sp) {
54        super(sp);
55        keys = new HashSet<SelectionKey>();
56        selectedKeys = new HashSet<SelectionKey>();
57        if (Util.atBugLevel("1.4")) {
58            publicKeys = keys;
59            publicSelectedKeys = selectedKeys;
60        } else {
61            publicKeys = Collections.unmodifiableSet(keys);
62            publicSelectedKeys = Util.ungrowableSet(selectedKeys);
63        }
64    }
65
66    public Set<SelectionKey> keys() {
67        if (!isOpen() && !Util.atBugLevel("1.4"))
68            throw new ClosedSelectorException();
69        return publicKeys;
70    }
71
72    public Set<SelectionKey> selectedKeys() {
73        if (!isOpen() && !Util.atBugLevel("1.4"))
74            throw new ClosedSelectorException();
75        return publicSelectedKeys;
76    }
77
78    protected abstract int doSelect(long timeout) throws IOException;
79
80    private int lockAndDoSelect(long timeout) throws IOException {
81        synchronized (this) {
82            if (!isOpen())
83                throw new ClosedSelectorException();
84            synchronized (publicKeys) {
85                synchronized (publicSelectedKeys) {
86                    return doSelect(timeout);
87                }
88            }
89        }
90    }
91
92    public int select(long timeout)
93        throws IOException
94    {
95        if (timeout < 0)
96            throw new IllegalArgumentException("Negative timeout");
97        return lockAndDoSelect((timeout == 0) ? -1 : timeout);
98    }
99
100    public int select() throws IOException {
101        return select(0);
102    }
103
104    public int selectNow() throws IOException {
105        return lockAndDoSelect(0);
106    }
107
108    public void implCloseSelector() throws IOException {
109        wakeup();
110        synchronized (this) {
111            synchronized (publicKeys) {
112                synchronized (publicSelectedKeys) {
113                    implClose();
114                }
115            }
116        }
117    }
118
119    protected abstract void implClose() throws IOException;
120
121    public void putEventOps(SelectionKeyImpl sk, int ops) { }
122
123    protected final SelectionKey register(AbstractSelectableChannel ch,
124                                          int ops,
125                                          Object attachment)
126    {
127        if (!(ch instanceof SelChImpl))
128            throw new IllegalSelectorException();
129        SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this);
130        k.attach(attachment);
131        synchronized (publicKeys) {
132            implRegister(k);
133        }
134        k.interestOps(ops);
135        return k;
136    }
137
138    protected abstract void implRegister(SelectionKeyImpl ski);
139
140    void processDeregisterQueue() throws IOException {
141        // Precondition: Synchronized on this, keys, and selectedKeys
142        Set<SelectionKey> cks = cancelledKeys();
143        synchronized (cks) {
144            if (!cks.isEmpty()) {
145                Iterator<SelectionKey> i = cks.iterator();
146                while (i.hasNext()) {
147                    SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
148                    try {
149                        implDereg(ski);
150                    } catch (SocketException se) {
151                        throw new IOException("Error deregistering key", se);
152                    } finally {
153                        i.remove();
154                    }
155                }
156            }
157        }
158    }
159
160    protected abstract void implDereg(SelectionKeyImpl ski) throws IOException;
161
162    abstract public Selector wakeup();
163
164}
165