/* * Sun Public License * * The contents of this file are subject to the Sun Public License Version * 1.0 (the "License"). You may not use this file except in compliance with * the License. A copy of the License is available at http://www.sun.com/ * * The Original Code is the SLAMD Distributed Load Generation Engine. * The Initial Developer of the Original Code is Neil A. Wilson. * Portions created by Neil A. Wilson are Copyright (C) 2004-2010. * Some preexisting portions Copyright (C) 2002-2006 Sun Microsystems, Inc. * All Rights Reserved. * * Contributor(s): Neil A. Wilson */ package com.slamd.loadvariance; import java.util.Arrays; /** * This class defines a thread that is used to keep track of when the actual job * threads should start and stop their processing (which may need to happen * several times over the course of a job). It does this by setting boolean * variables that the job should watch in order to determine whether it should * currently be running. */ public class LoadVarianceControlThread extends Thread { // Indicates whether a request has been received for this thread to start. private boolean startRequested; // Indicates whether a request has been received for this thread stop stop. private boolean stopRequested; // The load variance job instance that this control thread should manage. private LoadVarianceJobClass jobClass; /** * Creates a new instance of this load variance control thread that will be * used to manage the provided job class. * * @param jobClass The job class that this control thread will manage. */ public LoadVarianceControlThread(LoadVarianceJobClass jobClass) { this.jobClass = jobClass; setName("Load Variance Control Thread"); startRequested = false; stopRequested = false; } /** * Sets a flag that indicates that the control thread should start managing * the job. */ public void startRunning() { startRequested = true; } /** * Sets a flag that indicates that the control thread should stop managing the * job. */ public void stopRunning() { stopRequested = true; // Make sure to signal any the remaining threads that they should stop. Arrays.fill(jobClass.threadsActive, false); } /** * Waits for the actual job to start, then sets flags that will be read by * that job to indicate whether a given thread should be started or stopped. */ public void run() { // If there are no lines in the load distribution file, then we can simply // turn on all the threads and exit right away. if ((jobClass.varianceData == null) || (jobClass.varianceData.length == 0)) { Arrays.fill(jobClass.threadsActive, true); return; } // Wait until we either get a request to start or stop running. while (! (startRequested || stopRequested || jobClass.shouldStop())) { try { Thread.sleep(10); } catch (Exception e) {} } // Loop until we get a request to stop. int activeThreads = 0; int maxThreads = jobClass.getClientSideJob().getThreadsPerClient(); int slotPos = 0; long jobStartTime = System.currentTimeMillis(); long nextOpTime = jobStartTime + jobClass.varianceData[0][0]; while (! (stopRequested || jobClass.shouldStop())) { long now = System.currentTimeMillis(); if (now >= nextOpTime) { // It is time to start or stop the next thread or set of threads. int numThreads = jobClass.varianceData[slotPos++][1]; if (numThreads > 0) { // We need to start one or more threads. for (int i=0; ((i < numThreads) && (activeThreads < maxThreads)); i++) { jobClass.threadsActive[activeThreads++] = true; } } else { // We need to stop one or more threads. for (int i=numThreads; ((i < 0) && (activeThreads > 0)); i++) { jobClass.threadsActive[--activeThreads] = false; } } // Now figure out how long it should be before we do the next round of // start/stop. If there is no more work to do, then exit. if (slotPos >= jobClass.varianceData.length) { if (jobClass.loopVarianceDefinition) { slotPos = 0; jobStartTime = System.currentTimeMillis(); nextOpTime = jobStartTime + jobClass.varianceData[0][0]; } else { return; } } else { nextOpTime = jobStartTime + jobClass.varianceData[slotPos][0]; } } else if ((nextOpTime + 100) > now) { // We have less than 100 milliseconds before the next thread should be // started. Sleep just for that length of time. try { Thread.sleep(nextOpTime - now); } catch (Exception e) {} } else { // We have at least 100 milliseconds before the next thread should be // started. Just sleep for 100 milliseconds at a time so that we can // detect and respond to cancel requests and other kinds of job // termination quickly. try { Thread.sleep(100); } catch (Exception e) {} } } // Make sure to signal any the remaining threads that they should stop. Arrays.fill(jobClass.threadsActive, false); } }