modules/cldc-compact/src/main/java/java/util/__TimerThread__.java
// -*- Mode: Java; indent-tabs-mode: t; tab-width: 4 -*-
// ---------------------------------------------------------------------------
// SquirrelJME
// Copyright (C) Stephanie Gawroriski <xer@multiphasicapps.net>
// ---------------------------------------------------------------------------
// SquirrelJME is under the Mozilla Public License Version 2.0.
// See license.mkd for licensing and copyright information.
// ---------------------------------------------------------------------------
package java.util;
/**
* This is a thread which provides the basis for the timer.
*
* @since 2018/12/11
*/
final class __TimerThread__
extends Thread
{
/**
* Tasks which may be running, note that this is not a binary heap as
* Java SE says since there should not be thousands of running tasks.
* This is Java ME and timers are less likely to be heavy.
*/
final List<TimerTask> _tasks =
new ArrayList<>();
/** Cancel execution? */
volatile boolean _cancel;
/**
* Initializes the thread.
*
* @param __n The thread name.
* @throws NullPointerException On null arguments.
* @since 2018/12/11
*/
__TimerThread__(String __n)
throws NullPointerException
{
super(__n);
}
/**
* {@inheritDoc}
* @since 2018/12/11
*/
@Override
public final void run()
{
List<TimerTask> tasks = this._tasks;
// Constantly loop on our own lock since we will mess with things
for (;;)
synchronized (this)
{
if (this._cancel)
{
// Set all tasks to cancel
for (TimerTask t : tasks)
t._cancel = true;
// Clear all the tasks, because we no longer need them
tasks.clear();
// And just stop executing
return;
}
// Task to run
TimerTask execute = null;
// Need to determine how long to wait to run a task for
try
{
// If there are no tasks to run, then we wait forever
if (tasks.isEmpty())
this.wait();
// Otherwise, see how long we need to wait
else
{
// Need to determine if we are running this task
// or just waiting
TimerTask next = tasks.get(0);
long now = System.currentTimeMillis(),
sched = next._schedtime;
// We cancelled the task, so remove and do not bother
// at all
if (next._cancel)
{
tasks.remove(0);
continue;
}
// We can execute it!
else if (sched <= now)
{
execute = next;
tasks.remove(0);
}
// Wait around for it to happen, but another event
// could come before this!
else
this.wait(sched - now);
}
}
// If interrupted, try another run of the loop
catch (InterruptedException e)
{
continue;
}
// Execute if things are to be done
if (execute != null)
{
// We need to set the last one because fixed scheduling
// will set a new schedule time while delayed will wait
// on that
long schedtime = execute._schedtime;
execute._lastrun = schedtime;
// Fixed scheduling has it where the next event gets the
// period added to the scheduling time. This way if the
// task runs too slowly it gets built up.
boolean repeated = execute._repeated,
fixed = execute._fixed;
long period = execute._period;
if (repeated && fixed)
schedtime += period;
// Execute the task
execute._inrun = true;
try
{
execute.run();
}
catch (Throwable t)
{
// Ignore
t.printStackTrace();
}
execute._inrun = false;
// Repeat as long as the task is not cancelled
if (repeated && !execute._cancel)
{
// If not fixed use delay from the end of this
// execution
if (!fixed)
schedtime = System.currentTimeMillis() + period;
// Schedule for re-execution
execute._schedtime = schedtime;
this.__addTask(execute);
}
}
}
}
/**
* Adds the specified task.
*
* @param __task The task to add.
* @throws NullPointerException On null arguments.
* @since 2018/12/12
*/
private void __addTask(TimerTask __task)
throws NullPointerException
{
if (__task == null)
throw new NullPointerException("NARG");
List<TimerTask> tasks = this._tasks;
// Add task to the task list, but in task sorted order
// It is always inserted into the correct location
int dx = (tasks.isEmpty() ? 0 :
Collections.<TimerTask>binarySearch(tasks,
__task, new __TaskSchedComparator__()));
if (dx < 0)
dx = (-(dx) - 1);
// Add task at the index we found it should be at
tasks.add(dx, __task);
}
/**
* Schedules the task.
*
* @param __task The task to run.
* @param __first The time when the task should run.
* @param __rep Repeat the task?
* @param __fixed Fixed delays from execution?
* @param __period The period between each repetition.
* @throws IllegalArgumentException If the date is negative or the
* period is zero or negative.
* @throws IllegalStateException If a task was already scheduled, a task
* was cancelled, or this timer was cancelled.
* @throws NullPointerException On null arguments.
* @since 2018/12/11
*/
void __schedule(TimerTask __task, Date __first,
boolean __rep, boolean __fixed, long __period)
throws IllegalArgumentException, IllegalStateException,
NullPointerException
{
if (__task == null || __first == null)
throw new NullPointerException("NARG");
// Need to determine when
long datemilli = __first.getTime(),
nowtime = System.currentTimeMillis(),
diff = datemilli - nowtime;
/* {@squirreljme.error ZZ3m Cannot use a date which is far into the
past.} */
if (datemilli < 0)
throw new IllegalArgumentException("ZZ3m");
// Schedule immedietly?
if (diff < 0)
diff = 0;
// Forward since we use fixed delay schedule
this.__schedule(__task, diff, __rep, __fixed, __period);
}
/**
* Schedules the task.
*
* @param __task The task to run.
* @param __delay The delay before the first invocation.
* @param __rep Repeat the task?
* @param __fixed Fixed delays from execution?
* @param __period The period between each repetition.
* @throws IllegalArgumentException If the delay is negative or the
* period is zero or negative.
* @throws IllegalStateException If a task was already scheduled, a task
* was cancelled, or this timer was cancelled.
* @throws NullPointerException On null arguments.
* @since 2018/12/11
*/
void __schedule(TimerTask __task, long __delay,
boolean __rep, boolean __fixed, long __period)
throws IllegalArgumentException, IllegalStateException,
NullPointerException
{
if (__task == null)
throw new NullPointerException("NARG");
/* {@squirreljme.error ZZ3n The delay cannot be negative.} */
if (__delay < 0)
throw new IllegalArgumentException("ZZ3n");
/* {@squirreljme.error ZZ3o The period cannot be zero or negative.} */
if (__rep && __period <= 0)
throw new IllegalArgumentException("ZZ3o");
// When is the time to be scheduled?
long now = System.currentTimeMillis(),
sched = now + __delay;
// Lock on self
List<TimerTask> tasks = this._tasks;
synchronized (this)
{
/* {@squirreljme.error ZZ3p Cannot add a task to a timer which
was cancelled or a task which was cancelled.} */
if (this._cancel || __task._cancel)
throw new IllegalStateException("ZZ3p");
// Set task properties
__task._schedtime = sched;
__task._scheduled = true;
__task._repeated = __rep;
__task._fixed = __fixed;
__task._period = __period;
// Add the task
this.__addTask(__task);
// And notify that there is a new task in place
this.notifyAll();
}
}
}