blob: c1cfa10d10cf5d390bdfb20a355cda6b84f89ef2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.tomcat.util.net;
import java.net.Socket;
import org.apache.tomcat.util.threads.ThreadWithAttributes;
/**
* Regular master slave thread pool. Slave threads will wait for work.
*/
class MasterSlaveWorkerThread implements Runnable {
protected PoolTcpEndpoint endpoint;
protected String threadName;
protected boolean stopped = false;
private Object threadSync = new Object();
private Thread thread = null;
private boolean available = false;
private Socket socket = null;
private TcpConnection con = new TcpConnection();
private Object[] threadData = null;
public MasterSlaveWorkerThread(PoolTcpEndpoint endpoint, String threadName) {
this.endpoint = endpoint;
this.threadName = threadName;
}
/**
* Process an incoming TCP/IP connection on the specified socket. Any
* exception that occurs during processing must be logged and swallowed.
* <b>NOTE</b>: This method is called from our Connector's thread. We
* must assign it to our own thread so that multiple simultaneous
* requests can be handled.
*
* @param socket TCP socket to process
*/
synchronized void assign(Socket socket) {
// Wait for the Processor to get the previous Socket
while (available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Store the newly available Socket and notify our thread
this.socket = socket;
available = true;
notifyAll();
}
/**
* Await a newly assigned Socket from our Connector, or <code>null</code>
* if we are supposed to shut down.
*/
private synchronized Socket await() {
// Wait for the Connector to provide a new Socket
while (!available) {
try {
wait();
} catch (InterruptedException e) {
}
}
// Notify the Connector that we have received this Socket
Socket socket = this.socket;
available = false;
notifyAll();
return (socket);
}
/**
* The background thread that listens for incoming TCP/IP connections and
* hands them off to an appropriate processor.
*/
public void run() {
// Process requests until we receive a shutdown signal
while (!stopped) {
// Wait for the next socket to be assigned
Socket socket = await();
if (socket == null)
continue;
// Process the request from this socket
endpoint.processSocket(socket, con, threadData);
// Finish up this request
endpoint.recycleWorkerThread(this);
}
// Tell threadStop() we have shut ourselves down successfully
synchronized (threadSync) {
threadSync.notifyAll();
}
}
/**
* Start the background processing thread.
*/
public void start() {
threadData = endpoint.getConnectionHandler().init();
thread = new ThreadWithAttributes(null, this);
thread.setName(threadName);
thread.setDaemon(true);
thread.start();
}
/**
* Stop the background processing thread.
*/
public void stop() {
stopped = true;
assign(null);
thread = null;
threadData = null;
}
}