1 /*
2  * Copyright (c) 2001, 2013, 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.*;
30 import java.nio.channels.spi.*;
31 import java.util.*;
32 import sun.misc.*;
33 
34 
35 /**
36  * An abstract selector impl.
37  */
38 
39 abstract class AbstractPollSelectorImpl
40     extends SelectorImpl
41 {
42 
43     // The poll fd array
44     PollArrayWrapper pollWrapper;
45 
46     // Initial capacity of the pollfd array
47     protected final int INIT_CAP = 10;
48 
49     // The list of SelectableChannels serviced by this Selector
50     protected SelectionKeyImpl[] channelArray;
51 
52     // In some impls the first entry of channelArray is bogus
53     protected int channelOffset = 0;
54 
55     // The number of valid channels in this Selector's poll array
56     protected int totalChannels;
57 
58     // True if this Selector has been closed
59     private boolean closed = false;
60 
61     // Lock for close and cleanup
62     private Object closeLock = new Object();
63 
AbstractPollSelectorImpl(SelectorProvider sp, int channels, int offset)64     AbstractPollSelectorImpl(SelectorProvider sp, int channels, int offset) {
65         super(sp);
66         this.totalChannels = channels;
67         this.channelOffset = offset;
68     }
69 
putEventOps(SelectionKeyImpl sk, int ops)70     public void putEventOps(SelectionKeyImpl sk, int ops) {
71         synchronized (closeLock) {
72             if (closed)
73                 throw new ClosedSelectorException();
74             pollWrapper.putEventOps(sk.getIndex(), ops);
75         }
76     }
77 
wakeup()78     public Selector wakeup() {
79         pollWrapper.interrupt();
80         return this;
81     }
82 
doSelect(long timeout)83     protected abstract int doSelect(long timeout) throws IOException;
84 
implClose()85     protected void implClose() throws IOException {
86         synchronized (closeLock) {
87             if (closed)
88                 return;
89             closed = true;
90             // Deregister channels
91             for(int i=channelOffset; i<totalChannels; i++) {
92                 SelectionKeyImpl ski = channelArray[i];
93                 assert(ski.getIndex() != -1);
94                 ski.setIndex(-1);
95                 deregister(ski);
96                 SelectableChannel selch = channelArray[i].channel();
97                 if (!selch.isOpen() && !selch.isRegistered())
98                     ((SelChImpl)selch).kill();
99             }
100             implCloseInterrupt();
101             pollWrapper.free();
102             pollWrapper = null;
103             selectedKeys = null;
104             channelArray = null;
105             totalChannels = 0;
106         }
107     }
108 
implCloseInterrupt()109     protected abstract void implCloseInterrupt() throws IOException;
110 
111     /**
112      * Copy the information in the pollfd structs into the opss
113      * of the corresponding Channels. Add the ready keys to the
114      * ready queue.
115      */
updateSelectedKeys()116     protected int updateSelectedKeys() {
117         int numKeysUpdated = 0;
118         // Skip zeroth entry; it is for interrupts only
119         for (int i=channelOffset; i<totalChannels; i++) {
120             int rOps = pollWrapper.getReventOps(i);
121             if (rOps != 0) {
122                 SelectionKeyImpl sk = channelArray[i];
123                 pollWrapper.putReventOps(i, 0);
124                 if (selectedKeys.contains(sk)) {
125                     if (sk.channel.translateAndSetReadyOps(rOps, sk)) {
126                         numKeysUpdated++;
127                     }
128                 } else {
129                     sk.channel.translateAndSetReadyOps(rOps, sk);
130                     if ((sk.nioReadyOps() & sk.nioInterestOps()) != 0) {
131                         selectedKeys.add(sk);
132                         numKeysUpdated++;
133                     }
134                 }
135             }
136         }
137         return numKeysUpdated;
138     }
139 
implRegister(SelectionKeyImpl ski)140     protected void implRegister(SelectionKeyImpl ski) {
141         synchronized (closeLock) {
142             if (closed)
143                 throw new ClosedSelectorException();
144 
145             // Check to see if the array is large enough
146             if (channelArray.length == totalChannels) {
147                 // Make a larger array
148                 int newSize = pollWrapper.totalChannels * 2;
149                 SelectionKeyImpl temp[] = new SelectionKeyImpl[newSize];
150                 // Copy over
151                 for (int i=channelOffset; i<totalChannels; i++)
152                     temp[i] = channelArray[i];
153                 channelArray = temp;
154                 // Grow the NativeObject poll array
155                 pollWrapper.grow(newSize);
156             }
157             channelArray[totalChannels] = ski;
158             ski.setIndex(totalChannels);
159             pollWrapper.addEntry(ski.channel);
160             totalChannels++;
161             keys.add(ski);
162         }
163     }
164 
implDereg(SelectionKeyImpl ski)165     protected void implDereg(SelectionKeyImpl ski) throws IOException {
166         // Algorithm: Copy the sc from the end of the list and put it into
167         // the location of the sc to be removed (since order doesn't
168         // matter). Decrement the sc count. Update the index of the sc
169         // that is moved.
170         int i = ski.getIndex();
171         assert (i >= 0);
172         if (i != totalChannels - 1) {
173             // Copy end one over it
174             SelectionKeyImpl endChannel = channelArray[totalChannels-1];
175             channelArray[i] = endChannel;
176             endChannel.setIndex(i);
177             pollWrapper.release(i);
178             PollArrayWrapper.replaceEntry(pollWrapper, totalChannels - 1,
179                                           pollWrapper, i);
180         } else {
181             pollWrapper.release(i);
182         }
183         // Destroy the last one
184         channelArray[totalChannels-1] = null;
185         totalChannels--;
186         pollWrapper.totalChannels--;
187         ski.setIndex(-1);
188         // Remove the key from keys and selectedKeys
189         keys.remove(ski);
190         selectedKeys.remove(ski);
191         deregister((AbstractSelectionKey)ski);
192         SelectableChannel selch = ski.channel();
193         if (!selch.isOpen() && !selch.isRegistered())
194             ((SelChImpl)selch).kill();
195     }
196 }
197