1 /*
2 * Copyright (c) 2005, 2015, 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
33 /**
34 * An implementation of Selector for Linux 2.6+ kernels that uses
35 * the epoll event notification facility.
36 */
37 class EPollSelectorImpl
38 extends SelectorImpl
39 {
40
41 // File descriptors used for interrupt
42 protected int fd0;
43 protected int fd1;
44
45 // The poll object
46 EPollArrayWrapper pollWrapper;
47
48 // Maps from file descriptors to keys
49 private Map<Integer,SelectionKeyImpl> fdToKey;
50
51 // True if this Selector has been closed
52 private volatile boolean closed;
53
54 // Lock for interrupt triggering and clearing
55 private final Object interruptLock = new Object();
56 private boolean interruptTriggered = false;
57
58 /**
59 * Package private constructor called by factory method in
60 * the abstract superclass Selector.
61 */
62 EPollSelectorImpl(SelectorProvider sp) throws IOException {
63 super(sp);
64 long pipeFds = IOUtil.makePipe(false);
65 fd0 = (int) (pipeFds >>> 32);
66 fd1 = (int) pipeFds;
67 try {
68 pollWrapper = new EPollArrayWrapper();
69 pollWrapper.initInterrupt(fd0, fd1);
70 fdToKey = new HashMap<>();
71 } catch (Throwable t) {
72 try {
73 FileDispatcherImpl.closeIntFD(fd0);
74 } catch (IOException ioe0) {
75 t.addSuppressed(ioe0);
76 }
77 try {
78 FileDispatcherImpl.closeIntFD(fd1);
79 } catch (IOException ioe1) {
80 t.addSuppressed(ioe1);
81 }
82 throw t;
83 }
84 }
85
86 protected int doSelect(long timeout) throws IOException {
87 if (closed)
88 throw new ClosedSelectorException();
89 processDeregisterQueue();
90 try {
91 begin();
92 pollWrapper.poll(timeout);
93 } finally {
94 end();
95 }
96 processDeregisterQueue();
97 int numKeysUpdated = updateSelectedKeys();
98 if (pollWrapper.interrupted()) {
99 // Clear the wakeup pipe
100 pollWrapper.putEventOps(pollWrapper.interruptedIndex(), 0);
101 synchronized (interruptLock) {
102 pollWrapper.clearInterrupted();
103 IOUtil.drain(fd0);
104 interruptTriggered = false;
105 }
106 }
107 return numKeysUpdated;
108 }
109
110 /**
111 * Update the keys whose fd's have been selected by the epoll.
112 * Add the ready keys to the ready queue.
113 */
114 private int updateSelectedKeys() {
115 int entries = pollWrapper.updated;
116 int numKeysUpdated = 0;
117 for (int i=0; i<entries; i++) {
118 int nextFD = pollWrapper.getDescriptor(i);
119 SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
120 // ski is null in the case of an interrupt
121 if (ski != null) {
122 int rOps = pollWrapper.getEventOps(i);
123 if (selectedKeys.contains(ski)) {
124 if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
125 numKeysUpdated++;
126 }
127 } else {
128 ski.channel.translateAndSetReadyOps(rOps, ski);
129 if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
130 selectedKeys.add(ski);
131 numKeysUpdated++;
132 }
133 }
134 }
135 }
136 return numKeysUpdated;
137 }
138
139 protected void implClose() throws IOException {
140 if (closed)
141 return;
142 closed = true;
143
144 // prevent further wakeup
145 synchronized (interruptLock) {
146 interruptTriggered = true;
147 }
148
149 FileDispatcherImpl.closeIntFD(fd0);
150 FileDispatcherImpl.closeIntFD(fd1);
151
152 pollWrapper.closeEPollFD();
153 // it is possible
154 selectedKeys = null;
155
156 // Deregister channels
157 Iterator<SelectionKey> i = keys.iterator();
158 while (i.hasNext()) {
159 SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
160 deregister(ski);
161 SelectableChannel selch = ski.channel();
162 if (!selch.isOpen() && !selch.isRegistered())
163 ((SelChImpl)selch).kill();
164 i.remove();
165 }
166
167 fd0 = -1;
168 fd1 = -1;
169 }
170
171 protected void implRegister(SelectionKeyImpl ski) {
172 if (closed)
173 throw new ClosedSelectorException();
174 SelChImpl ch = ski.channel;
175 int fd = Integer.valueOf(ch.getFDVal());
176 fdToKey.put(fd, ski);
177 pollWrapper.add(fd);
178 keys.add(ski);
179 }
180
181 protected void implDereg(SelectionKeyImpl ski) throws IOException {
182 assert (ski.getIndex() >= 0);
183 SelChImpl ch = ski.channel;
184 int fd = ch.getFDVal();
185 fdToKey.remove(Integer.valueOf(fd));
186 pollWrapper.remove(fd);
187 ski.setIndex(-1);
188 keys.remove(ski);
189 selectedKeys.remove(ski);
190 deregister((AbstractSelectionKey)ski);
191 SelectableChannel selch = ski.channel();
192 if (!selch.isOpen() && !selch.isRegistered())
193 ((SelChImpl)selch).kill();
194 }
195
196 public void putEventOps(SelectionKeyImpl ski, int ops) {
197 if (closed)
198 throw new ClosedSelectorException();
199 SelChImpl ch = ski.channel;
200 pollWrapper.setInterest(ch.getFDVal(), ops);
201 }
202
203 public Selector wakeup() {
204 synchronized (interruptLock) {
205 if (!interruptTriggered) {
206 pollWrapper.interrupt();
207 interruptTriggered = true;
208 }
209 }
210 return this;
211 }
212 }
|
1 /*
2 * Copyright (c) 2005, 2018, 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
33 /**
34 * An implementation of Selector for Linux 2.6+ kernels that uses
35 * the epoll event notification facility.
36 */
37 class EPollSelectorImpl
38 extends SelectorImpl
39 {
40 // File descriptors used for interrupt
41 private final int fd0;
42 private final int fd1;
43
44 // The poll object
45 private final EPollArrayWrapper pollWrapper;
46
47 // Maps from file descriptors to keys
48 private final Map<Integer, SelectionKeyImpl> fdToKey;
49
50 // True if this Selector has been closed
51 private volatile boolean closed;
52
53 // Lock for interrupt triggering and clearing
54 private final Object interruptLock = new Object();
55 private boolean interruptTriggered = false;
56
57 /**
58 * Package private constructor called by factory method in
59 * the abstract superclass Selector.
60 */
61 EPollSelectorImpl(SelectorProvider sp) throws IOException {
62 super(sp);
63 long pipeFds = IOUtil.makePipe(false);
64 fd0 = (int) (pipeFds >>> 32);
65 fd1 = (int) pipeFds;
66 try {
67 pollWrapper = new EPollArrayWrapper(fd0, fd1);
68 fdToKey = new HashMap<>();
69 } catch (Throwable t) {
70 try {
71 FileDispatcherImpl.closeIntFD(fd0);
72 } catch (IOException ioe0) {
73 t.addSuppressed(ioe0);
74 }
75 try {
76 FileDispatcherImpl.closeIntFD(fd1);
77 } catch (IOException ioe1) {
78 t.addSuppressed(ioe1);
79 }
80 throw t;
81 }
82 }
83
84 private void ensureOpen() {
85 if (closed)
86 throw new ClosedSelectorException();
87 }
88
89 @Override
90 protected int doSelect(long timeout) throws IOException {
91 ensureOpen();
92 int numEntries;
93 processDeregisterQueue();
94 try {
95 begin();
96 numEntries = pollWrapper.poll(timeout);
97 } finally {
98 end();
99 }
100 processDeregisterQueue();
101 return updateSelectedKeys(numEntries);
102 }
103
104 /**
105 * Update the keys whose fd's have been selected by the epoll.
106 * Add the ready keys to the ready queue.
107 */
108 private int updateSelectedKeys(int numEntries) throws IOException {
109 boolean interrupted = false;
110 int numKeysUpdated = 0;
111 for (int i=0; i<numEntries; i++) {
112 int nextFD = pollWrapper.getDescriptor(i);
113 if (nextFD == fd0) {
114 interrupted = true;
115 } else {
116 SelectionKeyImpl ski = fdToKey.get(Integer.valueOf(nextFD));
117 if (ski != null) {
118 int rOps = pollWrapper.getEventOps(i);
119 if (selectedKeys.contains(ski)) {
120 if (ski.channel.translateAndSetReadyOps(rOps, ski)) {
121 numKeysUpdated++;
122 }
123 } else {
124 ski.channel.translateAndSetReadyOps(rOps, ski);
125 if ((ski.nioReadyOps() & ski.nioInterestOps()) != 0) {
126 selectedKeys.add(ski);
127 numKeysUpdated++;
128 }
129 }
130 }
131 }
132 }
133
134 if (interrupted) {
135 clearInterrupt();
136 }
137
138 return numKeysUpdated;
139 }
140
141 @Override
142 protected void implClose() throws IOException {
143 if (closed)
144 return;
145 closed = true;
146
147 // prevent further wakeup
148 synchronized (interruptLock) {
149 interruptTriggered = true;
150 }
151
152 pollWrapper.close();
153 FileDispatcherImpl.closeIntFD(fd0);
154 FileDispatcherImpl.closeIntFD(fd1);
155
156 // Deregister channels
157 Iterator<SelectionKey> i = keys.iterator();
158 while (i.hasNext()) {
159 SelectionKeyImpl ski = (SelectionKeyImpl)i.next();
160 deregister(ski);
161 SelectableChannel selch = ski.channel();
162 if (!selch.isOpen() && !selch.isRegistered())
163 ((SelChImpl)selch).kill();
164 i.remove();
165 }
166 }
167
168 @Override
169 protected void implRegister(SelectionKeyImpl ski) {
170 ensureOpen();
171 SelChImpl ch = ski.channel;
172 int fd = Integer.valueOf(ch.getFDVal());
173 fdToKey.put(fd, ski);
174 pollWrapper.add(fd);
175 keys.add(ski);
176 }
177
178 @Override
179 protected void implDereg(SelectionKeyImpl ski) throws IOException {
180 assert (ski.getIndex() >= 0);
181 SelChImpl ch = ski.channel;
182 int fd = ch.getFDVal();
183 fdToKey.remove(Integer.valueOf(fd));
184 pollWrapper.remove(fd);
185 ski.setIndex(-1);
186 keys.remove(ski);
187 selectedKeys.remove(ski);
188 deregister(ski);
189 SelectableChannel selch = ski.channel();
190 if (!selch.isOpen() && !selch.isRegistered())
191 ((SelChImpl)selch).kill();
192 }
193
194 @Override
195 public void putEventOps(SelectionKeyImpl ski, int ops) {
196 ensureOpen();
197 SelChImpl ch = ski.channel;
198 pollWrapper.setInterest(ch.getFDVal(), ops);
199 }
200
201 @Override
202 public Selector wakeup() {
203 synchronized (interruptLock) {
204 if (!interruptTriggered) {
205 pollWrapper.interrupt();
206 interruptTriggered = true;
207 }
208 }
209 return this;
210 }
211
212 private void clearInterrupt() throws IOException {
213 synchronized (interruptLock) {
214 IOUtil.drain(fd0);
215 interruptTriggered = false;
216 }
217 }
218 }
|