/*
* $Id$
*
* Copyright (C) 2003-2015 JNode.org
*
* This library is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; either version 2.1 of the License, or
* (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; If not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
package org.jnode.vm.scheduler;
import org.jnode.vm.Unsafe;
import org.jnode.vm.VmStackReader;
import org.jnode.vm.facade.VmThreadVisitor;
import org.jnode.vm.objects.VmSystemObject;
import org.jnode.annotation.KernelSpace;
import org.jnode.annotation.Uninterruptible;
import org.vmmagic.pragma.UninterruptiblePragma;
/**
* Queue of VmThread's.
* <p/>
* This class is not synchronized, but protected by PragmaUninterruptible's,
* since it is used by the scheduler itself.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
abstract class VmThreadQueue extends VmSystemObject {
protected final String name;
protected VmThreadQueueEntry first;
/**
* Create a new instance
*
* @param name
* @param sortByWakeupTime
*/
protected VmThreadQueue(String name) {
this.name = name;
}
/**
* Gets the first thread in the queue.
*
* @return VmThread
* @throws UninterruptiblePragma
*/
@KernelSpace
@Uninterruptible
final VmThread first() {
final VmThreadQueueEntry first = this.first;
if (first != null) {
return first.thread;
} else {
return null;
}
}
/**
* Gets the first thread in the queue that has its currentProcessor field
* set to null of the given processor.
*
* @param currentProcessor The processor making this request.
* @return VmThread
*/
@KernelSpace
@Uninterruptible
final VmThread first(VmProcessor currentProcessor) {
VmThreadQueueEntry entry = this.first;
while (entry != null) {
final VmThread thread = entry.thread;
if ((thread.currentProcessor == null)
|| (thread.currentProcessor == currentProcessor)) {
return thread;
}
entry = entry.next;
}
return null;
}
/**
* Invoke the visit method of the visitor for all threads in this queue.
*
* @param visitor
* @return false if the last visit returned false, true otherwise.
*/
public boolean visit(VmThreadVisitor visitor) {
VmThreadQueueEntry p = first;
while (p != null) {
if (!visitor.visit(p.thread)) {
return false;
}
p = p.next;
}
return true;
}
/**
* Is this queue empty?
*
* @return boolean
* @throws UninterruptiblePragma
*/
@KernelSpace
@Uninterruptible
final boolean isEmpty() {
return (first == null);
}
/**
* Add the given thread to the given queue. The thread is added after all
* thread with equal or higher priority.
*
* @param queue
* @param entry
* @param ignorePriority If true, the thread is always added to the back of the list,
* regarding its priority.
* @param caller
* @return The new queue.
* @throws UninterruptiblePragma
*/
@KernelSpace
@Uninterruptible
protected final VmThreadQueueEntry addToQueue(VmThreadQueueEntry queue,
VmThreadQueueEntry entry, boolean ignorePriority, String caller) {
entry.setInUse(this, caller);
if (queue == null) {
return entry;
} else if (ignorePriority) {
VmThreadQueueEntry t = queue;
while (t.next != null) {
t = t.next;
}
t.next = entry;
return queue;
} else {
final int priority = entry.thread.priority;
VmThreadQueueEntry t = queue;
if (priority > t.thread.priority) {
entry.setNext(t);
return entry;
}
while (t.next != null) {
if (priority > t.next.thread.priority) {
entry.next = t.next;
t.next = entry;
return queue;
}
t = t.next;
}
t.next = entry;
return queue;
}
}
/**
* Add the given thread to the given queue such that the queue is sorted by
* wakeup time. The nearest wakeup time is the first element in the queue.
*
* @param queue
* @param entry
* @param caller
* @return The new queue.
* @throws UninterruptiblePragma
*/
protected final VmThreadQueueEntry addToQueueSortByWakeupTime(
VmThreadQueueEntry queue, VmThreadQueueEntry entry, String caller)
throws UninterruptiblePragma {
entry.setInUse(this, caller);
if (queue == null) {
return entry;
} else {
long threadWakeup = entry.thread.wakeupTime;
VmThreadQueueEntry t = queue;
if (threadWakeup < t.thread.wakeupTime) {
entry.next = t;
return entry;
}
while (t.next != null) {
if (threadWakeup < t.next.thread.wakeupTime) {
entry.next = t.next;
t.next = entry;
return queue;
}
t = t.next;
}
t.next = entry;
return queue;
}
}
/**
* Remove the given thread from the given queue.
*
* @param queue
* @param entry
* @return The new queue.
* @throws UninterruptiblePragma
*/
@KernelSpace
@Uninterruptible
static VmThreadQueueEntry removeFromQueue(VmThreadQueueEntry queue,
VmThreadQueueEntry entry) {
if (queue == null) {
return queue;
} else if (entry == null) {
return queue;
} else if (queue == entry) {
VmThreadQueueEntry result = entry.next;
entry.next = null;
entry.setInUse(null, null);
return result;
} else {
VmThreadQueueEntry t = queue;
while ((t.next != null) && (t.next != entry)) {
t = t.next;
}
if (t.next == entry) {
t.next = entry.next;
entry.next = null;
entry.setInUse(null, null);
}
return queue;
}
}
/**
* Dump the status of this queue on Unsafe.debug.
*/
@KernelSpace
@Uninterruptible
final void dump(boolean dumpStack, VmStackReader stackReader) {
Unsafe.debug(name);
Unsafe.debug("-queue:\n");
VmThreadQueueEntry e = first;
if (e == null) {
Unsafe.debug("Empty\n");
} else {
while (e != null) {
Unsafe.debug(e.thread.getName());
Unsafe.debug(" id0x");
Unsafe.debug(e.thread.getId());
Unsafe.debug(" s0x");
Unsafe.debug(e.thread.getThreadState());
Unsafe.debug(" p0x");
Unsafe.debug(e.thread.priority);
Unsafe.debug("\n");
if (dumpStack && (stackReader != null)) {
stackReader.debugStackTrace(e.thread);
Unsafe.debug("\n");
}
e = e.getNext();
}
}
Unsafe.debug("\n");
}
/**
* Queue for all threads.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
static final class AllThreadsQueue extends VmThreadQueue {
/**
* Initialize this instance.
*/
public AllThreadsQueue(String name) {
super(name);
}
final void add(VmThread thread, String caller)
throws UninterruptiblePragma {
first = addToQueue(first, thread.allThreadsEntry, true, caller);
}
final void remove(VmThread thread) throws UninterruptiblePragma {
first = removeFromQueue(first, thread.allThreadsEntry);
}
}
/**
* Queue for all sleeping threads.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
static final class SleepQueue extends VmThreadQueue {
/**
* Initialize this instance.
*/
public SleepQueue(String name) {
super(name);
}
@Uninterruptible
final void add(VmThread thread, String caller) {
first = addToQueueSortByWakeupTime(first, thread.sleepQueueEntry,
caller);
}
@KernelSpace
@Uninterruptible
final void remove(VmThread thread) {
first = removeFromQueue(first, thread.sleepQueueEntry);
}
}
/**
* Queue used by the scheduler and monitors.
*
* @author Ewout Prangsma (epr@users.sourceforge.net)
*/
static final class ScheduleQueue extends VmThreadQueue {
/**
* Initialize this instance.
*/
public ScheduleQueue(String name) {
super(name);
}
@KernelSpace
@Uninterruptible
final void add(VmThread thread, boolean ignorePriority, String caller) {
first = addToQueue(first, thread.queueEntry, ignorePriority, caller);
}
@KernelSpace
@Uninterruptible
final void remove(VmThread thread) throws UninterruptiblePragma {
first = removeFromQueue(first, thread.queueEntry);
}
}
}