/** * SAMOA - PROTOCOL FRAMEWORK * Copyright (C) 2005 Olivier Rütti (EPFL) (olivier.rutti@a3.epfl.ch) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package seqSamoa; import java.io.File; import java.util.LinkedList; import java.util.logging.FileHandler; import java.util.logging.Level; import java.util.logging.Logger; import seqSamoa.exceptions.InterruptedSchedulerException; import seqSamoa.exceptions.NotInAComputationException; import framework.CompressedLongSet; /** * This manager allows only sequential runs. */ public class SequentialManager implements ConcurrencyManager, Runnable { // This class represents a computation private static class Computation { /* The computation ID in which the task is executed*/ public long cID; /* The task currently executed by the computation*/ public AtomicTask currentTask; /* Sorted internal tasks */ public LinkedList<AtomicTask> readyTasks = new LinkedList<AtomicTask>(); /* Internal Tasks not yet sorted */ public LinkedList<AtomicTask> initiatedTasks = new LinkedList<AtomicTask>(); public Computation(long cID) { this.cID = cID; } } // List of tasks scheduled private LinkedList<Computation> scheduledComputations = new LinkedList<Computation>(); // List of tasks handled private CompressedLongSet finishedComputations = new CompressedLongSet(); // Has the scheduler to be closed private boolean toBeClosed = false; // The computation currently being executed protected Computation currentComputation; // The next computation id available private long nextComputationID = 0; // The Thread that runs the sequential Manager private Thread runner; public SequentialManager() { super(); } /** * This method returns only when all the {@link seqSamoa.Service service} calls and response * that causally depends on the external {@link seqSamoa.Service service} * call or response identified by cid are executed. * * @param cID * the id of the corresponding external {@link seqSamoa.Service service} * call or response we want to wait the end * */ synchronized public void waitEnd(long cID) throws InterruptedSchedulerException { while (!finishedComputations.contains(cID)) { try { wait(); } catch (InterruptedException ie) { throw new InterruptedSchedulerException(cID); } } } // Schedule a new computation (i.e., a new external call or response) synchronized public long addExternalTask(AtomicTask task) { // Create the computation and add it to scheduled computation Computation c = new Computation(this.nextComputationID); c.readyTasks.addLast(task); this.scheduledComputations.addLast(c); // Increment cID for the following computation this.nextComputationID++; notifyAll(); return c.cID; } // Schedule a new internal call or response synchronized public void addInternalTask(AtomicTask task) throws NotInAComputationException { if (!Thread.currentThread().equals(this.runner)) throw new NotInAComputationException(""); currentComputation.initiatedTasks.addLast(task); // Set the module that initiate the task task.triggeringModule = currentComputation.currentTask.currentModule; } // Returns the current atomic task public AtomicTask currentTask() { if (this.currentComputation != null) return this.currentComputation.currentTask; else return null; } // Schedule a new atomic task synchronized public long scheduleAtomicTask(AtomicTask task) { // Create the computation and add it to scheduled computation Computation c = new Computation(this.nextComputationID); c.readyTasks.addLast(task); this.scheduledComputations.addLast(c); // Increment cID for the following computation this.nextComputationID++; notifyAll(); return c.cID; } public void start() { this.runner = new Thread(this); runner.start(); } synchronized public void close() { toBeClosed = true; notifyAll(); } public void run() { while (true) { synchronized (this) { while ((this.scheduledComputations.isEmpty()) && (!this.toBeClosed)) { try { wait(); } catch (InterruptedException ex) { throw new RuntimeException("Scheduler interrupted"); } } if (this.toBeClosed) return; this.currentComputation = this.scheduledComputations.removeFirst(); } while (!this.currentComputation.readyTasks.isEmpty()) { this.currentComputation.currentTask = this.currentComputation.readyTasks.removeFirst(); this.currentComputation.currentTask.execute(); // Sort the initiated Tasks after finishing executing of current tasks // The sort is done according to the extended causal order property int size = this.currentComputation.readyTasks.size(); int startI = 0; while (!this.currentComputation.initiatedTasks.isEmpty()) { AtomicTask initiatedTask = this.currentComputation.initiatedTasks.removeFirst(); int index = startI; if (initiatedTask.triggeringModule != null) { for (int i = startI; i < size; i++) { AtomicTask sTaskTmp = this.currentComputation.readyTasks.get(i); if (initiatedTask.triggeringModule.equals(sTaskTmp.triggeringModule)) index = i + 1; } } this.currentComputation.readyTasks.add(index, initiatedTask); startI = index + 1; } } synchronized(this) { this.finishedComputations.add(currentComputation.cID); this.currentComputation = null; this.notifyAll(); } } } public void stackReconfigured(ProtocolStack stack) { // Nothing has to be done } }