1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 package org.apache.tomcat.util.net;
19
20 import java.net.Socket;
21
22 import org.apache.tomcat.util.threads.ThreadWithAttributes;
23
24 /**
25 * Regular master slave thread pool. Slave threads will wait for work.
26 */
27 class MasterSlaveWorkerThread implements Runnable {
28
29 protected PoolTcpEndpoint endpoint;
30 protected String threadName;
31 protected boolean stopped = false;
32 private Object threadSync = new Object();
33 private Thread thread = null;
34 private boolean available = false;
35 private Socket socket = null;
36 private TcpConnection con = new TcpConnection();
37 private Object[] threadData = null;
38
39
40 public MasterSlaveWorkerThread(PoolTcpEndpoint endpoint, String threadName) {
41 this.endpoint = endpoint;
42 this.threadName = threadName;
43 }
44
45
46 /**
47 * Process an incoming TCP/IP connection on the specified socket. Any
48 * exception that occurs during processing must be logged and swallowed.
49 * <b>NOTE</b>: This method is called from our Connector's thread. We
50 * must assign it to our own thread so that multiple simultaneous
51 * requests can be handled.
52 *
53 * @param socket TCP socket to process
54 */
55 synchronized void assign(Socket socket) {
56
57 // Wait for the Processor to get the previous Socket
58 while (available) {
59 try {
60 wait();
61 } catch (InterruptedException e) {
62 }
63 }
64
65 // Store the newly available Socket and notify our thread
66 this.socket = socket;
67 available = true;
68 notifyAll();
69
70 }
71
72
73 /**
74 * Await a newly assigned Socket from our Connector, or <code>null</code>
75 * if we are supposed to shut down.
76 */
77 private synchronized Socket await() {
78
79 // Wait for the Connector to provide a new Socket
80 while (!available) {
81 try {
82 wait();
83 } catch (InterruptedException e) {
84 }
85 }
86
87 // Notify the Connector that we have received this Socket
88 Socket socket = this.socket;
89 available = false;
90 notifyAll();
91
92 return (socket);
93
94 }
95
96
97
98 /**
99 * The background thread that listens for incoming TCP/IP connections and
100 * hands them off to an appropriate processor.
101 */
102 public void run() {
103
104 // Process requests until we receive a shutdown signal
105 while (!stopped) {
106
107 // Wait for the next socket to be assigned
108 Socket socket = await();
109 if (socket == null)
110 continue;
111
112 // Process the request from this socket
113 endpoint.processSocket(socket, con, threadData);
114
115 // Finish up this request
116 endpoint.recycleWorkerThread(this);
117
118 }
119
120 // Tell threadStop() we have shut ourselves down successfully
121 synchronized (threadSync) {
122 threadSync.notifyAll();
123 }
124
125 }
126
127
128 /**
129 * Start the background processing thread.
130 */
131 public void start() {
132 threadData = endpoint.getConnectionHandler().init();
133 thread = new ThreadWithAttributes(null, this);
134 thread.setName(threadName);
135 thread.setDaemon(true);
136 thread.start();
137 }
138
139
140 /**
141 * Stop the background processing thread.
142 */
143 public void stop() {
144 stopped = true;
145 assign(null);
146 thread = null;
147 threadData = null;
148 }
149
150
151 }