thread-safe event scheduling
This commit is contained in:
parent
34829fe41e
commit
c4ba4b7008
|
@ -26,11 +26,13 @@
|
||||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||||
* SUCH DAMAGE.
|
* SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id: EventQueue.java,v 1.2 2008/12/04 14:03:42 joxe Exp $
|
* $Id: EventQueue.java,v 1.3 2008/12/08 13:07:32 fros4943 Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package se.sics.cooja;
|
package se.sics.cooja;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Joakim Eriksson (ported to COOJA by Fredrik Österlind)
|
* @author Joakim Eriksson (ported to COOJA by Fredrik Österlind)
|
||||||
*/
|
*/
|
||||||
|
@ -40,9 +42,30 @@ public class EventQueue {
|
||||||
private long nextTime;
|
private long nextTime;
|
||||||
private int eventCount = 0;
|
private int eventCount = 0;
|
||||||
|
|
||||||
|
private ArrayList<TimeEvent> pendingEvents = new ArrayList<TimeEvent>();
|
||||||
|
private boolean hasPendingEvents = false;
|
||||||
|
|
||||||
public EventQueue() {
|
public EventQueue() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public synchronized void addPendingEvent(TimeEvent event, long time) {
|
||||||
|
event.time = time;
|
||||||
|
pendingEvents.add(event);
|
||||||
|
hasPendingEvents = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void handlePendingEvents() {
|
||||||
|
if (!hasPendingEvents) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (TimeEvent e: pendingEvents) {
|
||||||
|
addEvent(e);
|
||||||
|
}
|
||||||
|
pendingEvents.clear();
|
||||||
|
hasPendingEvents = false;
|
||||||
|
}
|
||||||
|
|
||||||
public void addEvent(TimeEvent event, long time) {
|
public void addEvent(TimeEvent event, long time) {
|
||||||
event.time = time;
|
event.time = time;
|
||||||
addEvent(event);
|
addEvent(event);
|
||||||
|
@ -118,6 +141,10 @@ public class EventQueue {
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeEvent popFirst() {
|
public TimeEvent popFirst() {
|
||||||
|
if (hasPendingEvents) {
|
||||||
|
handlePendingEvents();
|
||||||
|
}
|
||||||
|
|
||||||
TimeEvent tmp = first;
|
TimeEvent tmp = first;
|
||||||
if (tmp == null) {
|
if (tmp == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*
|
*
|
||||||
* $Id: Simulation.java,v 1.35 2008/12/04 16:52:03 fros4943 Exp $
|
* $Id: Simulation.java,v 1.36 2008/12/08 13:07:06 fros4943 Exp $
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package se.sics.cooja;
|
package se.sics.cooja;
|
||||||
|
@ -68,7 +68,7 @@ public class Simulation extends Observable implements Runnable {
|
||||||
|
|
||||||
private boolean stopSimulation = false;
|
private boolean stopSimulation = false;
|
||||||
|
|
||||||
private Thread thread = null;
|
private Thread simulationThread = null;
|
||||||
|
|
||||||
private GUI myGUI = null;
|
private GUI myGUI = null;
|
||||||
|
|
||||||
|
@ -111,6 +111,11 @@ public class Simulation extends Observable implements Runnable {
|
||||||
tickObservable.deleteObserver(observer);
|
tickObservable.deleteObserver(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
protected void scheduleEventUnsafe(TimeEvent e, long time) {
|
||||||
|
eventQueue.addEvent(e, time);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Schedule event to be handled by event loop.
|
* Schedule event to be handled by event loop.
|
||||||
*
|
*
|
||||||
|
@ -118,7 +123,11 @@ public class Simulation extends Observable implements Runnable {
|
||||||
* @param time Simulated time
|
* @param time Simulated time
|
||||||
*/
|
*/
|
||||||
public void scheduleEvent(TimeEvent e, long time) {
|
public void scheduleEvent(TimeEvent e, long time) {
|
||||||
eventQueue.addEvent(e, time);
|
if (Thread.currentThread() == simulationThread) {
|
||||||
|
eventQueue.addEvent(e, time);
|
||||||
|
} else {
|
||||||
|
eventQueue.addPendingEvent(e, time);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private EventQueue eventQueue = new EventQueue();
|
private EventQueue eventQueue = new EventQueue();
|
||||||
|
@ -144,7 +153,7 @@ public class Simulation extends Observable implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reschedule MSP motes */
|
/* Reschedule MSP motes */
|
||||||
scheduleEvent(this, t+1);
|
scheduleEventUnsafe(this, t+1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -162,18 +171,19 @@ public class Simulation extends Observable implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Reschedule Contiki motes */
|
/* Reschedule Contiki motes */
|
||||||
scheduleEvent(this, t+1);
|
scheduleEventUnsafe(this, t+1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
private TimeEvent delayEvent = new TimeEvent(0) {
|
private TimeEvent delayEvent = new TimeEvent(0) {
|
||||||
public void execute(long t) {
|
public void execute(long t) {
|
||||||
/*logger.info("Delay at: " + t);*/
|
/*logger.info("Delay at: " + t);*/
|
||||||
if (delayTime == 0)
|
if (delayTime == 0) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
try { Thread.sleep(delayTime); } catch (InterruptedException e) { }
|
try { Thread.sleep(delayTime); } catch (InterruptedException e) { }
|
||||||
scheduleEvent(this, t+1);
|
scheduleEventUnsafe(this, t+1);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -184,9 +194,9 @@ public class Simulation extends Observable implements Runnable {
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
|
|
||||||
/* Schedule tick events */
|
/* Schedule tick events */
|
||||||
scheduleEvent(tickMotesEvent, currentSimulationTime);
|
scheduleEventUnsafe(tickMotesEvent, currentSimulationTime);
|
||||||
scheduleEvent(tickMspMotesEvent, currentSimulationTime);
|
scheduleEventUnsafe(tickMspMotesEvent, currentSimulationTime);
|
||||||
scheduleEvent(delayEvent, currentSimulationTime);
|
scheduleEventUnsafe(delayEvent, currentSimulationTime);
|
||||||
|
|
||||||
/* Simulation starting */
|
/* Simulation starting */
|
||||||
this.setChanged();
|
this.setChanged();
|
||||||
|
@ -212,9 +222,9 @@ public class Simulation extends Observable implements Runnable {
|
||||||
|
|
||||||
if (rescheduleEvents) {
|
if (rescheduleEvents) {
|
||||||
rescheduleEvents = false;
|
rescheduleEvents = false;
|
||||||
scheduleEvent(tickMotesEvent, currentSimulationTime);
|
scheduleEventUnsafe(tickMotesEvent, currentSimulationTime);
|
||||||
scheduleEvent(tickMspMotesEvent, currentSimulationTime);
|
scheduleEventUnsafe(tickMspMotesEvent, currentSimulationTime);
|
||||||
scheduleEvent(delayEvent, currentSimulationTime);
|
scheduleEventUnsafe(delayEvent, currentSimulationTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
nextEvent = eventQueue.popFirst();
|
nextEvent = eventQueue.popFirst();
|
||||||
|
@ -249,7 +259,7 @@ public class Simulation extends Observable implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
isRunning = false;
|
isRunning = false;
|
||||||
thread = null;
|
simulationThread = null;
|
||||||
stopSimulation = false;
|
stopSimulation = false;
|
||||||
|
|
||||||
// Notify observers simulation has stopped
|
// Notify observers simulation has stopped
|
||||||
|
@ -275,8 +285,8 @@ public class Simulation extends Observable implements Runnable {
|
||||||
public void startSimulation() {
|
public void startSimulation() {
|
||||||
if (!isRunning()) {
|
if (!isRunning()) {
|
||||||
isRunning = true;
|
isRunning = true;
|
||||||
thread = new Thread(this);
|
simulationThread = new Thread(this);
|
||||||
thread.start();
|
simulationThread.start();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,10 +298,10 @@ public class Simulation extends Observable implements Runnable {
|
||||||
stopSimulation = true;
|
stopSimulation = true;
|
||||||
|
|
||||||
/* Wait until simulation stops */
|
/* Wait until simulation stops */
|
||||||
if (Thread.currentThread() != thread) {
|
if (Thread.currentThread() != simulationThread) {
|
||||||
try {
|
try {
|
||||||
if (thread != null) {
|
if (simulationThread != null) {
|
||||||
thread.join();
|
simulationThread.join();
|
||||||
}
|
}
|
||||||
} catch (InterruptedException e) {
|
} catch (InterruptedException e) {
|
||||||
}
|
}
|
||||||
|
@ -783,7 +793,7 @@ public class Simulation extends Observable implements Runnable {
|
||||||
* @return True if simulation is running
|
* @return True if simulation is running
|
||||||
*/
|
*/
|
||||||
public boolean isRunning() {
|
public boolean isRunning() {
|
||||||
return isRunning && thread != null;
|
return isRunning && simulationThread != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in a new issue