/*
Реализация спецификаций CLDC версии 1.1 (JSR-139), MIDP версии 2.1 (JSR-118)
и других спецификаций для функционирования компактных приложений на языке
Java (мидлетов) в среде программного обеспечения Малик Эмулятор.
Copyright © 2016–2017, 2019–2023 Малик Разработчик
Это свободная программа: вы можете перераспространять ее и/или изменять
ее на условиях Меньшей Стандартной общественной лицензии GNU в том виде,
в каком она была опубликована Фондом свободного программного обеспечения;
либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.
Эта программа распространяется в надежде, что она будет полезной,
но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЕННЫХ ЦЕЛЕЙ. Подробнее см. в Меньшей Стандартной
общественной лицензии GNU.
Вы должны были получить копию Меньшей Стандартной общественной лицензии GNU
вместе с этой программой. Если это не так, см.
<https://www.gnu.org/licenses/>.
*/
package java.lang;
import malik.emulator.application.*;
public final class Scheduler extends Object
{
public static abstract class Task extends Object implements Runnable
{
boolean periodic;
int mode;
long period;
long runningTime;
long scheduledTime;
protected Task() {
this.scheduledTime = Long.MIN_VALUE;
}
public abstract void run();
public void cancel() {
Scheduler.cancel(this);
}
public final long scheduledTime() {
return scheduledTime;
}
protected void cancelled() {
}
}
public static final int ACTION = 0;
public static final int THREAD = 1;
public static final int MONOPOLY = 2;
private static int COUNT;
private static Task[] QUEUE;
static {
COUNT = 0;
QUEUE = new Task[0x10];
MalikInterrupt.register(0x18, new TimerInterruptHandler());
}
public static void schedule(Task task, long delay, int mode) {
boolean status;
if(task == null)
{
throw new NullPointerException("Scheduler.schedule: аргумент task равен нулевой ссылке.");
}
if(delay <= 0L)
{
throw new IllegalArgumentException("Scheduler.schedule: аргумент delay может быть только положительным.");
}
if(mode < ACTION || mode > MONOPOLY)
{
throw new IllegalArgumentException("Scheduler.schedule: недопустимое значение аргумента mode.");
}
status = MalikSystem.enterMonopolyAccess();
try
{
if(indexOf(task) < 0)
{
task.periodic = false;
task.mode = mode;
task.runningTime = System.currentTimeMillis() + delay;
push(task);
}
}
finally
{
MalikSystem.leaveMonopolyAccess(status);
}
}
public static void schedule(Task task, long delay, long period, int mode) {
boolean status;
if(task == null)
{
throw new NullPointerException("Scheduler.schedule: аргумент task равен нулевой ссылке.");
}
if(delay <= 0L)
{
throw new IllegalArgumentException("Scheduler.schedule: аргумент delay может быть только положительным.");
}
if(period <= 0L)
{
throw new IllegalArgumentException("Scheduler.schedule: аргумент period может быть только положительным.");
}
if(mode < ACTION || mode > MONOPOLY)
{
throw new IllegalArgumentException("Scheduler.schedule: недопустимое значение аргумента mode.");
}
status = MalikSystem.enterMonopolyAccess();
try
{
if(indexOf(task) < 0)
{
task.periodic = true;
task.mode = mode;
task.period = period;
task.runningTime = System.currentTimeMillis() + delay;
push(task);
}
}
finally
{
MalikSystem.leaveMonopolyAccess(status);
}
}
static void cancel(Task task) {
try
{
boolean cancel = false;
boolean status = MalikSystem.enterMonopolyAccess();
try
{
int index;
if((index = indexOf(task)) >= 0)
{
if(index < COUNT - 1) MalikSystem.arraycopyf_object(QUEUE, index + 1, QUEUE, index, COUNT - index - 1);
QUEUE[--COUNT] = null;
updateTimer();
if(task.mode != MONOPOLY)
{
cancel = true;
} else
{
task.cancelled();
}
}
}
finally
{
MalikSystem.leaveMonopolyAccess(status);
}
if(cancel) task.cancelled();
}
catch(RuntimeException e)
{
e.printRealStackTrace();
}
}
static void push(Task task) {
int index;
long runningTime;
if(COUNT == QUEUE.length) MalikSystem.arraycopyf_object(QUEUE, 0, QUEUE = new Task[COUNT << 1], 0, COUNT);
index = COUNT;
runningTime = task.runningTime;
for(int i = 0; i < index; i++) if(QUEUE[i].runningTime <= runningTime)
{
MalikSystem.arraycopyb_object(QUEUE, COUNT, QUEUE, COUNT + 1, COUNT - (index = i));
break;
}
COUNT++;
QUEUE[index] = task;
updateTimer();
}
static Task pop() {
long remainingTime;
Task result;
if(COUNT == 0) return null;
if((remainingTime = (result = QUEUE[COUNT - 1]).runningTime - System.currentTimeMillis()) > 0L)
{
MalikSystem.syscall(remainingTime, 0x0040);
return null;
}
QUEUE[--COUNT] = null;
updateTimer();
return result;
}
private static void updateTimer() {
long remainingTime;
if(COUNT > 0)
{
if((remainingTime = QUEUE[COUNT - 1].runningTime - System.currentTimeMillis()) <= 0L) remainingTime = 1L;
MalikSystem.syscall(remainingTime, 0x0040);
return;
}
MalikSystem.syscall(0L, 0x0040);
}
private static int indexOf(Task task) {
return COUNT > 0 ? MalikSystem.arrayfindb_object(QUEUE, COUNT - 1, task) : -1;
}
private Scheduler() {
}
}
final class TimerInterruptHandler extends InterruptHandler implements InterruptLong
{
public TimerInterruptHandler() {
}
public void interrupt(long argument) {
MalikSystem.disableThreadSwitching();
try
{
Scheduler.Task task;
if((task = Scheduler.pop()) != null)
{
try
{
task.scheduledTime = task.runningTime;
switch(task.mode)
{
case Scheduler.THREAD:
(new Thread(task, "Задача планировщика задач")).start();
break;
case Scheduler.ACTION:
Run.instance.request(task);
break;
case Scheduler.MONOPOLY:
task.run();
break;
}
}
catch(RuntimeException e)
{
e.printRealStackTrace();
}
if(task.periodic)
{
task.runningTime = System.currentTimeMillis() + task.period;
Scheduler.push(task);
}
}
}
finally
{
MalikSystem.enableThreadSwitching();
}
}
}