Repository for lakemenbane
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
4.9 KiB

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2022
// www.magicbane.com
package engine.job;
import engine.server.MBServerStatics;
import java.util.PriorityQueue;
public class JobScheduler {
private static final JobScheduler INSTANCE = new JobScheduler();
private final PriorityQueue<JobContainer> jobs;
private volatile boolean alive;
private long timeOfKill = -1;
private JobScheduler() {
jobs = new PriorityQueue<>(MBServerStatics.SCHEDULER_INITIAL_CAPACITY);
Runnable worker = new Runnable() {
@Override
public void run() {
execution();
}
};
alive = true;
Thread t = new Thread(worker, "JobScheduler");
t.start();
}
public static JobScheduler getInstance() {
return INSTANCE;
}
/**
* This function schedules a job to execute in <i>timeToExecution</i>
* milliseconds from now.
*
* @param job
* @param timeToExecution
* @return
*/
public JobContainer scheduleJob(AbstractJob job, int timeToExecution) {
long timeOfExecution = System.currentTimeMillis() + timeToExecution;
JobContainer container = new JobContainer(job, timeOfExecution);
synchronized (jobs) {
jobs.offer(container);
jobs.notify();
}
return container;
}
/**
* This function schedules a job to execute at the absolute time of
* <i>timeOfExecution</i> (milliseconds).
*
* @param job
* @param timeOfExecution
* @return
*/
public JobContainer scheduleJob(AbstractJob job, long timeOfExecution) {
JobContainer container = new JobContainer(job, timeOfExecution);
synchronized (jobs) {
jobs.offer(container);
jobs.notify();
}
return container;
}
public boolean cancelScheduledJob(JobContainer container) {
return cancelScheduledJob(container.getJob());
}
public boolean cancelScheduledJob(AbstractJob job) {
JobContainer container = new JobContainer(job, -1);
boolean success = false;
synchronized (jobs) {
success = jobs.remove(container);
jobs.notify();
}
return success;
}
/**
* Stops the jobScheduler
*/
public void shutdown() {
if (alive) {
alive = false;
timeOfKill = System.currentTimeMillis();
synchronized (jobs) {
jobs.notify();
}
}
}
public JobContainer pollNextJobContainer() {
if (alive) {
throw new IllegalStateException("Can't poll jobs from a live scheduler.");
}
synchronized (jobs) {
return jobs.poll();
}
}
public long getTimeOfKill() {
return this.timeOfKill;
}
public boolean isAlive() {
return this.alive;
}
private void execution() {
long duration;
JobContainer container;
int compensation = MBServerStatics.SCHEDULER_EXECUTION_TIME_COMPENSATION;
while (alive) {
synchronized (jobs) {
container = jobs.peek();
if (container == null) {
// queue is empty, wait until notified (which happens after
// a new job is offered)
try {
jobs.wait(0);
} catch (InterruptedException ie) {
// do nothing
}
} else {
duration = container.timeOfExecution - System.currentTimeMillis();
if (duration < compensation) {
jobs.poll();
} else {
// enforce new loop
container = null;
// sleep until the head job execution time
try {
jobs.wait(duration);
} catch (InterruptedException ie) {
// do nothing
}
}
}
}
if (container != null) {
JobManager.getInstance().submitJob(container.job);
}
}
}
}