[Tinyos-contrib-commits]
CVS: tinyos-1.x/contrib/ustutt/ncunit/java/avrora/sim/clock
ClockPrescaler.java, NONE, 1.1 Synchronizer.java, NONE,
1.1 DerivedClock.java, NONE, 1.1 ClockDomain.java, NONE,
1.1 Clock.java, NONE, 1.1 SystemClock.java, NONE,
1.1 DeltaQueue.java, NONE, 1.1 MainClock.java, NONE,
1.1 StepSynchronizer.java, NONE, 1.1 IntervalSynchronizer.java,
NONE, 1.1
Andreas Lachenmann
lachenmann at users.sourceforge.net
Tue Feb 20 04:33:06 PST 2007
- Previous message: [Tinyos-contrib-commits]
CVS: tinyos-1.x/contrib/ustutt/ncunit/java/ncunit/avrora
NCUnitMonitor.java, NONE, 1.1 DebugOutputMonitor.java, NONE,
1.1 NCAssert.java, NONE, 1.1
- Next message: [Tinyos-contrib-commits] CVS: tinyos-1.x/contrib/ustutt/ncunit/mote
Assert.nc, NONE, 1.1 AssertM.nc, NONE, 1.1 ncunit.h, NONE,
1.1 debug_gcc.h, NONE, 1.1 dbg.h, NONE, 1.1 debugoutput.h,
NONE, 1.1 AssertC.nc, NONE, 1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /cvsroot/tinyos/tinyos-1.x/contrib/ustutt/ncunit/java/avrora/sim/clock
In directory sc8-pr-cvs10.sourceforge.net:/tmp/cvs-serv4808/contrib/ustutt/ncunit/java/avrora/sim/clock
Added Files:
ClockPrescaler.java Synchronizer.java DerivedClock.java
ClockDomain.java Clock.java SystemClock.java DeltaQueue.java
MainClock.java StepSynchronizer.java IntervalSynchronizer.java
Log Message:
added files to repository
--- NEW FILE: ClockPrescaler.java ---
/**
* Copyright (c) 2004-2005, Regents of the University of California
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the University of California, Los Angeles nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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 COPYRIGHT
* OWNER OR 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.
*/
package avrora.sim.clock;
import avrora.sim.Simulator;
/**
* The <code>ClockPrescaler</code> class represents a clock that is another clock scaled appropriately; e.g.
* 8x slower.
*
* @author Ben L. Titzer
*/
public class ClockPrescaler extends Clock {
/**
* The <code>driveClock</code> field stores a reference to the clock that the prescaler is derived from.
*/
protected final Clock driveClock;
/**
* The <code>divider</code> stores the number of cycles of the underlying clock are equivalent to one
* cycle of this clock. For example, with a divider or 8, the underlying clock ticks 8 times for each tick
* of this clock.
*/
protected final int divider;
/**
* The <code>base</code> field stores the cycle count of the underlying clock at the last time that this
* clock was reset.
*/
protected long base;
/**
* The <code>ticksBeforeBase</code> field stores the number of ticks that were recorded before the
* prescaler was reset. This is used in the calculation of the total number of ticks that have elapsed.
*/
protected long ticksBeforeBase;
/**
* The constructor of the <code>ClockPrescaler</code> creates a new clock that is an integer multiple
* slower than the clock that it is derived from. Additionally, the phase at which this clock fires can be
* adjusted by resetting.
*
* @param n the name of the new clock
* @param drive the clock that drives this derived clock
* @param divider the muliple by which the derived clock is slower than the source
*/
public ClockPrescaler(String n, Clock drive, int divider) {
super(n, drive.getHZ() / divider);
driveClock = drive;
this.divider = divider;
}
/**
* The <code>getCount()</code> method returns the number of clock cycles (ticks) that have elapsed for
* this clock. In the implementation of the <code>ClockPrescaler</code>, this method calculates the number
* of scaled cycles since the last reset.
*
* @return the number of elapsed time ticks in clock cycles
*/
public long getCount() {
return (driveClock.getCount() - base) / divider;
}
/**
* The <code>getTotalCount()</code> method returns the total number of clock cycles (ticks) that have
* elapsed for this clock. In the implementation of the <code>ClockPrescaler</code>, this method
* calculates the number of scaled cycles since the last reset, plus the number of ticks elapsed before
* the reset.
*
* @return the number of elapsed time ticks in clock cycles
*/
public long getTotalCount() {
return getCount() + ticksBeforeBase;
}
/**
* The <code>insertEvent()</code> method inserts an event into the event queue of the clock with the
* specified delay in clock cycles. The event will then be executed at the future time specified. In the
* implementation of <code>ClockPrescaler</code>, the event will be scheduled in the underlying clock,
* with the delay calculated correctly from the last time that the prescaler was reset.
*
* @param e the event to be inserted
* @param delta the number of (scaled) cycles in the future at which to fire
*/
public void insertEvent(Simulator.Event e, long delta) {
long driverCount = driveClock.getCount() - base;
long nextTick = ((driverCount / divider) + 1) * divider;
driveClock.insertEvent(e, nextTick - driverCount);
}
/**
* The <code>removeEvent()</code> method removes an event from the event queue of the clock. The
* comparison used is reference equality, not <code>.equals()</code>.
*
* @param e the event to remove
*/
public void removeEvent(Simulator.Event e) {
driveClock.removeEvent(e);
}
/**
* The <code>reset()</code> method resets the internal clock prescaler to zero. Thus, the prescaler's
* previous phase is broken, and the clock signal continues with the same frequency, only that the first
* tick will happen <code>divider</code> cycles from now.
*/
public void reset() {
long newbase = driveClock.getCount();
long diff = newbase - base;
ticksBeforeBase += diff / divider;
base = newbase;
}
}
--- NEW FILE: Synchronizer.java ---
/**
* Copyright (c) 2004-2005, Regents of the University of California
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the University of California, Los Angeles nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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 COPYRIGHT
* OWNER OR 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.
*/
package avrora.sim.clock;
import avrora.sim.Simulation;
/**
* The <code>Synchronizer</code> class represents an object that controls the progress
* of a multi-node simulation. The synchronizer preserves the timing and order of events
* that influence other nodes' actions (e.g. communication). Since there are multiple
* strategies for doing this, this class abstracts the actual mechanism so that clients
* can simply create the appropriate synchronizer for their simulation.
*
* @author Ben L. Titzer
*/
public abstract class Synchronizer {
/**
* The <code>addNode()</code> method adds a node to this synchronization group.
* This method should only be called before the <code>start()</code> method is
* called.
* @param n the simulator representing the node to add to this group
*/
public abstract void addNode(Simulation.Node n);
/**
* The <code>removeNode()</code> method removes a node from this synchronization
* group, and wakes any nodes that might be waiting on it.
* @param n the simulator thread to remove from this synchronization group
*/
public abstract void removeNode(Simulation.Node n);
/**
* The <code>waitForNeighbors()</code> method is called from within the execution
* of a node when that node needs to wait for its neighbors to catch up to it
* in execution time. The node will be blocked until the other nodes in other
* threads catch up in global time.
*/
public abstract void waitForNeighbors(long time);
/**
* The <code>start()</code> method starts the threads executing, and the synchronizer
* will add whatever synchronization to their execution that is necessary to preserve
* the global timing properties of simulation.
*/
public abstract void start();
/**
* The <code>join()</code> method will block the caller until all of the threads in
* this synchronization interval have terminated, either through <code>stop()</code>
* being called, or terminating normally such as through a timeout.
*/
public abstract void join() throws InterruptedException;
/**
* The <code>pause()</code> method temporarily pauses the simulation. The nodes are
* not guaranteed to stop at the same global time. This method will return when all
* threads in the simulation have been paused and will no longer make progress until
* the <code>start()</code> method is called again.
*/
public abstract void pause();
/**
* The <code>stop()</code> method will terminate all the simulation threads. It is
* not guaranteed to stop all the simulation threads at the same global time.
*/
public abstract void stop();
/**
* The <code>synch()</code> method will pause all of the nodes at the same global time.
* This method can only be called when the simulation is paused. It will run all threads
* forward until the global time specified and pause them.
* @param globalTime the global time in clock cycles to run all threads ahead to
*/
public abstract void synch(long globalTime);
}
--- NEW FILE: DerivedClock.java ---
/**
* Copyright (c) 2004-2005, Regents of the University of California
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the University of California, Los Angeles nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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 COPYRIGHT
* OWNER OR 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.
*/
package avrora.sim.clock;
import avrora.sim.Simulator;
import cck.util.Util;
/**
* The <code>DerivedClock</code> class represents a clock that is derived from another clock; i.e. the derived
* clock runs slower but is synchronized with the clock that it is derived from. An example is the 32khz real
* time clock on the Mica2--it runs independently of the main clock, but in the simulation, it uses the
* main clock signal to synchronize its execution to the execution of the program.
*
* @author Ben L. Titzer
*/
public class DerivedClock extends Clock {
/**
* The <code>driveClock</code> field stores a reference to the clock that is underlying this derived
* clock.
*/
protected final Clock driveClock;
/**
* The <code>divider</code> stores a the ration between the clockspeed of the drive clock and the
* clockspeed of this clock.
*/
protected final double divider;
/**
* The constructor of the <code>DerivedClock</code> creates a new clock with the specified name, driven by
* the specified clock, with the specified clockrate. The derived clock can have any speed that is slower
* than the clock that it is derived from. Roundoff errors will happen when the rates are not an integer
* multiple of each other, but are guaranteed never to exceed 1 cycle of the underlying clock.
*
* @param n the name of the clock
* @param driver the clock source from which this clock is derived
* @param hz the number of cycles per second of this clock
*/
public DerivedClock(String n, Clock driver, long hz) {
super(n, hz);
this.driveClock = driver;
if (driver.getHZ() < hz)
throw Util.failure("cannot derive faster clock from slower clock");
divider = driver.getHZ() / hz;
}
/**
* The <code>getCount()</code> method returns the total count of clock ticks that have happened for this
* clock. Since this clock is a derived clock, it computes the number of clock cycles that have happened
* based on the number of clock cycles that have happened for the underlying clock from which it is
* derived.
*
* @return the count in cycles of this clock
*/
public long getCount() {
return (long)(driveClock.getCount() / divider);
}
/**
* The <code>insertEvent()</code> method inserts an event into the event queue of the clock with the
* specified delay in clock cycles. The event will then be executed at the future time specified.
*
* @param e the event to be inserted
* @param delta the number of cycles in the future at which to event
*/
public void insertEvent(Simulator.Event e, long delta) {
long driverCount = driveClock.getCount();
long nextTick = (long)(((long)(driverCount / divider) + delta) * divider);
driveClock.insertEvent(e, nextTick - driverCount);
}
/**
* The <code>removeEvent()</code> method removes an event from the event queue of the clock. The
* comparison used is reference equality, not <code>.equals()</code>.
*
* @param e the event to remove
*/
public void removeEvent(Simulator.Event e) {
driveClock.removeEvent(e);
}
}
--- NEW FILE: ClockDomain.java ---
/**
* Copyright (c) 2004-2005, Regents of the University of California
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the University of California, Los Angeles nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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 COPYRIGHT
* OWNER OR 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.
*/
package avrora.sim.clock;
import java.util.HashMap;
import java.util.NoSuchElementException;
import avrora.util.StringUtil;
/**
* The <code>ClockDomain</code> class represents a collection of clocks for a device or platform,
* including the main clock used for the microcontroller.
*
* @author Ben L. Titzer
*/
public class ClockDomain {
protected final HashMap clockMap;
protected final MainClock mainClock;
/**
* The constructor for the <code>ClockDomain</code> class constructs the main clock (from which
* all other clocks are derived). It accepts as a parameter the speed of the main clock.
* @param mainHz the speed of the main clock in cycles per second
*/
public ClockDomain(long mainHz) {
clockMap = new HashMap();
mainClock = new MainClock("main", mainHz);
clockMap.put("main", mainClock);
}
/**
* The <code>getMainClock()</code> method returns the main clock for this clock domain.
* @return an instance of the <code>MainClock</code> class that contains the main clock for
* this clock domain.
*/
public MainClock getMainClock() {
return mainClock;
}
/**
* The <code>getClock()</code> method looks for a clock with the specified name in this clock
* domain.
* @param name the name of the clock as a string
* @return an instance of the <code>Clock</code> interface for the specified clock name
* @throws NoSuchElementException if no clock with the specified name exists in this domain
*/
public Clock getClock(String name) {
Clock clock = (Clock)clockMap.get(name);
if ( clock == null )
throw new NoSuchElementException(StringUtil.quote(name)+" clock not found");
return clock;
}
/**
* The <code>addClock()</code> method adds a clock to this clock domain. It will be indexed
* by the name returned by the clock's <code>getName()</code> method. If there is a clock
* already in this domain with the name specified, the new clock will be returned for subsequent
* calls to <code>getClock()</code>, and the old clock will no longer be accessible.
* @param c the clock to add to this domain
*/
public void addClock(Clock c) {
clockMap.put(c.getName(), c);
}
/**
* The <code>newClock()</code> method creates a new clock derived from the main clock of
* this clock domain with the given name and clockspeed. The clock will automatically be
* added to this clock domain with the specified name.
* @param name the name of the new clock
* @param hz the clockspeed of the new clock in cycles per second
* @return a new <code>Clock</code> instance with the specified properties
*/
public Clock newClock(String name, long hz) {
if ( hz == mainClock.getHZ() ) {
clockMap.put(name, mainClock);
return mainClock;
}
DerivedClock c = new DerivedClock(name, mainClock, hz);
addClock(c);
return c;
}
/**
* The <code>hasClock()</code> method queries the clock domain whether it contains a particular
* named clock.
* @param name the name of the clock to check for
* @return true if a clock in this domain exists with the specified name; false otherwise
*/
public boolean hasClock(String name) {
return clockMap.get(name) != null;
}
}
--- NEW FILE: Clock.java ---
/**
* Copyright (c) 2004-2005, Regents of the University of California
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the University of California, Los Angeles nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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 COPYRIGHT
* OWNER OR 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.
*/
package avrora.sim.clock;
import avrora.sim.Simulator;
/**
* The <code>Clock</code> class represents a clock within the simulation. There is one main clock for the
* Simulator itself, and all other clocks, even if they are not physically derived off the same clock signal,
* are simulated by inserting events into the main clock.
*
* @author Ben L. Titzer
*/
public abstract class Clock {
/**
* The <code>hz</code> field stores the rate of this clock in cycles per second.
*/
protected final long hz;
/**
* The <code>name</code> field stores the name of this clock as a string.
*/
protected final String name;
protected Clock(String n, long hz) {
this.hz = hz;
this.name = n;
}
/**
* The <code>getHZ()</code> method returns the number of cycles per second at which this clock runs.
*
* @return the number of cycles per second on this clock
*/
public long getHZ() {
return hz;
}
/**
* The <code>getName()</code> method returns the name of this clock source. Each clock has a name, so that
* they can be indexed in the simulator.
*
* @return the name of the clock as a string
*/
public String getName() {
return name;
}
/**
* The <code>getCount()</code> method returns the number of clock cycles (ticks) that have elapsed for
* this clock.
*
* @return the number of elapsed time ticks in clock cycles
*/
public abstract long getCount();
/**
* The <code>insertEvent()</code> method inserts an event into the event queue of the clock with the
* specified delay in clock cycles. The event will then be executed at the future time specified.
*
* @param e the event to be inserted
* @param cycles the number of cycles in the future at which to fire
*/
public abstract void insertEvent(Simulator.Event e, long cycles);
/**
* The <code>removeEvent()</code> method removes an event from the event queue of the clock. The
* comparison used is reference equality, not <code>.equals()</code>.
*
* @param e the event to remove
*/
public abstract void removeEvent(Simulator.Event e);
/**
* The <code>millisToCycles()</code> method converts the specified number of milliseconds to a cycle
* count. The conversion factor used is the number of cycles per second of this clock. This method serves
* as a utility so that clients need not do repeated work in converting milliseconds to cycles and back.
*
* @param ms a time quantity in milliseconds as a double
* @return the same time quantity in clock cycles, rounded up to the nearest integer
*/
public long millisToCycles(double ms) {
return (long)(ms * hz / 1000);
}
/**
* The <code>cyclesToMillis()</code> method converts the specified number of cycles to a time quantity in
* milliseconds. The conversion factor used is the number of cycles per second of this clock. This method
* serves as a utility so that clients need not do repeated work in converting milliseconds to cycles and
* back.
*
* @param cycles the number of cycles
* @return the same time quantity in milliseconds
*/
public double cyclesToMillis(long cycles) {
return 1000 * ((double)cycles) / hz;
}
}
--- NEW FILE: SystemClock.java ---
package avrora.sim.clock;
/**
* Copyright (c) 2004-2005, Regents of the University of California
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the University of California, Los Angeles nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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 COPYRIGHT
* OWNER OR 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.
*/
import avrora.sim.Simulator;
import cck.util.Util;
/**
* The <code>SystemClock</code> class represents a wrapper around the system clock that
* measures actual wall clock time passed in simulation. This implementation encapsulates
* the <code>System.currentTimeMillis()</code> method, and thus provides a precision
* of approximately 1000 cycles per second.
*
* @author Ben L. Titzer
*/
public class SystemClock extends Clock {
private static final SystemClock instance = new SystemClock();
private SystemClock() {
super("system", 1000);
}
/**
* The <code>get()</code> method retrieves the singleton instance of the system clock.
* @return an instance of the <code>SystemClock</code> class
*/
public static SystemClock get() {
return instance;
}
/**
* The <code>getCount()</code> method returns the number of clock cycles (ticks) that have elapsed for
* this clock.
*
* @return the number of elapsed time ticks in clock cycles
*/
public long getCount() {
return System.currentTimeMillis();
}
/**
* The <code>insertEvent()</code> method inserts an event into the event queue of the clock with the
* specified delay in clock cycles. The event will then be executed at the future time specified.
*
* @param e the event to be inserted
* @param cycles the number of cycles in the future at which to fire
*/
public void insertEvent(Simulator.Event e, long cycles) {
throw Util.unimplemented();
}
/**
* The <code>removeEvent()</code> method removes an event from the event queue of the clock. The
* comparison used is reference equality, not <code>.equals()</code>.
*
* @param e the event to remove
*/
public void removeEvent(Simulator.Event e) {
throw Util.unimplemented();
}
/**
* The <code>getFirstEventDelta()</code> method returns the number of clock cycles until
* the first event in the event queue will fire. This method will return -1 if there are no
* events in the queue.
* @return the delta in clock cycles of the first event in the queue; -1 if there are no
* events in the queue
*/
public long getFirstEventDelta() {
throw Util.unimplemented();
}
}
--- NEW FILE: DeltaQueue.java ---
/**
* Copyright (c) 2004-2005, Regents of the University of California
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the University of California, Los Angeles nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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 COPYRIGHT
* OWNER OR 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.
*/
package avrora.sim.clock;
import avrora.sim.Simulator;
/**
* The <code>DeltaQueue</code> class implements an amortized constant time delta-queue for processing of
* scheduled events. Events are put into the queue that will fire at a given number of cycles in the future.
* An internal delta list is maintained where each link in the list represents a set of events to be fired
* some number of clock cycles after the previous link.
* <p/>
* Each delta between links is maintained to be non-zero. Thus, to insert an event X cycles in the future, at
* most X nodes will be skipped over. Therefore, when the list is advanced over X time steps, this cost is
* amortized to be constant.
* <p/>
* For each clock cycle, only the first node in the list must be checked, leading to constant time work per
* clock cycle.
* <p/>
* This class allows the clock to be advanced multiple ticks at a time.
* <p/>
* Also, since this class is used heavily in the simulator, its performance is important and maintains an
* internal cache of objects. Thus, it does not create garbage over its execution and never uses more space
* than is required to store the maximum encountered simultaneous events. It does not use standard libraries,
* casts, virtual dispatch, etc.
*/
public class DeltaQueue {
/**
* The <code>EventList</code> class represents a link in the list of events for a given <code>Link</code>
* in the delta queue chain.
*/
private static class EventList {
Simulator.Event event;
EventList next;
/**
* The constructor for the <code>EventList</code> class simply initializes the internal references to
* the event and the next link in the chain based on the parameters passed.
*
* @param t a reference the event
* @param n the next link in the chain
*/
EventList(Simulator.Event t, EventList n) {
event = t;
next = n;
}
}
/**
* The <code>Link</code> class represents a link in the list of delta queue items that are being stored.
* It contains a list of events that share the same delta.
*/
private class Link {
EventList events;
Link next;
long delta;
Link(Simulator.Event t, long d) {
events = newEventList(t, null);
delta = d;
}
void add(Simulator.Event t) {
events = newEventList(t, events);
}
void remove(Simulator.Event t) {
EventList prev = null;
EventList pos = events;
while (pos != null) {
EventList next = pos.next;
if (pos.event == t) {
if (prev == null)
// remove the whole thing.
events = pos.next;
else
// remove the "pos" link
prev.next = pos.next;
free(pos);
} else {
prev = pos;
}
pos = next;
}
}
void fire() {
for (EventList pos = events; pos != null; pos = pos.next) {
pos.event.fire();
}
}
}
/**
* The <code>head</code> field stores a reference to the head of the delta queue, which represents the
* event that is nearest in the future.
*/
protected Link head;
/**
* The <code>freeLinks</code> field stores a reference to any free links that have become unused during
* the processing of events. A free list is used to prevent garbage from accumulating.
*/
protected Link freeLinks;
/**
* The <code>freeEventLists</code> field stores a reference to any free event links that have become
* unused during the processing of events. A free list is used to prevent garbage from accumulating.
*/
protected EventList freeEventLists;
/**
* The <code>count</code> field stores the total number of cycles that this queue has been advanced, i.e.
* the sum of all <code>advance()</code> calls.
*/
protected long count;
/**
* The <code>add</code> method adds an event to be executed in the future.
*
* @param t the event to add
* @param cycles the number of clock cycles in the future
*/
public void insertEvent(Simulator.Event t, long cycles) {
// degenerate case, nothing in the queue.
if (head == null) {
head = newLink(t, cycles, null);
return;
}
// search for first link that is "after" this cycle delta
Link prev = null;
Link pos = head;
while (pos != null && cycles > pos.delta) {
cycles -= pos.delta;
prev = pos;
pos = pos.next;
}
if (pos == null) {
// end of the head
insertAfter(prev, t, cycles, null);
} else if (cycles == pos.delta) {
// exactly matched the delta of some other event
pos.add(t);
} else {
// insert a new link in the chain
insertAfter(prev, t, cycles, pos);
}
}
private void insertAfter(Link prev, Simulator.Event t, long cycles, Link next) {
if (prev != null)
prev.next = newLink(t, cycles, next);
else
head = newLink(t, cycles, next);
}
/**
* The <code>remove</code> method removes all occurrences of the specified event within the delta queue.
*
* @param e the event to remove
*/
public void removeEvent(Simulator.Event e) {
if (head == null) return;
// search for first link that is "after" this cycle delta
Link prev = null;
Link pos = head;
while (pos != null) {
Link next = pos.next;
pos.remove(e);
if (pos.events == null) {
// the link became empty because of removing this event
if (prev == null)
head = pos.next;
else
prev.next = pos.next;
// fixes up the delta of the next item in the queue
if (pos.next != null) {
pos.next.delta += pos.delta;
}
free(pos);
} else {
// the link did not become empty, just move on
prev = pos;
}
// advance to next link in the list
pos = next;
}
}
/**
* The <code>advance</code> method advances timesteps through the queue by the specified number of clock
* cycles, processing any events.
*
* @param cycles the number of clock cycles to advance
*/
public void advance(long cycles) {
if ( head == null ) {
// fast path 1: nothing in the queue
count += cycles;
return;
}
if ( head.delta > cycles ) {
// fast path 2: head does not fire
count += cycles;
head.delta -= cycles;
return;
}
advanceSlow(cycles);
}
/**
* The <code>skipAhead()</code> method skips ahead to the next event in the queue and fires it.
*/
public void skipAhead() {
if ( head == null ) {
// fast path 1: nothing in the queue
count++;
return;
}
Link h = head;
count += h.delta;
head = h.next;
h.fire();
free(h);
}
private void advanceSlow(long cycles) {
// slow path: head (and maybe more) fires
while (head != null && cycles > 0) {
Link pos = head;
Link next = pos.next;
// cache pos.delta because it is used twice
long delta = pos.delta;
// number of cycles leftover after advancing by pos.delta
long leftover = cycles - delta;
// if haven't arrived yet, advance and return
if (leftover < 0) {
count += cycles;
pos.delta = -leftover;
return;
}
// advance by the number of cycles at the head of the queue
count += delta;
// chop off head
head = next;
// fire all events at head
pos.fire();
// free the head
free(pos);
// process leftover cycles next time through loop
cycles = leftover;
}
// add in leftover cycles if we reached end of queue (head == null)
count += cycles;
}
/**
* The <code>getHeadDelta()</code> method gets the number of clock cycles until the first event will
* fire.
*
* @return the number of clock cycles until the first event will fire
*/
public long getFirstEventTime() {
if (head != null) return head.delta;
return -1;
}
/**
* The <code>getCount()</code> gets the total cumulative count of all the <code>advance()</code> calls on
* this delta queue.
*
* @return the total number of cycles this queue has been advanced
*/
public long getCount() {
return count;
}
private void free(Link l) {
l.next = freeLinks;
freeLinks = l;
freeEventLists = l.events;
l.events = null;
}
private void free(EventList l) {
l.event = null;
l.next = freeEventLists;
freeEventLists = l;
}
private Link newLink(Simulator.Event t, long cycles, Link next) {
Link l;
if (freeLinks == null)
// if none in the free list, allocate one
l = new Link(t, cycles);
else {
// grab one from the free list
l = freeLinks;
freeLinks = freeLinks.next;
l.delta = cycles;
l.add(t);
}
// adjust delta in the next link in the chain
if (next != null) {
next.delta -= cycles;
}
l.next = next;
return l;
}
private EventList newEventList(Simulator.Event t, EventList next) {
EventList l;
if (freeEventLists == null) {
// no free links, so allocate one
l = new EventList(t, next);
} else {
// grab the first link off the free chain
l = freeEventLists;
freeEventLists = freeEventLists.next;
l.next = next;
l.event = t;
}
return l;
}
}
--- NEW FILE: MainClock.java ---
/**
* Copyright (c) 2004-2005, Regents of the University of California
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the University of California, Los Angeles nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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 COPYRIGHT
* OWNER OR 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.
*/
package avrora.sim.clock;
import avrora.sim.Simulator;
/**
* The <code>MainClock</code> class represents a clock that has an associated delta queue. This clock is
* meant as the main, or driving clock. Clocks that are derived from this class are kept in synch
* through the event queue. The <code>MainClock</code> is advanced by the interpreter for a node.
*
* @author Ben L. Titzer
*/
public class MainClock extends Clock {
/**
* The <code>eventQueue</code> field stores a reference to the event queue for this node.
*/
protected final DeltaQueue eventQueue;
/**
* The <code>MainClock()</code> method creates a main clock with the specified name and frequency.
* @param n the name of this clock
* @param hz the number of cycles per second for this clock
*/
public MainClock(String n, long hz) {
super(n, hz);
eventQueue = new DeltaQueue();
}
/**
* The <code>getCount()</code> method returns the number of clock cycles (ticks) that have elapsed for
* this clock.
*
* @return the number of elapsed time ticks in clock cycles
*/
public long getCount() {
return eventQueue.getCount();
}
/**
* The <code>insertEvent()</code> method inserts an event into the event queue of the clock with the
* specified delay in clock cycles. The event will then be executed at the future time specified.
*
* @param e the event to be inserted
* @param cycles the number of cycles in the future at which to fire
*/
public void insertEvent(Simulator.Event e, long cycles) {
eventQueue.insertEvent(e, cycles);
}
/**
* The <code>removeEvent()</code> method removes an event from the event queue of the clock. The
* comparison used is reference equality, not <code>.equals()</code>.
*
* @param e the event to remove
*/
public void removeEvent(Simulator.Event e) {
eventQueue.removeEvent(e);
}
/**
* The <code>advance()</code> method advances the time of the clock by the number of cycles. This may
* happen as the result of executing an instruction, sleeping for a time, delaying, etc. This method is
* only intended for use by the agent driving the clock; e.g. the simulator, and not a monitor or probe.
*
* @param cycles the number of cycles to advance the clock
*/
public void advance(long cycles) {
eventQueue.advance(cycles);
}
/**
* The <code>getFirstEventDelta()</code> method returns the number of clock cycles until
* the first event in the event queue will fire. This method will return -1 if there are no
* events in the queue.
* @return the delta in clock cycles of the first event in the queue; -1 if there are no
* events in the queue
*/
public long getFirstEventDelta() {
return eventQueue.getFirstEventTime();
}
/**
* The <code>skipAhead()</code> method skips ahead to the next event in the queue and fires it.
*/
public void skipAhead() {
eventQueue.skipAhead();
}
}
--- NEW FILE: StepSynchronizer.java ---
/**
* Copyright (c) 2004-2005, Regents of the University of California
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the University of California, Los Angeles nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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 COPYRIGHT
* OWNER OR 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.
*/
package avrora.sim.clock;
import avrora.sim.Simulation;
import avrora.sim.Simulator;
import cck.util.Util;
/**
* The <code>StepSynchronizer</code> class is an implementation of simulator synchronization
* that steps each node one cycle at a time using the <code>Simulator.step()</code> method
* of each simulator.
*
* @author Ben L. Titzer
*/
public class StepSynchronizer extends Synchronizer {
protected final Simulator.Event action;
protected Simulator[] threads;
protected int numThreads;
protected boolean shouldRun;
protected boolean innerLoop;
protected RunThread thread;
/**
* The constructor for the <code>StepSynchronizer</code> class creates a new instance
* of this synchronizer. The event passed as a parameter will be fired after each iteration;
* i.e. when all nodes have been stepped one clock cycle.
* @param e the event to fire after each step of the simulation
*/
public StepSynchronizer(Simulator.Event e) {
action = e;
threads = new Simulator[8];
}
/**
* The <code>addNode()</code> method adds a node to this synchronization group.
* This method should only be called before the <code>start()</code> method is
* called.
* @param n the simulator representing the node to add to this group
*/
public void addNode(Simulation.Node n) {
int nn = numThreads++;
if ( nn >= threads.length ) {
Simulator[] nthreads = new Simulator[threads.length * 2];
System.arraycopy(threads, 0, nthreads, 0, threads.length);
threads = nthreads;
}
threads[nn] = n.getSimulator();
}
/**
* The <code>removeNode()</code> method removes a node from this synchronization
* group, and wakes any nodes that might be waiting on it.
* @param n the simulator thread to remove from this synchronization group
*/
public void removeNode(Simulation.Node n) {
removeSimulator(n.getSimulator());
}
/**
* The <code>waitForNeighbors()</code> method is called from within the execution
* of a node when that node needs to wait for its neighbors to catch up to it
* in execution time. The node will be blocked until the other nodes in other
* threads catch up in global time.
*/
public void waitForNeighbors(long time) {
throw Util.unimplemented();
}
/**
* The <code>start()</code> method starts the threads executing, and the synchronizer
* will add whatever synchronization to their execution that is necessary to preserve
* the global timing properties of simulation.
*/
public void start() {
thread = new RunThread();
thread.start();
}
/**
* The <code>join()</code> method will block the caller until all of the threads in
* this synchronization interval have terminated, either through <code>stop()</code>
* being called, or terminating normally such as through a timeout.
*/
public void join() throws InterruptedException {
if ( thread != null )
thread.join();
}
/**
* The <code>pause()</code> method temporarily pauses the simulation. The nodes are
* not guaranteed to stop at the same global time. This method will return when all
* threads in the simulation have been paused and will no longer make progress until
* the <code>start()</code> method is called again.
*/
public void pause() {
if ( thread != null )
thread.pause();
}
/**
* The <code>stop()</code> method will terminate all the simulation threads. It is
* not guaranteed to stop all the simulation threads at the same global time.
*/
public void stop() {
if ( thread == null ) return;
shouldRun = false;
innerLoop = false;
try {
thread.join();
} catch ( InterruptedException e) {
// do nothing.
}
}
/**
* The <code>RunThread</code> class implements a thread that runs the simulation, to preserve
* the model that the thread interacting with the synchronizer through calls to
* <code>start()</code>, stop()</code>, etc. is different than any of the
* threads running actual simulator code.
*/
protected class RunThread extends Thread {
public void run() {
shouldRun = true;
runLoop();
}
protected void runLoop() {
int[] cycles = new int[numThreads];
while ( shouldRun ) {
fastLoop(cycles);
}
}
private void fastLoop(int[] cycles) {
innerLoop = true;
while ( innerLoop )
step(cycles, threads);
}
protected void step(int[] cycles, Simulator[] threads) {
for ( int cntr = 0; cntr < numThreads; cntr++ ) {
int left = --cycles[cntr];
if ( left <= 0 ) {
Simulator sim = threads[cntr];
try {
cycles[cntr] = sim.step();
} catch ( Throwable t) {
reportExit(sim, t);
removeSimulator(threads[cntr]);
}
}
}
// Execute the event if there is one.
if ( action != null)
action.fire();
}
public void pause() {
throw Util.unimplemented();
}
}
void reportExit(Simulator s, Throwable t) {
throw Util.unimplemented();
}
void removeSimulator(Simulator s) {
throw Util.unimplemented();
}
/**
* The <code>synch()</code> method will pause all of the nodes at the same global time.
* This method can only be called when the simulation is paused. It will run all threads
* forward until the global time specified and pause them.
* @param globalTime the global time in clock cycles to run all threads ahead to
*/
public void synch(long globalTime) {
throw Util.unimplemented();
}
}
--- NEW FILE: IntervalSynchronizer.java ---
/**
* Copyright (c) 2004-2005, Regents of the University of California
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 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.
*
* Neither the name of the University of California, Los Angeles nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS 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 COPYRIGHT
* OWNER OR 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.
*/
package avrora.sim.clock;
import avrora.sim.*;
import cck.util.Util;
import java.util.HashMap;
import java.util.Iterator;
/**
* The <code>IntervalSynchronizer</code> class implements a global timer among multiple simulators by inserting
* periodic events into the queue of each simulator.
*
* @author Ben L. Titzer, Daniel Lee
*/
public class IntervalSynchronizer extends Synchronizer {
/**
* <code>period</code> is the number of cycles on a member local clock per cycle on the global clock. Some
* re-coding must be done if microcontrollers running at difference speeds are to be accurately
* simulated.
*/
protected long period;
protected final HashMap threadMap;
protected final Simulator.Event action;
protected final Object condition;
protected int goal;
protected int meet_count;
protected int wait_count;
protected WaitSlot waitSlotList;
/**
* The constructor for the <code>IntervalSynchronizer</code> class creates a new synchronizer
* with the specified period, that will fire the specified event each time all threads meet at
* a synchronization point.
* @param p the period in clock cycles which to synchronize the threads
* @param a the event to fire each time all threads meet at a synchronization point
*/
public IntervalSynchronizer(long p, Simulator.Event a) {
period = p;
action = a;
threadMap = new HashMap();
condition = new Object();
}
/**
* The <code>SynchEvent</code> class represents an event that is inserted into the event
* queue of each simulator at the same global time. When this event fires, it will stop the thread
* running this simulator by waiting on a shared
* condition variable. The last thread to fire the event will then notify the condition variable
* which frees the other threads to run again in parallel.
*/
protected class SynchEvent implements Simulator.Event {
protected final SimulatorThread thread;
protected final MainClock clock;
protected boolean removed;
protected boolean met;
protected WaitSlot waitSlot;
protected SynchEvent(SimulatorThread t) {
thread = t;
clock = t.getSimulator().getClock();
}
/**
* The <code>fire()</code> method of this event is called by the individual event queues of each
* simulator as they reach this point in time. The implementation of this method waits for all threads
* to join.
*/
public void fire() {
try {
synchronized (condition) {
// if we have been removed since the last synchronization, return!
if ( removed ) return;
met = true;
// increment the count of the number of threads that have entered
meet_count++;
if ( !signalOthers() )
condition.wait();
met = false;
}
// if we have been removed since the last synchronization, don't insert synch event
if ( removed ) return;
// we have not been removed, we can reinsert the synch event
clock.insertEvent(this, period);
} catch (java.lang.InterruptedException e) {
throw Util.unexpected(e);
}
}
}
/**
* The <code>signalOthers()</code> method is used to check whether the thread that has just arrived
* should signal other threads to continue.
* @return true if this thread signalled the others to continue; false if this thread should stop
* and wait for the other threads before continuing
*/
protected boolean signalOthers() {
// check for any waiters that need to be woken
checkWaiters();
// have we reached the goal?
if (meet_count < goal) {
return false;
} else {
// last thread to arrive sets the count to zero and notifies all other threads
meet_count = 0;
wait_count = 0;
// perform the action that should be run while all threads are stopped (serial)
action.fire();
// release threads
condition.notifyAll();
return true;
}
}
/**
* The <code>start()</code> method starts the threads executing, and the synchronizer
* will add whatever synchronization to their execution that is necessary to preserve
* the global timing properties of simulation.
*/
public synchronized void start() {
Iterator threadIterator = threadMap.keySet().iterator();
while (threadIterator.hasNext()) {
SimulatorThread thread = (SimulatorThread)threadIterator.next();
thread.start();
}
}
/**
* The <code>join()</code> method will block the caller until all of the threads in
* this synchronization interval have terminated, either through <code>stop()</code>
* being called, or terminating normally such as through a timeout.
*/
public void join() throws java.lang.InterruptedException {
Iterator threadIterator = threadMap.keySet().iterator();
while (threadIterator.hasNext()) {
SimulatorThread thread = (SimulatorThread)threadIterator.next();
thread.join();
}
}
/**
* The <code>stop()</code> method will terminate all the simulation threads. It is
* not guaranteed to stop all the simulation threads at the same global time.
*/
public synchronized void stop() {
Iterator threadIterator = threadMap.keySet().iterator();
while (threadIterator.hasNext()) {
SimulatorThread thread = (SimulatorThread)threadIterator.next();
thread.getSimulator().stop();
}
}
/**
* The <code>pause()</code> method temporarily pauses the simulation. The nodes are
* not guaranteed to stop at the same global time. This method will return when all
* threads in the simulation have been paused and will no longer make progress until
* the <code>start()</code> method is called again.
*/
public synchronized void pause() {
throw Util.unimplemented();
}
/**
* The <code>synch()</code> method will pause all of the nodes at the same global time.
* This method can only be called when the simulation is paused. It will run all threads
* forward until the global time specified and pause them.
* @param globalTime the global time in clock cycles to run all threads ahead to
*/
public synchronized void synch(long globalTime) {
throw Util.unimplemented();
}
/**
* The <code>addNode()</code> method adds a node to this synchronization group.
* This method should only be called before the <code>start()</code> method is
* called.
* @param t the simulator representing the node to add to this group
*/
public synchronized void addNode(Simulation.Node t) {
// if we already have this thread, do nothing
SimulatorThread st = t.getThread();
if (threadMap.containsKey(st)) return;
st.setSynchronizer(this);
// create a new synchronization event for this thread's queue
SynchEvent event = new SynchEvent(st);
threadMap.put(st, event);
// insert the synch event in the thread's queue
event.clock.insertEvent(event, period);
goal++;
}
/**
* The <code>removeNode()</code> method removes a node from this synchronization
* group, and wakes any nodes that might be waiting on it.
* @param t the simulator thread to remove from this synchronization group
*/
public synchronized void removeNode(Simulation.Node t) {
// don't try to remove a thread that's not here!
if ( !threadMap.containsKey(t) ) return;
synchronized ( condition ) {
SynchEvent e = (SynchEvent)threadMap.get(t);
e.removed = true; // just in case the thread is still running, don't let it synch
if ( e.met ) meet_count--;
if ( stillWaiting(e.waitSlot) ) {
// if this wait slot hasn't happened yet, we need to decrement wait_count
// and to decrement the number of waiters in that slot
e.waitSlot.numWaiters--;
wait_count--;
}
threadMap.remove(e);
goal--;
// signal any other threads (and wake waiters as necessary) but don't wait
signalOthers();
}
}
/**
* The <code>waitForNeighbors()</code> method is called from within the execution
* of a node when that node needs to wait for its neighbors to catch up to it
* in execution time. The node will be blocked until the other nodes in other
* threads catch up in global time.
*/
public void waitForNeighbors(long time) {
// get the current simulator thread
SimulatorThread thread = (SimulatorThread)Thread.currentThread();
SynchEvent event = (SynchEvent)threadMap.get(thread);
// if the current thread is not in the synchronizer, do nothing
if ( event == null ) return;
WaitSlot w;
synchronized ( condition ) {
// allocate a wait slot for this thread
w = insertWaiter(event, time);
// check for other waiters and wake them if necessary
WaitSlot h = checkWaiters();
// if we were at the head and just woken up, we can just return
if ( w == h ) return;
}
// falling through means that we are either not at the head
// or that not all threads have performed a meet or a wait
try {
// we must grab the lock for this wait slot
synchronized ( w ) {
// check for intervening wakeup between dropping global lock and taking local lock
if ( w.shouldWait )
w.wait();
}
} catch ( java.lang.InterruptedException e) {
throw Util.unexpected(e);
}
}
/**
* The <code>WaitSlot</code> class represents a slot in time where multiple threads are waiting
* for others to catch up.
*/
static class WaitSlot {
final long time;
int numWaiters;
WaitSlot next;
boolean shouldWait;
WaitSlot(long t) {
shouldWait = true;
time = t;
}
}
protected WaitSlot insertWaiter(SynchEvent event, long time) {
// get a wait slot for this waiter
WaitSlot w = getWaitSlot(time);
// now this thread is officially waiting
wait_count++;
// remember the wait slot this waiter is in
event.waitSlot = w;
// increment the number of waiters in this slot
w.numWaiters++;
return w;
}
private WaitSlot getWaitSlot(long time) {
WaitSlot prev = waitSlotList;
// search through the wait list from front to back
for ( WaitSlot slot = waitSlotList; ; slot = slot.next ) {
// if we are at the end of the list, or in-between links, create a new link
if ( slot == null || slot.time > time ) {
return insertAfter(prev, new WaitSlot(time));
}
// if we matched the time of some other waiter exactly
if ( slot.time == time ) {
return slot;
}
// keep track of previous link
prev = slot;
}
}
private WaitSlot insertAfter(WaitSlot prev, WaitSlot w) {
if ( prev != null ) {
w.next = prev.next;
prev.next = w;
} else {
waitSlotList = w;
}
return w;
}
protected WaitSlot checkWaiters() {
// have all threads reached either a meet or a wait?
if ( wait_count + meet_count < goal ) return null;
// are there any waiters at all?
if ( waitSlotList == null ) return null;
// there is a ready wait slot, wake those threads waiting on it
WaitSlot h = waitSlotList;
// move the wait list ahead to the next link
waitSlotList = h.next;
synchronized ( h ) {
// notify the threads waiting on this wait slot
h.shouldWait = false;
h.notifyAll();
}
// reduce the wait count by the number of waiters in this slot
wait_count -= h.numWaiters;
return h;
}
protected boolean stillWaiting(WaitSlot w) {
if ( w == null ) return false;
for ( WaitSlot h = waitSlotList; h != null; h = h.next )
if ( h == w ) return true;
return false;
}
/**
* The <code>adjustPeriod()</code> method can be used to adjust the period of synchronization
* while the simulation is executing. This is useful for adaptive types of synchronization,
* for example when the latency between beginning the first transmission and reception is larger
* than subsequent transmissions (e.g. implementing partial preamble loss).
*
* Care should be taken when calling this method! It should only be called at times when the
* simulation is guaranteed to be stopped at the same global time; i.e. either at a meet
* point or while it has been pause()'d and synch()'d.
*
* @param nperiod the new period in cycles
*/
public void adjustPeriod(long nperiod) {
period = nperiod;
}
}
- Previous message: [Tinyos-contrib-commits]
CVS: tinyos-1.x/contrib/ustutt/ncunit/java/ncunit/avrora
NCUnitMonitor.java, NONE, 1.1 DebugOutputMonitor.java, NONE,
1.1 NCAssert.java, NONE, 1.1
- Next message: [Tinyos-contrib-commits] CVS: tinyos-1.x/contrib/ustutt/ncunit/mote
Assert.nc, NONE, 1.1 AssertM.nc, NONE, 1.1 ncunit.h, NONE,
1.1 debug_gcc.h, NONE, 1.1 dbg.h, NONE, 1.1 debugoutput.h,
NONE, 1.1 AssertC.nc, NONE, 1.1
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the Tinyos-contrib-commits
mailing list