tomcat-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From cos...@locus.apache.org
Subject cvs commit: jakarta-tomcat/src/share/org/apache/tomcat/util/threads Reaper.java ThreadPool.java ThreadPoolRunnable.java
Date Mon, 28 Aug 2000 03:14:09 GMT
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[]);
  
  }
  
  
  

Mime
View raw message