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