1 /*
  2  * Copyright (c) 2000, 2019, 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 
 26 package sun.nio.ch;
 27 
 28 import java.io.IOException;
 29 import java.nio.channels.ClosedSelectorException;
 30 import java.nio.channels.IllegalSelectorException;
 31 import java.nio.channels.SelectableChannel;
 32 import java.nio.channels.SelectionKey;
 33 import java.nio.channels.spi.AbstractSelectableChannel;
 34 import java.nio.channels.spi.AbstractSelector;
 35 import java.nio.channels.spi.SelectorProvider;
 36 import java.util.ArrayDeque;
 37 import java.util.Collections;
 38 import java.util.Deque;
 39 import java.util.HashSet;
 40 import java.util.Iterator;
 41 import java.util.Objects;
 42 import java.util.Set;

 43 import java.util.concurrent.ConcurrentHashMap;


 44 import java.util.function.Consumer;
 45 



 46 
 47 /**
 48  * Base Selector implementation class.
 49  */
 50 
 51 public abstract class SelectorImpl
 52     extends AbstractSelector
 53 {


 54     // The set of keys registered with this Selector
 55     private final Set<SelectionKey> keys;
 56 
 57     // The set of keys with data ready for an operation
 58     private final Set<SelectionKey> selectedKeys;
 59 
 60     // Public views of the key sets
 61     private final Set<SelectionKey> publicKeys;             // Immutable
 62     private final Set<SelectionKey> publicSelectedKeys;     // Removal allowed, but not addition
 63 
 64     // pending cancelled keys for deregistration
 65     private final Deque<SelectionKeyImpl> cancelledKeys = new ArrayDeque<>();
 66 
 67     // used to check for reentrancy
 68     private boolean inSelect;
 69 



 70     protected SelectorImpl(SelectorProvider sp) {
 71         super(sp);
 72         keys = ConcurrentHashMap.newKeySet();
 73         selectedKeys = new HashSet<>();
 74         publicKeys = Collections.unmodifiableSet(keys);
 75         publicSelectedKeys = Util.ungrowableSet(selectedKeys);
 76     }
 77 
 78     private void ensureOpen() {
 79         if (!isOpen())
 80             throw new ClosedSelectorException();
 81     }
 82 
 83     @Override
 84     public final Set<SelectionKey> keys() {
 85         ensureOpen();
 86         return publicKeys;
 87     }
 88 
 89     @Override
 90     public final Set<SelectionKey> selectedKeys() {
 91         ensureOpen();
 92         return publicSelectedKeys;
 93     }
 94 
 95     /**
 96      * Marks the beginning of a select operation that might block
 97      */
 98     protected final void begin(boolean blocking) {
 99         if (blocking) begin();
100     }
101 
102     /**
103      * Marks the end of a select operation that may have blocked
104      */
105     protected final void end(boolean blocking) {
106         if (blocking) end();
107     }
108 
109     /**
110      * Selects the keys for channels that are ready for I/O operations.
111      *
112      * @param action  the action to perform, can be null
113      * @param timeout timeout in milliseconds to wait, 0 to not wait, -1 to
114      *                wait indefinitely
115      */
116     protected abstract int doSelect(Consumer<SelectionKey> action, long timeout)
117         throws IOException;
118 
119     private int lockAndDoSelect(Consumer<SelectionKey> action, long timeout)
120         throws IOException
121     {
122         synchronized (this) {
123             ensureOpen();
124             if (inSelect)
125                 throw new IllegalStateException("select in progress");
126             inSelect = true;
127             try {
128                 synchronized (publicSelectedKeys) {
129                     return doSelect(action, timeout);
130                 }
131             } finally {
132                 inSelect = false;
133             }
134         }
135     }
136 
137     @Override
138     public final int select(long timeout) throws IOException {
139         if (timeout < 0)
140             throw new IllegalArgumentException("Negative timeout");
141         return lockAndDoSelect(null, (timeout == 0) ? -1 : timeout);
142     }
143 
144     @Override
145     public final int select() throws IOException {
146         return lockAndDoSelect(null, -1);
147     }
148 
149     @Override
150     public final int selectNow() throws IOException {
151         return lockAndDoSelect(null, 0);
152     }
153 
154     @Override
155     public final int select(Consumer<SelectionKey> action, long timeout)
156         throws IOException
157     {
158         Objects.requireNonNull(action);
159         if (timeout < 0)
160             throw new IllegalArgumentException("Negative timeout");
161         return lockAndDoSelect(action, (timeout == 0) ? -1 : timeout);
162     }
163 
164     @Override
165     public final int select(Consumer<SelectionKey> action) throws IOException {
166         Objects.requireNonNull(action);
167         return lockAndDoSelect(action, -1);
168     }
169 
170     @Override
171     public final int selectNow(Consumer<SelectionKey> action) throws IOException {
172         Objects.requireNonNull(action);
173         return lockAndDoSelect(action, 0);
174     }
175 
































































































176     /**
177      * Invoked by implCloseSelector to close the selector.
178      */
179     protected abstract void implClose() throws IOException;
180 
181     @Override
182     public final void implCloseSelector() throws IOException {
183         wakeup();
184         synchronized (this) {
185             implClose();
186             synchronized (publicSelectedKeys) {
187                 // Deregister channels
188                 Iterator<SelectionKey> i = keys.iterator();
189                 while (i.hasNext()) {
190                     SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
191                     deregister(ski);
192                     SelectableChannel selch = ski.channel();
193                     if (!selch.isOpen() && !selch.isRegistered())
194                         ((SelChImpl)selch).kill();
195                     selectedKeys.remove(ski);
196                     i.remove();
197                 }
198                 assert selectedKeys.isEmpty() && keys.isEmpty();
199             }
200         }
201     }
202 
203     @Override
204     protected final SelectionKey register(AbstractSelectableChannel ch,
205                                           int ops,
206                                           Object attachment)
207     {
208         if (!(ch instanceof SelChImpl))
209             throw new IllegalSelectorException();
210         SelectionKeyImpl k = new SelectionKeyImpl((SelChImpl)ch, this);
211         if (attachment != null)
212             k.attach(attachment);
213 
214         // register (if needed) before adding to key set
215         implRegister(k);
216 
217         // add to the selector's key set, removing it immediately if the selector
218         // is closed. The key is not in the channel's key set at this point but
219         // it may be observed by a thread iterating over the selector's key set.
220         keys.add(k);
221         try {
222             k.interestOps(ops);
223         } catch (ClosedSelectorException e) {
224             assert ch.keyFor(this) == null;
225             keys.remove(k);
226             k.cancel();
227             throw e;
228         }
229         return k;
230     }
231 
232     /**
233      * Register the key in the selector.
234      *
235      * The default implementation checks if the selector is open. It should
236      * be overridden by selector implementations as needed.
237      */
238     protected void implRegister(SelectionKeyImpl ski) {
239         ensureOpen();
240     }
241 
242     /**
243      * Removes the key from the selector
244      */
245     protected abstract void implDereg(SelectionKeyImpl ski) throws IOException;
246 
247     /**
248      * Queue a cancelled key for the next selection operation
249      */
250     public void cancel(SelectionKeyImpl ski) {
251         synchronized (cancelledKeys) {
252             cancelledKeys.addLast(ski);
253         }
254     }
255 
256     /**
257      * Invoked by selection operations to process the cancelled keys
258      */
259     protected final void processDeregisterQueue() throws IOException {
260         assert Thread.holdsLock(this);
261         assert Thread.holdsLock(publicSelectedKeys);
262 
263         synchronized (cancelledKeys) {
264             SelectionKeyImpl ski;
265             while ((ski = cancelledKeys.pollFirst()) != null) {
266                 // remove the key from the selector
267                 implDereg(ski);
268 
269                 selectedKeys.remove(ski);
270                 keys.remove(ski);
271 
272                 // remove from channel's key set
273                 deregister(ski);
274 
275                 SelectableChannel ch = ski.channel();
276                 if (!ch.isOpen() && !ch.isRegistered())
277                     ((SelChImpl)ch).kill();
278             }
279         }
280     }
281 
282     /**
283      * Invoked by selection operations to handle ready events. If an action
284      * is specified then it is invoked to handle the key, otherwise the key
285      * is added to the selected-key set (or updated when it is already in the
286      * set).
287      */
288     protected final int processReadyEvents(int rOps,
289                                            SelectionKeyImpl ski,
290                                            Consumer<SelectionKey> action) {
291         if (action != null) {
292             ski.translateAndSetReadyOps(rOps);
293             if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
294                 action.accept(ski);
295                 ensureOpen();
296                 return 1;
297             }
298         } else {
299             assert Thread.holdsLock(publicSelectedKeys);
300             if (selectedKeys.contains(ski)) {
301                 if (ski.translateAndUpdateReadyOps(rOps)) {
302                     return 1;
303                 }
304             } else {
305                 ski.translateAndSetReadyOps(rOps);
306                 if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
307                     selectedKeys.add(ski);
308                     return 1;
309                 }
310             }
311         }
312         return 0;
313     }
314 
315     /**
316      * Invoked by interestOps to ensure the interest ops are updated at the
317      * next selection operation.
318      */
319     protected abstract void setEventOps(SelectionKeyImpl ski);
320 }
--- EOF ---