/*
Реализация спецификаций 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.util;
public class Timer extends Object
{
private TimerThread thread;
public Timer() {
TimerThread thread;
this.thread = thread = new TimerThread();
((Thread) thread).start();
}
public void cancel() {
TimerThread thread;
if((thread = this.thread) != null)
{
this.thread = null;
thread.terminate();
}
}
public void schedule(TimerTask task, long delay) {
long firstExecutionTime;
TimerThread thread;
if(delay < 0L || (firstExecutionTime = System.currentTimeMillis() + delay) < 0L)
{
throw new IllegalArgumentException("Timer.schedule: аргумент delay имеет недопустимое значение.");
}
if((thread = this.thread) == null)
{
throw new IllegalStateException("Timer.schedule: планирование новых задач было отменено.");
}
if(task != null) thread.schedule(task, firstExecutionTime);
}
public void schedule(TimerTask task, long delay, long period) {
long firstExecutionTime;
TimerThread thread;
if(delay < 0L || (firstExecutionTime = System.currentTimeMillis() + delay) < 0L)
{
throw new IllegalArgumentException("Timer.schedule: аргумент delay имеет недопустимое значение.");
}
if((thread = this.thread) == null)
{
throw new IllegalStateException("Timer.schedule: планирование новых задач было отменено.");
}
if(task != null) thread.schedule(task, firstExecutionTime, period, false);
}
public void schedule(TimerTask task, Date time) {
long firstExecutionTime;
TimerThread thread;
if((firstExecutionTime = time == null ? System.currentTimeMillis() : time.getTime()) < 0L)
{
throw new IllegalArgumentException("Timer.schedule: аргумент time имеет недопустимое значение.");
}
if((thread = this.thread) == null)
{
throw new IllegalStateException("Timer.schedule: планирование новых задач было отменено.");
}
if(task != null) thread.schedule(task, firstExecutionTime);
}
public void schedule(TimerTask task, Date firstTime, long period) {
long firstExecutionTime;
TimerThread thread;
if((firstExecutionTime = firstTime == null ? System.currentTimeMillis() : firstTime.getTime()) < 0L)
{
throw new IllegalArgumentException("Timer.schedule: аргумент firstTime имеет недопустимое значение.");
}
if((thread = this.thread) == null)
{
throw new IllegalStateException("Timer.schedule: планирование новых задач было отменено.");
}
if(task != null) thread.schedule(task, firstExecutionTime, period, false);
}
public void scheduleAtFixedRate(TimerTask task, long delay, long period) {
long firstExecutionTime;
TimerThread thread;
if(delay < 0L || (firstExecutionTime = System.currentTimeMillis() + delay) < 0L)
{
throw new IllegalArgumentException("Timer.scheduleAtFixedRate: аргумент delay имеет недопустимое значение.");
}
if((thread = this.thread) == null)
{
throw new IllegalStateException("Timer.scheduleAtFixedRate: планирование новых задач было отменено.");
}
if(task != null) thread.schedule(task, firstExecutionTime, period, true);
}
public void scheduleAtFixedRate(TimerTask task, Date firstTime, long period) {
long firstExecutionTime;
TimerThread thread;
if((firstExecutionTime = firstTime == null ? System.currentTimeMillis() : firstTime.getTime()) < 0L)
{
throw new IllegalArgumentException("Timer.scheduleAtFixedRate: аргумент firstTime имеет недопустимое значение.");
}
if((thread = this.thread) == null)
{
throw new IllegalStateException("Timer.scheduleAtFixedRate: планирование новых задач было отменено.");
}
if(task != null) thread.schedule(task, firstExecutionTime, period, true);
}
}
final class TimerThread extends Thread
{
private static final int STATE_MASK = 0x03;
private static final int STATE_FREE = 0x00;
private static final int STATE_SCHEDULED = 0x01;
private static final int STATE_EXECUTING = 0x02;
private static final int STATE_CANCELLED = 0x03;
private static final int FLAG_PERIODIC = 0x04;
private static final int FLAG_FIXED_RATE = 0x08;
private static final Object MONITOR;
static {
MONITOR = new Object();
}
private boolean terminated;
private int length;
private TimerTask[] queue;
private final Object monitor;
public TimerThread() {
super("Поток событий тимера");
this.queue = new TimerTask[8];
this.monitor = new Object();
}
public void run() {
for(Object monitor = this.monitor; ; )
{
boolean fixedRate;
boolean mustContinue;
TimerTask task;
waitTask();
if(terminated) break;
if((task = pop()) == null) continue;
mustContinue = false;
synchronized(monitor)
{
label0:
{
int flags;
fixedRate = ((flags = task.flags) & FLAG_FIXED_RATE) != 0;
if((flags & STATE_MASK) != STATE_SCHEDULED)
{
task.flags = STATE_CANCELLED;
task.period = 0L;
task.nextExecutionTime = 0L;
task.shedExecutionTime = 0L;
task.owner = null;
mustContinue = true;
break label0;
}
task.flags = flags & ~STATE_MASK | STATE_EXECUTING;
task.shedExecutionTime = task.nextExecutionTime;
if(fixedRate) task.nextExecutionTime += task.period;
}
}
if(mustContinue) continue;
try
{
task.run();
}
catch(RuntimeException e)
{
e.printRealStackTrace();
}
synchronized(monitor)
{
label0:
{
int flags;
if(((flags = task.flags) & STATE_MASK) != STATE_EXECUTING || (flags & FLAG_PERIODIC) == 0)
{
task.flags = STATE_CANCELLED;
task.period = 0L;
task.nextExecutionTime = 0L;
task.shedExecutionTime = 0L;
task.owner = null;
break label0;
}
if(!fixedRate) task.nextExecutionTime = System.currentTimeMillis() + task.period;
task.flags = flags & ~STATE_MASK | STATE_SCHEDULED;
push(task);
}
}
}
clear();
}
public void terminate() {
Object monitor;
synchronized(monitor = this.monitor)
{
terminated = true;
monitor.notify();
}
}
public void schedule(TimerTask task, long time) {
int error = 0;
Object monitor;
synchronized(MONITOR)
{
label0:
{
if((task.flags & STATE_MASK) != STATE_FREE)
{
error = 1;
break label0;
}
task.flags = STATE_SCHEDULED;
task.period = 0L;
}
}
if(error == 1)
{
throw new IllegalStateException("Timer.schedule: задача уже планировалась раннее.");
}
synchronized(monitor = this.monitor)
{
task.nextExecutionTime = time;
task.owner = this;
push(task);
monitor.notify();
}
}
public void schedule(TimerTask task, long time, long period, boolean fixedRate) {
int error = 0;
Object monitor;
synchronized(MONITOR)
{
label0:
{
if((task.flags & STATE_MASK) != STATE_FREE)
{
error = 1;
break label0;
}
task.flags = fixedRate ? FLAG_FIXED_RATE | FLAG_PERIODIC | STATE_SCHEDULED : FLAG_PERIODIC | STATE_SCHEDULED;
task.period = period >= 0L ? period : 0L;
}
}
if(error == 1)
{
throw new IllegalStateException(fixedRate ? "Timer.scheduleAtFixedRate: задача уже планировалась раннее." : "Timer.schedule: задача уже планировалась раннее.");
}
synchronized(monitor = this.monitor)
{
task.nextExecutionTime = time;
task.owner = this;
push(task);
monitor.notify();
}
}
public boolean cancel(TimerTask task) {
boolean result;
Object monitor;
synchronized(monitor = this.monitor)
{
label0:
{
int flags;
int index;
int length;
TimerTask[] queue;
if(task.owner != this)
{
result = false;
break label0;
}
result = ((flags = task.flags) & FLAG_PERIODIC) != 0 || (flags & STATE_MASK) == STATE_SCHEDULED;
if((index = Array.findb(queue = this.queue, length = this.length - 1, task)) < 0)
{
task.flags = STATE_CANCELLED;
task.period = 0L;
task.nextExecutionTime = 0L;
task.shedExecutionTime = 0L;
task.owner = null;
break label0;
}
if(index < length) Array.copy(queue, index + 1, queue, index, length - index);
queue[this.length = length] = null;
task.flags = STATE_CANCELLED;
task.period = 0L;
task.nextExecutionTime = 0L;
task.shedExecutionTime = 0L;
task.owner = null;
monitor.notify();
}
}
return result;
}
private void clear() {
synchronized(monitor)
{
TimerTask[] queue = this.queue;
for(int i = length; i-- > 0; )
{
TimerTask task;
(task = queue[i]).flags = STATE_CANCELLED;
task.period = 0L;
task.nextExecutionTime = 0L;
task.shedExecutionTime = 0L;
task.owner = null;
queue[i] = null;
}
length = 0;
}
}
private void waitTask() {
Object monitor;
synchronized(monitor = this.monitor)
{
for(; ; )
{
int length = this.length;
TimerTask[] queue = this.queue;
try
{
long remainingTime;
if(length <= 0)
{
monitor.wait();
}
else if((remainingTime = queue[length - 1].nextExecutionTime - System.currentTimeMillis()) > 0L)
{
monitor.wait(remainingTime);
}
break;
}
catch(InterruptedException e)
{
e.printRealStackTrace();
}
}
}
}
private void push(TimerTask task) {
int length;
int index;
long time;
TimerTask[] queue;
if((length = this.length) == (queue = this.queue).length) Array.copy(queue, 0, queue = this.queue = new TimerTask[length << 1], 0, length);
index = length;
time = task.nextExecutionTime;
for(int i = 0; i < length; i++) if(queue[i].nextExecutionTime <= time)
{
Array.copy(queue, index = i, queue, index + 1, length - index);
break;
}
queue[index] = task;
this.length = length + 1;
}
private TimerTask pop() {
TimerTask result;
synchronized(monitor)
{
int length;
TimerTask[] queue;
if((length = this.length - 1) >= 0 && (result = (queue = this.queue)[length]).nextExecutionTime <= System.currentTimeMillis())
{
queue[this.length = length] = null;
} else
{
result = null;
}
}
return result;
}
}