| /** |
| ******************************************************************************** |
| * Copyright (c) 2019 Dortmund University of Applied Sciences and Arts and others. |
| * |
| * This program and the accompanying materials are made |
| * available under the terms of the Eclipse Public License 2.0 |
| * which is available at https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| * |
| * Contributors: |
| * Dortmund University of Applied Sciences and Arts - initial API and implementation |
| ******************************************************************************** |
| */ |
| |
| package org.eclipse.app4mc.multicore.execution.logic.systemproxy.scheduler.core; |
| |
| import java.util.LinkedList; |
| import java.util.List; |
| |
| import org.eclipse.app4mc.multicore.execution.logic.systemproxy.scheduler.ISchedulerTask; |
| |
| public class SchedulerTask extends TaskFSM implements ISchedulerTask { |
| |
| /** |
| * Barriers are task-synchronization-points. This implementation relies on |
| * simulated barriers. All owned barriers will be locked at beginning of |
| * every task-period. It will be released after barrier release time is |
| * reached. |
| */ |
| private final List<BarrierAccess> ownedBarriers = new LinkedList<>(); |
| |
| /** |
| * Barriers are used for synchronization of dependent tasks. The current |
| * task has to wait until all dependentMutexes are unlocked. |
| */ |
| private final List<Barrier> dependentBarrier = new LinkedList<>(); |
| |
| /** Task name */ |
| private final String name; |
| |
| /** Worst case execution time. */ |
| private final long wcet; |
| |
| /** Fix period of the task. */ |
| private final long period; |
| |
| /** Count of the current period. */ |
| private int periodCount = 0; |
| |
| /** Relative earliest start time or activation time. */ |
| private long esTime = 0; |
| |
| /** Current consumed execution time. */ |
| private long currentExecTime = 0; |
| |
| /** Unique upcounting number in a scheduler */ |
| private int id; |
| |
| public SchedulerTask(final String name, final long wcet, final long period) { |
| super(TState.READY); |
| this.name = name; |
| this.wcet = wcet; |
| this.period = period; |
| this.esTime = 0; |
| } |
| |
| public String getName() { |
| return this.name; |
| } |
| |
| @Override |
| public long getWCET() { |
| return this.wcet; |
| } |
| |
| @Override |
| public long getPeriod() { |
| return this.period; |
| } |
| |
| /** |
| * @return the periodCount |
| */ |
| public int getPeriodCount() { |
| return this.periodCount; |
| } |
| |
| /** |
| * @param periodCount |
| * the periodCount to set |
| */ |
| public void incrementPeriodCount() { |
| this.periodCount++; |
| } |
| |
| public long getCurrentExecTime() { |
| return this.currentExecTime; |
| } |
| |
| /** |
| * Run one time slot. |
| */ |
| public void run() { |
| assert isRunning(); |
| this.currentExecTime = Math.addExact(this.currentExecTime, 1); // one |
| // time |
| // step |
| assert this.currentExecTime <= this.wcet; |
| } |
| |
| /** |
| * Check if current execution time of the task reached WCET. |
| * |
| * @return |
| */ |
| public boolean reachedWCET() { |
| return this.currentExecTime == this.wcet; |
| } |
| |
| |
| /** |
| * Get the remaining execution time to WCET. |
| * |
| * @return |
| */ |
| public long remainingExecutionTime() { |
| return this.wcet - this.currentExecTime; |
| } |
| |
| |
| /** |
| * Reset the task to be ready for the next period. |
| * <ul> |
| * <li>set current execution time to zero</li> |
| * <li>set the next earliest start time to the start of the next period</li> |
| * </ul> |
| */ |
| public void resetForNextPeriod() { |
| this.currentExecTime = 0; |
| this.esTime += this.period; |
| lockOwnedBarriers(); |
| incrementPeriodCount(); |
| } |
| |
| |
| /** |
| * Get current absolute earliest start time. |
| * |
| * @return |
| */ |
| public long getEearliestStartTime() { |
| return this.esTime; |
| } |
| |
| public long getNextActivationTime() { |
| return getEearliestStartTime() + this.period; |
| } |
| |
| /** |
| * Check if has blocking barriers (by mutexes). |
| * |
| * @return |
| */ |
| public boolean hasBlockingBarrier() { |
| for (final Barrier m : this.dependentBarrier) { |
| if (m.isLocked()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public Barrier getFirstBlockingMutex() { |
| for (final Barrier m : this.dependentBarrier) { |
| if (m.isLocked()) { |
| return m; |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * Get the current (absolute) deadline. |
| * |
| * @return |
| */ |
| public long getDeadline() { |
| return getEearliestStartTime() + getPeriod(); |
| } |
| |
| |
| /** |
| * Unlock owned barriers/ mutexes that reached release time. |
| */ |
| public void updateOwnedBarriers() { |
| for (final BarrierAccess ma : this.ownedBarriers) { |
| final long releaseTime = ma.getReleaseTime(); |
| assert releaseTime <= getCurrentExecTime() || releaseTime == ISchedulerTask.BARRIER_UNLOCK_AT_SUSPENSION; |
| if (releaseTime == getCurrentExecTime()) { |
| ma.getBarrier().unlock(); |
| } |
| else if (releaseTime == ISchedulerTask.BARRIER_UNLOCK_AT_SUSPENSION && isSuspended()) { |
| ma.getBarrier().unlock(); |
| } |
| } |
| } |
| |
| /** |
| * Lock all owned barriers (mutexes) |
| */ |
| public void lockOwnedBarriers() { |
| |
| for (final BarrierAccess ma : this.ownedBarriers) { |
| if (!ma.getBarrier().tryLock(getName())) { |
| // with owned mutexes the locking will always be possible |
| // because current thread have to be the only task |
| // that locks it. |
| |
| // Despite the task overrun an deadline and some owned barriers |
| // arent |
| } |
| } |
| } |
| |
| /** |
| * Get identifier for the task. Unique in a scheduler. Indicates the adding |
| * order for the scheduler. |
| * |
| * @return |
| */ |
| public int getId() { |
| return this.id; |
| } |
| |
| /** |
| * Set identification. |
| * |
| * @param id |
| */ |
| public void setId(final int id) { |
| this.id = id; |
| } |
| |
| /** |
| * Add an owned barrier to the task. Owned barriers are used for setting up |
| * task precedence. The owner is the predecessor task. The successor task is |
| * dependent of the same barrier instance |
| * ({@link #addDependentBarrier(Barrier m)}). |
| * |
| * Barrier requirements |
| * <ul> |
| * <li>Passed instance have to be unlocked (free)</li> |
| * <li>Passed instance have to be added to one owning task and to one or |
| * multiple depending tasks</li> |
| * <li>Only the owner task locks and unlocks the barrier. Dependants only |
| * query if is unlocked</li> |
| * </ul> |
| * |
| * @see #addDependentBarrier(Barrier) |
| * @param barrier |
| * Barrier that have to be unlocked. |
| * @param releaseTime |
| * Execution time of the task when the barrier gets unlocked in |
| * each period. |
| */ |
| @Override |
| public void addOwnedBarrier(final Barrier barrier, final long releaseTime) { |
| // implementation through barriers and not through predecessor task |
| // so unlocking can happen at random release times and not only at |
| // suspension |
| // lock initially |
| if (!barrier.tryLock(getName())) { |
| // not free |
| assert false; // precondition free |
| } |
| final BarrierAccess ma = new BarrierAccess(ISchedulerTask.BARRIER_LOCK_AT_ACTIVATION, releaseTime, barrier); |
| this.ownedBarriers.add(ma); |
| } |
| |
| /** |
| * Add dependent barrier. |
| * |
| * @see #addOwnedBarrier(Barrier, long) |
| * @param m |
| */ |
| @Override |
| public void addDependentBarrier(final Barrier m) { |
| this.dependentBarrier.add(m); |
| } |
| |
| |
| } |