Scheduler.java

Переключить прокрутку окна
Загрузить этот исходный код

/*
    Реализация спецификаций 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();
        }
    }
}