/*******************************************************************************
*
* Copyright (c) 2009 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 java.util.Random;
import org.overture.interpreter.values.TransactionValue;
import org.overture.parser.config.Properties;
public class FCFSPolicy extends SchedulingPolicy
{
private static final long serialVersionUID = 1L;
protected final List<ISchedulableThread> threads;
protected ISchedulableThread bestThread = null;
protected Random PRNG = null;
private ISchedulableThread durationThread = null;
public FCFSPolicy()
{
threads = new LinkedList<ISchedulableThread>();
PRNG = new Random(); // NB deliberately non-deterministic!
}
@Override
public void reset()
{
synchronized (threads)
{
threads.clear();
}
bestThread = null;
durationThread = null;
}
@Override
public void register(ISchedulableThread thread, long priority)
{
synchronized (threads)
{
// The last thread is the one currently running, so insert ahead of this
// one so that the new thread is scheduled before the current one is
// next scheduled.
int count = threads.size();
if (count == 0)
{
threads.add(thread);
} else
{
threads.add(count - 1, thread);
}
}
}
@Override
public void unregister(ISchedulableThread thread)
{
synchronized (threads)
{
threads.remove(thread);
if (durationThread == thread)
{
durationThread = null;
}
}
}
@Override
public boolean reschedule()
{
bestThread = null;
if (durationThread != null)
{
bestThread = durationThread;
durationThread = null;
return true;
}
synchronized (threads)
{
for (ISchedulableThread th : threads)
{
switch (th.getRunState())
{
case RUNNABLE:
bestThread = th;
threads.remove(th);
threads.add(th);
return true;
case TIMESTEP:
case WAITING:
case LOCKING:
default:
break;
}
}
}
return false;
}
@Override
public ISchedulableThread getThread()
{
synchronized (threads) // As it was set under threads
{
return bestThread;
}
}
@Override
public long getTimeslice()
{
long slice = 0;
if (bestThread.isVirtual())
{
slice = Properties.scheduler_virtual_timeslice;
} else
{
slice = Properties.scheduler_fcfs_timeslice;
}
if (Properties.scheduler_jitter > 0)
{
// Plus or minus jitter ticks...
slice += PRNG.nextLong() % (Properties.scheduler_jitter + 1);
}
return slice;
}
@Override
public long timeToNextAlarm()
{
long minTime = Long.MAX_VALUE;
long now = SystemClock.getWallTime();
synchronized (threads)
{
for (ISchedulableThread th : threads)
{
switch (th.getRunState())
{
case ALARM:
long delay = th.getAlarmWakeTime() - now;
if (delay < 0)
{
delay = 0; // Time has past
}
if (delay < minTime)
{
minTime = delay;
}
break;
default:
break;
}
}
}
return minTime;
}
@Override
public void advance()
{
synchronized (threads)
{
for (ISchedulableThread th : threads)
{
switch (th.getRunState())
{
case TIMESTEP:
durationThread = th;
th.setState(RunState.RUNNABLE);
if (Properties.rt_duration_transactions
&& th.getDurationEnd() == SystemClock.getWallTime())
{
TransactionValue.commitOne(th.getId());
}
break;
case ALARM:
if (th.getAlarmWakeTime() <= SystemClock.getWallTime())
{
th.clearAlarm(); // Time to wake up!
th.setState(RunState.RUNNABLE);
}
break;
default:
break;
}
}
}
}
@Override
public boolean hasActive()
{
synchronized (threads)
{
for (ISchedulableThread th : threads)
{
if (th.isActive())
{
return true;
}
}
}
return false;
}
@Override
public boolean hasPriorities()
{
return false;
}
@Override
public String getStatus()
{
StringBuilder sb = new StringBuilder();
String sep = "";
for (ISchedulableThread th : threads)
{
sb.append(sep);
sb.append(th);
sep = "\n";
}
return sb.toString();
}
}