1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.channel.socket.oio;
17
18 import org.jboss.netty.channel.Channel;
19 import org.jboss.netty.channel.ChannelFuture;
20 import org.jboss.netty.channel.Channels;
21 import org.jboss.netty.channel.socket.Worker;
22
23 import java.io.IOException;
24 import java.net.SocketTimeoutException;
25 import java.util.Queue;
26 import java.util.concurrent.ConcurrentLinkedQueue;
27
28 import static org.jboss.netty.channel.Channels.*;
29
30
31
32
33
34
35 abstract class AbstractOioWorker<C extends AbstractOioChannel> implements Worker {
36
37 private final Queue<Runnable> eventQueue = new ConcurrentLinkedQueue<Runnable>();
38
39 protected final C channel;
40
41
42
43
44
45 protected volatile Thread thread;
46
47 private volatile boolean done;
48
49 protected AbstractOioWorker(C channel) {
50 this.channel = channel;
51 channel.worker = this;
52 }
53
54 public void run() {
55 thread = channel.workerThread = Thread.currentThread();
56 while (channel.isOpen()) {
57 synchronized (channel.interestOpsLock) {
58 while (!channel.isReadable()) {
59 try {
60
61
62 channel.interestOpsLock.wait();
63 } catch (InterruptedException e) {
64 if (!channel.isOpen()) {
65 break;
66 }
67 }
68 }
69 }
70
71 boolean cont = false;
72 try {
73 cont = process();
74 } catch (Throwable t) {
75 boolean readTimeout = t instanceof SocketTimeoutException;
76 if (!readTimeout && !channel.isSocketClosed()) {
77 fireExceptionCaught(channel, t);
78 }
79 if (readTimeout) {
80
81
82 cont = true;
83 }
84 } finally {
85 processEventQueue();
86 }
87
88 if (!cont) {
89 break;
90 }
91 }
92
93
94
95 channel.workerThread = null;
96
97
98 close(channel, succeededFuture(channel), true);
99
100
101
102 done = true;
103
104
105 processEventQueue();
106 }
107
108 static boolean isIoThread(AbstractOioChannel channel) {
109 return Thread.currentThread() == channel.workerThread;
110 }
111
112 public void executeInIoThread(Runnable task) {
113
114
115
116
117 if (Thread.currentThread() == thread || done) {
118 task.run();
119 } else {
120 boolean added = eventQueue.offer(task);
121
122 if (added) {
123
124 }
125 }
126 }
127
128 private void processEventQueue() {
129 for (;;) {
130 final Runnable task = eventQueue.poll();
131 if (task == null) {
132 break;
133 }
134 task.run();
135 }
136 }
137
138
139
140
141
142
143
144
145
146
147 abstract boolean process() throws IOException;
148
149 static void setInterestOps(
150 AbstractOioChannel channel, ChannelFuture future, int interestOps) {
151 boolean iothread = isIoThread(channel);
152
153
154 interestOps &= ~Channel.OP_WRITE;
155 interestOps |= channel.getInterestOps() & Channel.OP_WRITE;
156
157 boolean changed = false;
158 try {
159 if (channel.getInterestOps() != interestOps) {
160 if ((interestOps & Channel.OP_READ) != 0) {
161 channel.setInterestOpsNow(Channel.OP_READ);
162 } else {
163 channel.setInterestOpsNow(Channel.OP_NONE);
164 }
165 changed = true;
166 }
167
168 future.setSuccess();
169 if (changed) {
170 synchronized (channel.interestOpsLock) {
171 channel.setInterestOpsNow(interestOps);
172
173
174 Thread currentThread = Thread.currentThread();
175 Thread workerThread = channel.workerThread;
176 if (workerThread != null && currentThread != workerThread) {
177 workerThread.interrupt();
178 }
179 }
180 if (iothread) {
181 fireChannelInterestChanged(channel);
182 } else {
183 fireChannelInterestChangedLater(channel);
184 }
185 }
186 } catch (Throwable t) {
187 future.setFailure(t);
188 if (iothread) {
189 fireExceptionCaught(channel, t);
190 } else {
191 fireExceptionCaughtLater(channel, t);
192 }
193 }
194 }
195
196 static void close(AbstractOioChannel channel, ChannelFuture future) {
197 close(channel, future, isIoThread(channel));
198 }
199
200 private static void close(AbstractOioChannel channel, ChannelFuture future, boolean iothread) {
201 boolean connected = channel.isConnected();
202 boolean bound = channel.isBound();
203
204 try {
205 channel.closeSocket();
206 if (channel.setClosed()) {
207 future.setSuccess();
208 if (connected) {
209
210 Thread currentThread = Thread.currentThread();
211 Thread workerThread = channel.workerThread;
212 if (workerThread != null && currentThread != workerThread) {
213 workerThread.interrupt();
214 }
215 if (iothread) {
216 fireChannelDisconnected(channel);
217 } else {
218 fireChannelDisconnectedLater(channel);
219 }
220 }
221 if (bound) {
222 if (iothread) {
223 fireChannelUnbound(channel);
224 } else {
225 fireChannelUnboundLater(channel);
226 }
227 }
228 if (iothread) {
229 fireChannelClosed(channel);
230 } else {
231 fireChannelClosedLater(channel);
232 }
233 } else {
234 future.setSuccess();
235 }
236 } catch (Throwable t) {
237 future.setFailure(t);
238 if (iothread) {
239 fireExceptionCaught(channel, t);
240 } else {
241 fireExceptionCaughtLater(channel, t);
242 }
243 }
244 }
245 }