You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by co...@locus.apache.org on 2000/08/28 05:14:09 UTC
cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util/threads Reaper.java ThreadPool.java ThreadPoolRunnable.java
costin 00/08/27 20:14:09
Modified: src/share/org/apache/tomcat/core ContextManager.java
src/share/org/apache/tomcat/request ReloadInterceptor.java
src/share/org/apache/tomcat/session StandardManager.java
src/share/org/apache/tomcat/startup Main.java
src/share/org/apache/tomcat/util/net PoolTcpEndpoint.java
Added: src/share/org/apache/tomcat/util/threads Reaper.java
ThreadPool.java ThreadPoolRunnable.java
Removed: src/share/org/apache/tomcat/util Reaper.java ThreadPool.java
ThreadPoolRunnable.java
Log:
- moved thread pool and reaper to util.threads ( part of util refactoring)
- removed a bit of duplicated code from ContextManager
- fixed a bug in StandardManager.
- started to add argument processing to Main ( jar -jar tomcat.jar)
Revision Changes Path
1.124 +3 -12 jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManager.java
Index: ContextManager.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/core/ContextManager.java,v
retrieving revision 1.123
retrieving revision 1.124
diff -u -r1.123 -r1.124
--- ContextManager.java 2000/08/27 21:03:32 1.123
+++ ContextManager.java 2000/08/28 03:14:01 1.124
@@ -479,7 +479,7 @@
if( context==null ) return;
log( "Removing context " + context.toString());
-
+
ContextInterceptor cI[]=getContextInterceptors(context);
for( int i=0; i< cI.length; i++ ) {
cI[i].removeContext( this, context );
@@ -487,6 +487,7 @@
shutdownContext( context );
contextsV.removeElement(context);
+ contexts.remove(context.getPath());
}
public void doReload( Request req, Context context )
@@ -1329,17 +1330,7 @@
public void removeContext(String name) throws TomcatException {
loghelper.log("removeContext(String) is deprecated", new Throwable("trace"), Logger.DEBUG);
Context context = (Context)contexts.get(name);
- log( "Removing context " + context.toString());
-
- ContextInterceptor cI[]=getContextInterceptors(context);
- for( int i=0; i< cI.length; i++ ) {
- cI[i].removeContext( this, context );
- }
-
- if(context != null) {
- shutdownContext( context );
- contexts.remove(name);
- }
+ removeContext( context);
}
public void doPreServletInit(Context ctx, Handler sw)
1.4 +1 -1 jakarta-tomcat/src/share/org/apache/tomcat/request/ReloadInterceptor.java
Index: ReloadInterceptor.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/request/ReloadInterceptor.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -r1.3 -r1.4
--- ReloadInterceptor.java 2000/08/14 18:40:33 1.3
+++ ReloadInterceptor.java 2000/08/28 03:14:02 1.4
@@ -148,7 +148,7 @@
ctx1.addHostAlias( (String)e.nextElement());
cm.removeContext( ctx );
-
+
cm.addContext( ctx1 );
cm.initContext( ctx1 );
1.14 +23 -10 jakarta-tomcat/src/share/org/apache/tomcat/session/StandardManager.java
Index: StandardManager.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/StandardManager.java,v
retrieving revision 1.13
retrieving revision 1.14
diff -u -r1.13 -r1.14
--- StandardManager.java 2000/08/22 06:56:55 1.13
+++ StandardManager.java 2000/08/28 03:14:03 1.14
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/StandardManager.java,v 1.13 2000/08/22 06:56:55 costin Exp $
- * $Revision: 1.13 $
- * $Date: 2000/08/22 06:56:55 $
+ * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/StandardManager.java,v 1.14 2000/08/28 03:14:03 costin Exp $
+ * $Revision: 1.14 $
+ * $Date: 2000/08/28 03:14:03 $
*
* ====================================================================
*
@@ -103,7 +103,7 @@
* @author Craig R. McClanahan
* @author costin@eng.sun.com
* @author <a href="mailto:jon@latchkey.com">Jon S. Stevens</a>
- * @version $Revision: 1.13 $ $Date: 2000/08/22 06:56:55 $
+ * @version $Revision: 1.14 $ $Date: 2000/08/28 03:14:03 $
*/
public final class StandardManager implements Runnable {
// ----------------------------------------------------- Instance Variables
@@ -155,7 +155,7 @@
/**
* The background thread completion semaphore.
*/
- private boolean threadDone = false;
+ private transient boolean threadDone = false;
/**
* Name to register for the background thread.
@@ -413,7 +413,6 @@
public void stop() {
// Stop the background reaper thread
threadStop();
-
// Expire all active sessions
HttpSession sessions[] = findSessions();
for (int i = 0; i < sessions.length; i++) {
@@ -422,7 +421,6 @@
continue;
session.expire();
}
-
}
// -------------------------------------------------------- Package Methods
@@ -479,6 +477,9 @@
}
}
+ final boolean isDone() {
+ return threadDone;
+ }
/**
* Sleep for the duration specified by the <code>checkInterval</code>
@@ -487,9 +488,11 @@
private void threadSleep() {
try {
+ // System.out.println("s" + threadDone+ " " + isDone());
Thread.sleep(checkInterval * 1000L);
+ //System.out.println("S");
} catch (InterruptedException e) {
- ;
+ //System.out.println("SS " + threadDone);
}
}
@@ -523,12 +526,21 @@
threadDone = true;
thread.interrupt();
+ /* Under certain JITs ( probably as a result of
+ over-optimization ) threadDone will not be
+ updated for a while.
+ It is probably a bug ( but I'm not sure about it! )
+ ( so far IBM JDK1.3 had this problem, and
+ something similar ( a bit harder to reproduce )
+ seems to happen under hotspot - I'm not very sure
+ about it)
try {
- thread.join();
+ thread.join();
} catch (InterruptedException e) {
;
}
-
+ */
+
thread = null;
}
@@ -544,6 +556,7 @@
// Loop until the termination semaphore is set
while (!threadDone) {
+ //System.out.println( threadDone + " " + isDone());
threadSleep();
processExpires();
}
1.7 +17 -2 jakarta-tomcat/src/share/org/apache/tomcat/startup/Main.java
Index: Main.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/startup/Main.java,v
retrieving revision 1.6
retrieving revision 1.7
diff -u -r1.6 -r1.7
--- Main.java 2000/08/23 04:06:43 1.6
+++ Main.java 2000/08/28 03:14:05 1.7
@@ -259,7 +259,8 @@
// Add tools.jar if JDK1.2
String java_home=System.getProperty( "java.home" );
- urls[jarCount]= new URL( "file", null , java_home + "/../lib/tools.jar");
+ urls[jarCount]= new URL( "file", null , java_home +
+ "/../lib/tools.jar");
System.out.println( "Add to CP: " + urls[jarCount] );
ClassLoader parentL=this.getClass().getClassLoader();
@@ -325,13 +326,27 @@
}
// -------------------- Command-line args processing --------------------
+ static class Arg {
+ String name;
+ String aliases[];
+ int args;
+
+ boolean task;
+
+
+ }
+ String args0[]= { "help", "stop" };
+ String args1[]= { "f", "config", "h", "home" };
+
/** Read command line arguments and set properties in proxy,
using ant-like patterns
*/
void processArgs(Object proxy, String args[] ) {
for( int i=0; i< args.length; i++ ) {
-
+ String arg=args[i];
+
+
}
}
1.2 +4 -3 jakarta-tomcat/src/share/org/apache/tomcat/util/net/PoolTcpEndpoint.java
Index: PoolTcpEndpoint.java
===================================================================
RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/net/PoolTcpEndpoint.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- PoolTcpEndpoint.java 2000/08/14 21:54:37 1.1
+++ PoolTcpEndpoint.java 2000/08/28 03:14:07 1.2
@@ -1,7 +1,7 @@
/*
- * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/net/PoolTcpEndpoint.java,v 1.1 2000/08/14 21:54:37 costin Exp $
- * $Revision: 1.1 $
- * $Date: 2000/08/14 21:54:37 $
+ * $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/net/PoolTcpEndpoint.java,v 1.2 2000/08/28 03:14:07 costin Exp $
+ * $Revision: 1.2 $
+ * $Date: 2000/08/28 03:14:07 $
*
* ====================================================================
*
@@ -65,6 +65,7 @@
package org.apache.tomcat.util.net;
import org.apache.tomcat.util.*;
+import org.apache.tomcat.util.threads.*;
import org.apache.tomcat.logging.*;
import java.io.*;
import java.net.*;
1.1 jakarta-tomcat/src/share/org/apache/tomcat/util/threads/Reaper.java
Index: Reaper.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.util.threads;
import org.apache.tomcat.util.*;
/**
* The reaper is a background thread with which ticks every minute
* and calls registered objects to allow reaping of old session
* data.
*
* @author James Duncan Davidson [duncan@eng.sun.com]
* @author Costin Manolache
*/
public class Reaper extends Thread {
public Reaper() {
this.setDaemon(true);
this.setName("TomcatReaper");
}
private int interval = 1000 * 60; //ms
// XXX TODO Allow per/callback interval, find next, etc
// Right now the "interval" is used for all callbacks
// and it represent a sleep between runs.
ThreadPoolRunnable cbacks[]=new ThreadPoolRunnable[30]; // XXX max
Object tdata[][]=new Object[30][]; // XXX max
int count=0;
/** Adding and removing callbacks is synchronized
*/
Object lock=new Object();
static boolean running=true;
public int addCallback( ThreadPoolRunnable c, int interval ) {
synchronized( lock ) {
cbacks[count]=c;
count++;
return count-1;
}
}
public void removeCallback( int idx ) {
synchronized( lock ) {
count--;
cbacks[idx]=cbacks[count];
cbacks[count]=null;
}
}
public void stopReaper() {
running=false;
this.notify();
}
public void run() {
while (running) {
try {
this.sleep(interval);
} catch (InterruptedException ie) {
// sometimes will happen
}
for( int i=0; i< count; i++ ) {
ThreadPoolRunnable callB=cbacks[i];
// it may be null if a callback is removed.
// I think the code is correct
if( callB!= null ) {
callB.runIt( tdata[i] );
}
}
}
}
}
1.1 jakarta-tomcat/src/share/org/apache/tomcat/util/threads/ThreadPool.java
Index: ThreadPool.java
===================================================================
/*
* $Header: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/threads/ThreadPool.java,v 1.1 2000/08/28 03:14:09 costin Exp $
* $Revision: 1.1 $
* $Date: 2000/08/28 03:14:09 $
*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.util.threads;
import java.util.zip.*;
import java.net.*;
import java.util.*;
import java.io.*;
import org.apache.tomcat.logging.*;
/**
* A thread pool that is trying to copy the apache process management.
*
* @author Gal Shachor
*/
public class ThreadPool {
/*
* Default values ...
*/
public static final int MAX_THREADS = 100;
public static final int MAX_SPARE_THREADS = 50;
public static final int MIN_SPARE_THREADS = 10;
public static final int WORK_WAIT_TIMEOUT = 60*1000;
/*
* Where the threads are held.
*/
protected Vector pool;
/*
* A monitor thread that monitors the pool for idel threads.
*/
protected MonitorRunnable monitor;
/*
* Max number of threads that you can open in the pool.
*/
protected int maxThreads;
/*
* Min number of idel threads that you can leave in the pool.
*/
protected int minSpareThreads;
/*
* Max number of idel threads that you can leave in the pool.
*/
protected int maxSpareThreads;
/*
* Number of threads in the pool.
*/
protected int currentThreadCount;
/*
* Number of busy threads in the pool.
*/
protected int currentThreadsBusy;
/*
* Flag that the pool should terminate all the threads and stop.
*/
protected boolean stopThePool;
static int debug=0;
/**
* Helper object for logging
**/
Logger.Helper loghelper = new Logger.Helper("tc_log", "ThreadPool");
public ThreadPool() {
maxThreads = MAX_THREADS;
maxSpareThreads = MAX_SPARE_THREADS;
minSpareThreads = MIN_SPARE_THREADS;
currentThreadCount = 0;
currentThreadsBusy = 0;
stopThePool = false;
}
public synchronized void start() {
adjustLimits();
openThreads(minSpareThreads);
monitor = new MonitorRunnable(this);
}
public void setMaxThreads(int maxThreads) {
this.maxThreads = maxThreads;
}
public int getMaxThreads() {
return maxThreads;
}
public void setMinSpareThreads(int minSpareThreads) {
this.minSpareThreads = minSpareThreads;
}
public int getMinSpareThreads() {
return minSpareThreads;
}
public void setMaxSpareThreads(int maxSpareThreads) {
this.maxSpareThreads = maxSpareThreads;
}
public int getMaxSpareThreads() {
return maxSpareThreads;
}
//
// You may wonder what you see here ... basically I am trying
// to maintain a stack of threads. This way locality in time
// is kept and there is a better chance to find residues of the
// thread in memory next time it runs.
//
/**
* Executes a given Runnable on a thread in the pool, block if needed.
*/
public void runIt(ThreadPoolRunnable r) {
if(null == r) {
throw new NullPointerException();
}
if(0 == currentThreadCount || stopThePool) {
throw new IllegalStateException();
}
ControlRunnable c = null;
// Obtain a free thread from the pool.
synchronized(this) {
if(currentThreadsBusy == currentThreadCount) {
// All threads are busy
if(currentThreadCount < maxThreads) {
// Not all threads were open,
// Open new threads up to the max number of idel threads
int toOpen = currentThreadCount + minSpareThreads;
openThreads(toOpen);
} else {
// Wait for a thread to become idel.
while(currentThreadsBusy == currentThreadCount) {
try {
this.wait();
}
// was just catch Throwable -- but no other
// exceptions can be thrown by wait, right?
// So we catch and ignore this one, since
// it'll never actually happen, since nowhere
// do we say pool.interrupt().
catch(InterruptedException e) {
loghelper.log("Unexpected exception", e);
}
// Pool was stopped. Get away of the pool.
if(0 == currentThreadCount || stopThePool) {
throw new IllegalStateException();
}
}
}
}
// If we are here it means that there is a free thred. Take it.
c = (ControlRunnable)pool.lastElement();
pool.removeElement(c);
currentThreadsBusy++;
}
c.runIt(r);
}
/**
* Stop the thread pool
*/
public synchronized void shutdown() {
if(!stopThePool) {
stopThePool = true;
monitor.terminate();
monitor = null;
for(int i = 0 ; i < (currentThreadCount - currentThreadsBusy) ; i++) {
try {
((ControlRunnable)(pool.elementAt(i))).terminate();
} catch(Throwable t) {
/*
* Do nothing... The show must go on, we are shutting
* down the pool and nothing should stop that.
*/
loghelper.log("Ignored exception while shutting down thread pool", t, Logger.ERROR);
}
}
currentThreadsBusy = currentThreadCount = 0;
pool = null;
notifyAll();
}
}
/**
* Called by the monitor thread to harvest idel threads.
*/
protected synchronized void checkSpareControllers() {
if(stopThePool) {
return;
}
if((currentThreadCount - currentThreadsBusy) > maxSpareThreads) {
int toFree = currentThreadCount -
currentThreadsBusy -
maxSpareThreads;
for(int i = 0 ; i < toFree ; i++) {
ControlRunnable c = (ControlRunnable)pool.firstElement();
pool.removeElement(c);
c.terminate();
currentThreadCount --;
}
}
}
/**
* Returns the thread to the pool.
* Called by threads as they are becoming idel.
*/
protected synchronized void returnController(ControlRunnable c) {
if(0 == currentThreadCount || stopThePool) {
c.terminate();
return;
}
currentThreadsBusy--;
pool.addElement(c);
notify();
}
/**
* Inform the pool that the specific thread finish.
*
* Called by the ControlRunnable.run() when the runnable
* throws an exception.
*/
protected synchronized void notifyThreadEnd(ControlRunnable c) {
currentThreadsBusy--;
currentThreadCount --;
notify();
}
/*
* Checks for problematic configuration and fix it.
* The fix provides reasonable settings for a single CPU
* with medium load.
*/
protected void adjustLimits() {
if(maxThreads <= 0) {
maxThreads = MAX_THREADS;
}
if(maxSpareThreads >= maxThreads) {
maxSpareThreads = maxThreads;
}
if(maxSpareThreads <= 0) {
if(1 == maxThreads) {
maxSpareThreads = 1;
} else {
maxSpareThreads = maxThreads/2;
}
}
if(minSpareThreads > maxSpareThreads) {
minSpareThreads = maxSpareThreads;
}
if(minSpareThreads <= 0) {
if(1 == maxSpareThreads) {
minSpareThreads = 1;
} else {
minSpareThreads = maxSpareThreads/2;
}
}
}
protected void openThreads(int toOpen) {
if(toOpen > maxThreads) {
toOpen = maxThreads;
}
if(0 == currentThreadCount) {
pool = new Vector(toOpen);
}
for(int i = currentThreadCount ; i < toOpen ; i++) {
pool.addElement(new ControlRunnable(this));
}
currentThreadCount = toOpen;
}
void log( String s ) {
loghelper.log(s);
}
/**
* Periodically execute an action - cleanup in this case
*/
class MonitorRunnable implements Runnable {
ThreadPool p;
Thread t;
boolean shouldTerminate;
MonitorRunnable(ThreadPool p) {
shouldTerminate = false;
this.p = p;
t = new Thread(this);
t.start();
}
public void run() {
while(true) {
try {
// Sleep for a while.
synchronized(this) {
this.wait(WORK_WAIT_TIMEOUT);
}
// Check if should terminate.
// termination happens when the pool is shutting down.
if(shouldTerminate) {
break;
}
// Harvest idle threads.
p.checkSpareControllers();
} catch(Throwable t) {
loghelper.log("Unexpected exception", t, Logger.ERROR);
}
}
}
/** Stop the monitor
*/
public synchronized void terminate() {
shouldTerminate = true;
this.notify();
}
}
/**
* A Thread object that executes various actions ( ThreadPoolRunnable )
* under control of ThreadPool
*/
class ControlRunnable implements Runnable {
/**
* ThreadPool where this thread will be returned
*/
ThreadPool p;
/**
* The thread that executes the actions
*/
Thread t;
/**
* The method that is executed in this thread
*/
ThreadPoolRunnable toRun;
/**
* Stop this thread
*/
boolean shouldTerminate;
/**
* Activate the execution of the action
*/
boolean shouldRun;
/**
* Per thread data - can be used only if all actions are
* of the same type.
* A better mechanism is possible ( that would allow association of
* thread data with action type ), but right now it's enough.
*/
boolean noThData;
Object thData[]=null;
/**
* Start a new thread, with no method in it
*/
ControlRunnable(ThreadPool p) {
toRun = null;
shouldTerminate = false;
shouldRun = false;
this.p = p;
t = new Thread(this);
t.start();
noThData=true;
thData=null;
}
public void run() {
while(true) {
try {
/* Wait for work. */
synchronized(this) {
if(!shouldRun && !shouldTerminate) {
this.wait();
}
}
if(toRun == null ) {
if( p.debug>0) p.log( "No toRun ???");
}
if( shouldTerminate ) {
if( p.debug>0) p.log( "Terminate");
break;
}
/* Check if should execute a runnable. */
try {
if(noThData) {
if(p.debug>0) p.log( "Getting new thread data");
thData=toRun.getInitData();
noThData = false;
}
if(shouldRun) {
toRun.runIt(thData);
}
} catch(Throwable t) {
loghelper.log("Caught exception executing " + toRun.toString() + ", terminating thread", t);
/*
* The runnable throw an exception (can be even a ThreadDeath),
* signalling that the thread die.
*
* The meaning is that we should release the thread from
* the pool.
*/
shouldTerminate = true;
shouldRun = false;
p.notifyThreadEnd(this);
} finally {
if(shouldRun) {
shouldRun = false;
/*
* Notify the pool that the thread is now idle.
*/
p.returnController(this);
}
}
/*
* Check if should terminate.
* termination happens when the pool is shutting down.
*/
if(shouldTerminate) {
break;
}
} catch(InterruptedException ie) { /* for the wait operation */
// can never happen, since we don't call interrupt
loghelper.log("Unexpected exception", ie);
}
}
}
public synchronized void runIt(ThreadPoolRunnable toRun) {
if( toRun == null ) {
throw new NullPointerException("No Runnable");
}
this.toRun = toRun;
shouldRun = true;
this.notify();
}
public synchronized void terminate() {
shouldTerminate = true;
this.notify();
}
}
}
1.1 jakarta-tomcat/src/share/org/apache/tomcat/util/threads/ThreadPoolRunnable.java
Index: ThreadPoolRunnable.java
===================================================================
/*
* ====================================================================
*
* The Apache Software License, Version 1.1
*
* Copyright (c) 1999 The Apache Software Foundation. All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution, if
* any, must include the following acknowlegement:
* "This product includes software developed by the
* Apache Software Foundation (http://www.apache.org/)."
* Alternately, this acknowlegement may appear in the software itself,
* if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
* Foundation" must not be used to endorse or promote products derived
* from this software without prior written permission. For written
* permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
* nor may "Apache" appear in their names without prior written
* permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation. For more
* information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*
* [Additional notices, if required by prior licensing conditions]
*
*/
package org.apache.tomcat.util.threads;
import java.util.zip.*;
import java.net.*;
import java.util.*;
import java.io.*;
/** Implemented if you want to run a piece of code inside a thread pool.
*/
public interface ThreadPoolRunnable {
// XXX use notes or a hashtable-like
// Important: ThreadData in JDK1.2 is implemented as a Hashtable( Thread -> object ),
// expensive.
/** Called when this object is first loaded in the thread pool.
* Important: all workers in a pool must be of the same type,
* otherwise the mechanism becomes more complex.
*/
public Object[] getInitData();
/** This method will be executed in one of the pool's threads. The
* thread will be returned to the pool.
*/
public void runIt(Object thData[]);
}