/******************************************************************************* * * Copyright (c) 2010 Fujitsu Services Ltd. * * Author: Nick Battle * * This file is part of VDMJ. * * VDMJ 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 3 of the License, or * (at your option) any later version. * * VDMJ 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 VDMJ. If not, see <http://www.gnu.org/licenses/>. * ******************************************************************************/ package org.overture.interpreter.scheduler; import java.util.LinkedList; import java.util.List; import org.overture.interpreter.messages.rtlog.RTBusActivateMessage; import org.overture.interpreter.messages.rtlog.RTBusCompletedMessage; import org.overture.interpreter.messages.rtlog.RTBusReplyRequestMessage; import org.overture.interpreter.messages.rtlog.RTBusRequestMessage; import org.overture.interpreter.messages.rtlog.RTDeclareBUSMessage; import org.overture.interpreter.messages.rtlog.RTLogger; import org.overture.interpreter.scheduler.SystemClock.TimeUnit; public class BUSResource extends Resource { private static final long serialVersionUID = 1L; private static int nextBUS = 1; private static BUSResource vBUS = null; private final int busNumber; private final ControlQueue cq; private final double speed; private final List<CPUResource> cpus; private final List<MessagePacket> messages; private ISchedulableThread busThread = null; public BUSResource(boolean isVirtual, SchedulingPolicy policy, double speed, List<CPUResource> cpus) { super(policy); this.busNumber = isVirtual ? 0 : nextBUS++; this.cq = new ControlQueue(); this.speed = speed; this.cpus = cpus; this.messages = new LinkedList<MessagePacket>(); busThread = null; if (isVirtual) { vBUS = this; } } public static void init() { MessagePacket.init(); nextBUS = 1; vBUS = null; } @Override public void reset() { messages.clear(); cq.reset(); policy.reset(); } @Override public void setName(String name) { super.setName(name); if (busNumber != 0) { RTLogger.log(new RTDeclareBUSMessage(busNumber, cpusToSet(), name)); } } @Override public boolean reschedule() { // This is scheduling threads, as though for a CPU, but really we // want to schedule (ie. order) the messages on the queue for the BUS. // There is only one BUS thread. if (policy.reschedule()) { busThread = policy.getThread(); busThread.runslice(policy.getTimeslice()); return true; } else { return false; } } @Override public long getMinimumTimestep() { if (busThread == null) { return Long.MAX_VALUE; // We're not in timestep } else { switch (busThread.getRunState()) { case TIMESTEP: return busThread.getTimestep(); case RUNNING: return -1; // Can't timestep default: return Long.MAX_VALUE; } } } public boolean links(CPUResource from, CPUResource to) { if (from.equals(to)) { return false; } else { return cpus.contains(from) && cpus.contains(to); } } public void transmit(MessageRequest request) { RTLogger.log(new RTBusRequestMessage(request)); messages.add(request); cq.stim(); } public void reply(MessageResponse response) { RTLogger.log(new RTBusReplyRequestMessage(response)); messages.add(response); cq.stim(); } public void process(ISchedulableThread th) { cq.join(null, null); // Never leaves while (true) { while (messages.isEmpty()) { cq.block(null, null); } MessagePacket m = messages.remove(0); RTLogger.log(new RTBusActivateMessage(m)); if (m instanceof MessageRequest) { MessageRequest mr = (MessageRequest) m; if (!mr.bus.isVirtual()) { long pause = getDataDuration(mr.getSize()); th.duration(pause, null, null); } AsyncThread thread = new AsyncThread(mr); thread.start(); } else { MessageResponse mr = (MessageResponse) m; if (!mr.bus.isVirtual()) { long pause = getDataDuration(mr.getSize()); th.duration(pause, null, null); } mr.replyTo.set(mr); } RTLogger.log(new RTBusCompletedMessage(m)); } } @Override public boolean isVirtual() { return this == vBUS; } private long getDataDuration(long bytes) { if (speed == 0) { return 0; // Infinitely fast virtual bus } else { // TODO optimize by converting the speed into the correct units only once return SystemClock.timeToInternal(TimeUnit.seconds, new Double(bytes) / speed); // bytes/s } } private String cpusToSet() { StringBuilder sb = new StringBuilder(); sb.append("{"); String prefix = ""; for (CPUResource cpu : cpus) { sb.append(prefix); sb.append(cpu.getNumber()); prefix = ","; } sb.append("}"); return sb.toString(); } @Override public String getStatus() { return name + " queue = " + messages.size(); } public int getNumber() { return busNumber; } }