Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Fixed race condition. Worker thread always uses its own runQ, and loa…

…ds it from scheduler when empty.

Updated manual.
Some changes are cosmetic: changing tabs to spaces
	modified:   README.txt
	modified:   bench/kilim/bench/LotsOfTasks.java
	modified:   docs/manual.html
	deleted:    docs/manual.txt
	modified:   src/kilim/Cell.java
	modified:   src/kilim/Mailbox.java
	modified:   src/kilim/RingQueue.java
	modified:   src/kilim/Scheduler.java
	new file:   src/kilim/ShutdownException.java
	modified:   src/kilim/Task.java
	modified:   src/kilim/WorkerThread.java
	modified:   src/kilim/YieldReason.java
  • Loading branch information...
commit 8ee45f749545ac430f385654f7a3be56de38140b 1 parent 8fdb99a
@sriram-srinivasan sriram-srinivasan authored
View
4 README.txt
@@ -1,4 +1,4 @@
-Kilim v0.5
+Kilim v0.7
Copyright (c) 2006 Sriram Srinivasan.
(kilim _at_ malhar.net)
======================================================================
@@ -9,7 +9,7 @@ License file).
Please see docs/manual.txt and docs/kilim_ecoop08.pdf for a brief
introduction.
-This software depends on the ASM bytecode library (v 3.0).
+This software depends on the ASM bytecode library (v 2.2.3).
To build, you can either run "build.sh" on Unix or ant from the top
directory. Run "test.sh" or "ant test" to test.
View
71 bench/kilim/bench/LotsOfTasks.java
@@ -8,54 +8,81 @@
import kilim.*;
+// Usage: java kilim.bench.LotsOfTasks -ntasks
+// creates ntasks and waits for them to finish
+// Or
+//Usage: java kilim.bench.LotsOfTasks ntasks pause
+// creates ntasks, which in turn block indefinitely on their mailboxes.
public class LotsOfTasks {
static boolean block;
+ static int nTasks = 100000;
+ static int nRounds = 10;
+
public static void main(String[] args) throws Exception {
- // Usage: java kilim.bench.LotsOfTasks [ntasks] [pause]
- // pause will tell each task to wait on its mailbox
-
- final int numTasks = (args.length > 0) ? Integer.parseInt(args[0]) : 100000;
- final boolean block = (args.length > 1) ? true : false;
- final Stopwatch s = new Stopwatch("Tasks(" + numTasks + ")");
- for (int round = 0; round < 10; round++) {
+ try {
+ for (int i = 0; i < args.length; i++) {
+ String arg = args[i];
+ if (arg.equalsIgnoreCase("-nRounds")) {
+ nRounds = Integer.parseInt(args[++i]);
+ } else if (arg.equalsIgnoreCase("-nTasks")) {
+ nTasks = Integer.parseInt(args[++i]);
+ } else if (arg.equalsIgnoreCase("-block")) {
+ block = true;
+ }
+ }
+ } catch (NumberFormatException e) {
+ e.printStackTrace();
+ System.exit(0);
+ }
+ System.out.println("kilim.bench.LotsOfTasks -nTasks " + nTasks + (block ? " -block": "") + " -nRounds " + nRounds);
+
+ final Stopwatch s = new Stopwatch("Tasks(" + nTasks + ")");
+ for (int round = 1; round <= nRounds; round++) {
+ System.out.println("Round #" + round + " ================= ");
s.tick();
final Mailbox<ExitMsg> exitmb = new Mailbox<ExitMsg>();
-
- System.out.println("Creating " + numTasks + (block ? " blocking tasks" : " tasks"));
- for (int i = 1; i <= numTasks; i++) {
+
+ System.out.println("Creating " + nTasks + (block ? " blocking tasks" : " tasks"));
+ for (int i = 1; i <= nTasks; i++) {
Task t = new LTask();
t.informOnExit(exitmb);
t.start();
if (i % 100000 == 0) {
- System.out.println("Created " + i + " tasks .... (contd.)");
+ System.out.println(" created " + i + " tasks .... (contd.)");
}
}
-
- if (block) {
- for (int i = 1; i <= numTasks; i++) {
+ profilerMark(); // dummy method to study memory consumption at this stage
+ if (!block) {
+ System.out.println("Waiting for completion");
+ for (int i = 1; i <= nTasks; i++) {
exitmb.getb();
if (i % 100000 == 0) {
- System.out.println("Created " + i + " tasks .... (contd.)");
+ System.out.println(" " + i + " tasks finished.... (contd.)");
}
- };
- }
- System.out.println("Round #" + round + " done. " + numTasks + " created in " + s.tick() + " ms");
- s.tickPrint(numTasks);
+ }
+ ;
+ }
+ System.out.println("Round #" + round + " done:");
+ System.out.print(" ");
+ s.tickPrint(nTasks);
System.gc();
- Thread.sleep(1000); // give the GC a chance.
+ Thread.sleep(100); // give the GC a chance.
}
System.exit(0);
}
+ public static void profilerMark() {
+ // dummy method to help as a profiler breakpoint in JProfiler.
+ }
}
class LTask extends Task {
Mailbox<String> mymb = new Mailbox<String>();
-
+
public void execute() throws Pausable {
if (LotsOfTasks.block) {
mymb.get();
}
}
-
+
}
View
48 docs/manual.html
@@ -5,11 +5,12 @@
</head>
<body>
-<h1>Kilim. Release 0.5</h1>
-<p>Last updated: May 24, 2008.
+
+<h1>Kilim v0.7</h1>
+<p>Last updated: March 17, 2010
+
<p>by Sriram Srinivasan
-<p>University of Cambridge.
<p>Please send comments, encouragements, money, cakes, code fixes to
<b>kilim@malhar.net</b>. Thank you.
@@ -84,7 +85,7 @@
new MyThread().start();
</pre>
<p>Now, if you replace the words "Thread" with "Task", "run" with
-"execute" and add an <code>@pausable</code> annotation to <code>execute()</code>, you have a
+"execute" and add an exception called <code>Pausable</code> to <code>execute()</code>, you have a
Kilim Task. Simple.
<pre>
@@ -92,20 +93,25 @@
public class MyTask extends Task {
- @pausable
- public void execute() {
+ public void execute() throws Pausable{
}
}
</pre>
and to start it, you say <code>new MyTask().start()</code>
-<p>A method marked pausable is one that calls another pausable method; the
-built-in ones are Task.yield() and Task.sleep() (mailbox.get() calls
-Task.yield()).
-<p>The only difference is that you can spawn a million of these
-without turning your computer into a room heater. These tasks
-get executed on a thread pool.
+<p>The "Pausable" exception is used as an annotation, and is never actually thrown (it replaces
+@pausable from earlier versions). A method with such an annotation is deemed "pausable". Pausing refers to
+voluntarily yielding control to the scheduler so that another task may run. For example,
+Task.sleep() is a pausable method that pauses a task
+for a give time. Another example is Mailbox.get(), which pauses a task until a mailbox is
+non-empty.
+
+<p>A pausbale method is similar to blocking calls such as InputStream.read() and
+Thread.wait(), except that it makes its intention clear in its signature with
+the Pausable annotation. This annotation is used by the Kilim weaver to rewrite the bytecode
+of all pausable methods to incorporate the voluntary yielding logic. One important property
+of this scheme is that a pausable method can only be called by another pausable method.
<h1>Communication</h1>
@@ -128,12 +134,9 @@
mb.put("hello");
String s = mb.get();
</pre>
-<p>These two methods block the task (not the java Thread) when they are
-unable to perform the operation. How does one know ? They are marked
-<code>@pausable</code>.
+<p>These two methods pause the task when they are unable to perform the operation.
-<p><code>mailbox.getnb()</code> and <code>putnb()</code> are the non-blocking versions: they are
-not pausable, and they return quickly.
+<p><code>mailbox.getnb()</code> and <code>putnb()</code> are variants that neither pause the task, nor block the thread. They return immediately indicating whether they were able to dequeue (respectively enqueue) an object from the mailbox.
<p><code>mailbox.getb()</code> and putb are the *thread*-blocking versions. Use them if you want to wait for a message but cannot make the calling method
pausable (like <code>main()</code>, for example). You shouldn't be using these
@@ -145,10 +148,9 @@
<p>This package comes with a bytecode transformation tool called Weaver
(package: kilim.tools.Weaver) that post-processes .class files
-looking for the @pausable annotation.
+looking for the "throws Pausable" annotation.
-<p>When a task needs to block (or "pause", calling <code>Task.sleep()</code>, for
-example), the task unwinds its stack, squirrels away all state that
+<p>When a task needs to pause, it unwinds its stack, squirrels away all state that
it'll need later on resumption. This unwinding and rewinding the
stack is automatically performed by the code introduced by the Weaver.
(Debug information is adjusted so that the transformed code can be
@@ -159,7 +161,6 @@
the Workshop on New Horizons in Compilers (2006). A simple introduction
to CPS is in the accompanying IFAQ.txt.
-
<h1>Building, running the examples</h1>
<p>Build the sources by running ant (or build.sh) at the topmost
@@ -179,12 +180,11 @@
<pre> java -cp ./classes kilim.examples.SimpleTask</pre>
<p>Create a million tasks just for the heck of it.
-<p> Try <code>java kilim.bench.LotsOfTasks 1000000</code>
-<p> (Notice the JIT's effect after the first round)
+<p> Try <code>java kilim.bench.LotsOfTasks -ntasks 300000</code>
<p>You can supply a different directory for the weaver's output, but
remember to include that directory in the classpath before the
-original, otherwise you will "class not woven" errors at run time.
+original, otherwise you will see "class not woven" errors at run time.
<p>NOTE: It is safer (and convenient) to supply the entire directory to
weave, like this:
View
210 docs/manual.txt
@@ -1,210 +0,0 @@
-(Copyright 2007 Sriram Srinivasan)
-======================================================================
-Kilim. Release 0.5
-Last updated: May 24, 2008.
-
-by Sriram Srinivasan
-University of Cambridge.
-
-Please send comments, encouragements, money, cakes, code fixes to
-kilim@malhar.net. Thank you.
-
-======================================================================
-What is Kilim?
-======================================================================
-A Java framework for fast, safe, cheap message passing.
-
-The message passing (MP) paradigm is often seen as a superior
-alternative to the typical mix of idioms in concurrent (shared-memory,
-locks) and distributed programming (CORBA/RMI). MP eliminates worries
-endemic to the shared-memory mindset: lock ordering, failure-coupling,
-low-level data races and memory models. It simplifies synchronization
-between data and control planes (no lost signals or updates), and
-unifies APIs for local and remote process interaction.
-
-Curiously however, there are no efficient _and_ safe frameworks for
-intra-process message-passing, except for Ada and Erlang. The Kilim
-framework is intended to fix this state of affairs. It provides:
-
-1. Extremely lightweight user-level threads (actors) with automatic
- stack management, obtained via CPS transformation.
-
-2. A simple type system that ensures actor isolation by controlling
- pointer aliasing in messages at compile time, and by ensuring
- linear ownership of mutable message objects. This permits safe,
- zero-copy communication.
- (NOTE: This feature is NOT included in this release because it
- is undergoing a rewrite. The docs/kilim_ecoop08.pdf paper gives
- details about what you can expect).
-
-3. A compact run-time library containing typed mailboxes (with
- optional flow control), user-definable scheduling and python style
- generators.
-
-Kilim is portable; one of our explicit goals was to not require
-changes to the Java language syntax or to the JVM.
-
-Kilim scales comfortably to handle hundreds of thousands of actors and
-messages on modest hardware. It is fast as well ­ task-switching is
-1000x faster than Java threads and 60x faster than other lightweight
-tasking frameworks, and message-passing is 3x faster than Erlang
-(currently the gold standard for concurrency-oriented programming).
-
-The term "Kilim" refers to a class of rugs in a number of
-middle-eastern and central european countries. Kilims are light and
-are flat-woven with thin threads (as opposed to deep-pile carpets).
-
-======================================================================
-Getting started.
-======================================================================
-The first few pages of the docs/kilim_ecoop08 paper give an overview
-of the facilities and the programming model.
-
-Take a look at the examples to get an idea. The only important classes
-to begin with are kilim.Task and kilim.Mailbox.
-
-Let's start with conventional thread programming. This is how you
-create your own thread in Java.
-
- class MyThread extends Thread {
- public void run() {
- }
- }
-
-And spawn a thread thus:
- new MyThread().start();
-
-Now, if you replace the words "Thread" with "Task", "run" with
-"execute" and add a @pausable annotation to execute(), you have a
-Kilim Task. Simple.
-
- import kilim.*;
-
- public class MyTask extends Task {
-
- @pausable
- public void execute() {
- }
- }
-and to start it, you say "new MyTask().start()"
-
-A method marked pausable is one that calls another pausable method; the
-built-in ones are Task.yield() and Task.sleep() (mailbox.get() calls
-Task.yield()).
-
-The only difference is that you can spawn a million of these
-without turning your computer into a room heater. These tasks
-get executed on a thread pool.
-
-======================================================================
-Communication
-======================================================================
-
-Mailboxes are the medium of communication between tasks. They are
-typed buffers that can have at most one consumer task waiting on it at
-any point in time, but multiple producers are allowed. Mailboxes are
-not owned by anyone (unlike Erlang's process mailbox). They can be
-static fields, instance variables, local variables .. it is your
-design choice. They can even be sent as part of messages themselves,
-which can make for an extremely dynamic and mobile topology.
-
-Creating a mailbox:
- // This mailbox only allows Strings
- Mailbox<String> mb = new Mailbox<String>();
-
-Sending and receiving messages:
- mb.put("hello");
- String s = mb.get();
-
-These two methods block the task (not the java Thread) when they are
-unable to perform the operation. How does one know ? They are marked
-@pausable.
-
-mailbox.getnb() and putnb() are the non-blocking versions: they are
-not pausable, and they return quickly.
-
-mailbox.getb() and putb are the *thread*-blocking versions. Use them
-if you want to wait for a message but cannot make the calling method
-pausable (like main(), for example). You shouldn't be using these
-inside a task.
-
-======================================================================
-How does it work?
-======================================================================
-First, the lightweight thread part.
-
-This package comes with a bytecode transformation tool called Weaver
-(package: kilim.tools.Weaver) that post-processes .class files
-looking for the @pausable annotation.
-
-When a task needs to block (or "pause", calling Task.sleep(), for
-example), the task unwinds its stack, squirrels away all state that
-it'll need later on resumption. This unwinding and rewinding the
-stack is automatically performed by the code introduced by the Weaver.
-(Debug information is adjusted so that the transformed code can be
-debugged inside eclipse)
-
-The transformation is a variation of continuation passing style; the
-details are in the paper entitled "A Thread of Ones Own" presented at
-the Workshop on New Horizons in Compilers (2006). A simple introduction
-to CPS is in the accompanying IFAQ.txt.
-
-======================================================================
-Building, running the examples
-======================================================================
-Build the sources by running ant (or build.sh) at the topmost
-level.
-
-To manually compile a kilim task (say kilim.examples.SimpleTask),
-
-Now, compile (into "./classes")
- javac -d ./classes ./examples/kilim/examples/SimpleTask.java
-
-Weave the class (and overwrite it).
- java kilim.tools.Weaver -d ./classes kilim.examples.SimpleTask
-
-Run it like any regular java program.
- java -cp ./classes kilim.examples.SimpleTask
-
-Create a million tasks just for the heck of it.
- Try java kilim.bench.LotsOfTasks 1000000
- (Notice the JIT's effect after the first round)
-
-You can supply a different directory for the weaver's output, but
-remember to include that directory in the classpath before the
-original, otherwise you will "class not woven" errors at run time.
-
-NOTE: It is safer (and convenient) to supply the entire directory to
-weave, like this:
-
- java kilim.tools.Weave -d ./classes ./classes
- ^^^^^^^^^^
-
-That eliminates the chances of mistakenly omitting to weave inner
-and anonymous classes.
-
-Eclipse notes:
--------------
-
-Loading kilim under eclipse is like any other java project.
-Select File -> New -> Java Project,
-"Create project from existing source"
-
-There is no plugin (yet) to run the weaver automatically; you will have
-to run the weaver separately in the command line. If you are changing
-the kilim examples, you can just run "build.sh" or "ant" from the
-command line once the project's been created.
-
-Debugging and profiling should work as usual.
-
-======================================================================
-
-Future directions
-
-The immediate future release will include the type system for process isolation and
-then, remote mailboxes for distributed programming.
-
-Suggestions most welcome and will be duly acknowledged.
-
---Sriram Srinivasan
-(kilim _at_ malhar.net)
View
8 src/kilim/Cell.java
@@ -71,19 +71,19 @@ public T get(EventSubscriber eo) {
* @return buffered message if there's one, or null
*/
public boolean put(T amsg, EventSubscriber eo) {
- boolean ret = true; // assume we'll be able to enqueue
+ boolean ret = true; // assume we'll be able to enqueue
EventSubscriber subscriber;
synchronized(this) {
if (amsg == null) {
throw new NullPointerException("Null message supplied to put");
}
if (msg == null) { // space available
- msg = amsg;
+ msg = amsg;
subscriber = sink;
sink = null;
} else {
- ret = false;
- // unable to enqueue. Cell is full
+ ret = false;
+ // unable to enqueue. Cell is full
subscriber = null;
if (eo != null) {
srcs.add(eo);
View
3  src/kilim/Mailbox.java
@@ -78,6 +78,7 @@ public T get(EventSubscriber eo) {
if (n > 0) {
int ic = icons;
msg = msgs[ic];
+ msgs[ic] = null;
icons = (ic + 1) % msgs.length;
numMsgs = n - 1;
@@ -317,7 +318,7 @@ public void putb(T msg, final long timeoutMillis) {
}
public synchronized int size() {
- return numMsgs;
+ return numMsgs;
}
public synchronized boolean hasMessage() {
View
65 src/kilim/RingQueue.java
@@ -2,28 +2,31 @@
public class RingQueue<T> {
protected T[] elements;
- protected int iprod; // producer index
- protected int icons; // consumer index;
+ protected int iprod; // producer index
+ protected int icons; // consumer index;
protected int maxSize;
protected int size;
public RingQueue(int initialSize) {
this(initialSize, Integer.MAX_VALUE);
}
+
public RingQueue(int initialSize, int maxSize) {
- elements = (T[])new Object[initialSize];
- size = 0 ;
+ elements = (T[]) new Object[initialSize];
+ size = 0;
this.maxSize = maxSize;
}
- public int size() {return size;}
+ public int size() {
+ return size;
+ }
public T get() {
T elem;
T[] elems;
int n = size;
if (n > 0) {
- elems = elements;
+ elems = elements;
int ic = icons;
elem = elems[ic];
elems[ic] = null;
@@ -31,7 +34,7 @@ public T get() {
size = n - 1;
} else {
elem = null;
- }
+ }
return elem;
}
@@ -42,7 +45,7 @@ public boolean put(T elem) {
}
int ip = iprod;
int ic = icons;
- int n = size;
+ int n = size;
if (n == elements.length) {
assert ic == ip : "numElements == elements.length && ic != ip";
if (n < maxSize) {
@@ -66,33 +69,35 @@ public boolean put(T elem) {
}
return ret;
}
-
+
public boolean contains(T obj) {
- int i = icons;
- int c = 0;
- T[] elems = elements;
- while (c < size) {
- if (obj == elems[i]) return true;
- i = (i + 1) % elems.length;
- c++;
- }
- return false;
+ int i = icons;
+ int c = 0;
+ T[] elems = elements;
+ while (c < size) {
+ if (obj == elems[i])
+ return true;
+ i = (i + 1) % elems.length;
+ c++;
+ }
+ return false;
}
-
+
public void reset() {
- icons = iprod = 0;
+ icons = iprod = 0;
}
+
@Override
public String toString() {
- StringBuilder sb = new StringBuilder();
- int i = icons;
- int c = 0;
- T[] elems = elements;
- while (c < size) {
- sb.append(elems[i]);
- i = (i + 1) % elems.length;
- c++;
- }
- return sb.toString();
+ StringBuilder sb = new StringBuilder();
+ int i = icons;
+ int c = 0;
+ T[] elems = elements;
+ while (c < size) {
+ sb.append(elems[i]);
+ i = (i + 1) % elems.length;
+ c++;
+ }
+ return sb.toString();
}
}
View
97 src/kilim/Scheduler.java
@@ -21,8 +21,8 @@
public static Scheduler defaultScheduler = null;
public static int defaultNumberThreads;
public LinkedList<WorkerThread> allThreads = new LinkedList<WorkerThread>();
- public LinkedList<WorkerThread> waitingThreads = new LinkedList<WorkerThread>();
- protected boolean shutdown = false;
+ public RingQueue<WorkerThread> waitingThreads = new RingQueue<WorkerThread>(10);
+ protected volatile boolean shutdown = false;
public RingQueue<Task> runnableTasks = new RingQueue<Task>(100);
static {
@@ -42,11 +42,23 @@ public Scheduler(int numThreads) {
for (int i = 0; i < numThreads; i++) {
WorkerThread wt = new WorkerThread(this);
allThreads.add(wt);
- waitingThreads.add(wt);
+ addWaitingThread(wt);
wt.start();
}
}
+ void addWaitingThread(WorkerThread wt) {
+ synchronized (waitingThreads) {
+ waitingThreads.put(wt);
+ }
+ }
+
+ WorkerThread getWaitingThread() {
+ synchronized(waitingThreads) {
+ return waitingThreads.get();
+ }
+ }
+
/**
* Schedule a task to run. It is the task's job to ensure that
* it is not scheduled when it is runnable.
@@ -57,9 +69,8 @@ public void schedule(Task t) {
synchronized(this) {
assert t.running == true : "Task " + t + " scheduled even though running is false";
runnableTasks.put(t);
- if (!waitingThreads.isEmpty())
- wt = waitingThreads.poll();
}
+ wt = getWaitingThread();
if (wt != null) {
synchronized(wt) {
wt.notify();
@@ -74,39 +85,45 @@ public void shutdown() {
}
}
+ public boolean isShutdown() {
+ return shutdown;
+ }
+
/**
- * This is called in the WorkerThread's stack and blocks until a task is available
- *
+ * This is called in the WorkerThread's stack. It transfers a runnable task to the given worker thread's
+ * list of runnables. If the task prefers a different worker thread, then the search continues (after notifying
+ * the other thread that it has a task to execute).
+ *
* @return
*/
- Task getNextTask(WorkerThread wt) {
+ void loadNextTask(WorkerThread wt) throws ShutdownException {
while (true) {
Task t = null;
WorkerThread prefThread = null;
///////////////
synchronized(this) {
- if (shutdown) return null;
-
- if ((t = wt.getNextTask()) != null) {
- return t;
- }
+ if (shutdown) throw new ShutdownException();
t = runnableTasks.get();
if (t == null) {
- waitingThreads.add(wt);
+ // WorkerThread will add itself to waitingThreads in WorkerThread.getNextTask()
+ break;
} else {
prefThread = t.preferredResumeThread;
+ if (prefThread == null || prefThread == wt) {
+ wt.addRunnableTask(t);
+ break; // Supplied worker thread has work to do
+ } else {
+ // The task states a preferred thread which is not the supplied worker thread
+ // Enqueue it and continue searching.
+ prefThread.addRunnableTask(t);
+ synchronized(prefThread) {
+ prefThread.notify();
+ }
+ }
}
}
/////////////
- if (t == null) {
- wt.waitForMsgOrSignal();
- } else if (prefThread == null || prefThread == wt) {
- assert t.currentThread == null: " Task " + t + " already running";
- return t;
- } else {
- prefThread.addRunnableTask(t);
- }
}
}
@@ -121,23 +138,23 @@ public static void setDefaultScheduler(Scheduler s) {
defaultScheduler = s;
}
- public void dump() {
- System.out.println(runnableTasks);
-// for (WorkerThread w: allThreads) {
-// w.dumpStack();
-// }
- }
+ public void dump() {
+ System.out.println(runnableTasks);
+// for (WorkerThread w: allThreads) {
+// w.dumpStack();
+// }
+ }
- public static boolean isRunnable(Task task) {
- Scheduler s = defaultScheduler;
- synchronized (s) {
- if (s.runnableTasks.contains(task)) {
- return true;
- }
- for (WorkerThread wt: s.allThreads) {
- if (wt.tasks.contains(task)) return true;
- }
- }
- return false;
- }
+ public static boolean isRunnable(Task task) {
+ Scheduler s = defaultScheduler;
+ synchronized (s) {
+ if (s.runnableTasks.contains(task)) {
+ return true;
+ }
+ for (WorkerThread wt: s.allThreads) {
+ if (wt.tasks.contains(task)) return true;
+ }
+ }
+ return false;
+ }
}
View
8 src/kilim/ShutdownException.java
@@ -0,0 +1,8 @@
+package kilim;
+
+public class ShutdownException extends Exception {
+
+ public ShutdownException() {
+ // TODO Auto-generated constructor stub
+ }
+}
View
4 src/kilim/Task.java
@@ -349,7 +349,7 @@ public static void yield(Fiber f) {
if (f.pc == 0) {
f.task.setPauseReason(yieldReason);
} else {
- f.task.setPauseReason(null);
+ f.task.setPauseReason(null);
}
f.togglePause();
}
@@ -446,7 +446,7 @@ public void _runExecute(WorkerThread thread) throws NotPausable {
}
if (isDone) {
- done = true;
+ done = true;
// inform on exit
if (numActivePins > 0) {
throw new AssertionError("Task ended but has active locks");
View
39 src/kilim/WorkerThread.java
@@ -27,20 +27,51 @@
public void run() {
try {
while (true) {
- Task t = scheduler.getNextTask(this); // blocks until task available
- if (t == null)
- break; // scheduler shut down
+ Task t = getNextTask(this); // blocks until task available
runningTask = t;
t._runExecute(this);
runningTask = null;
}
+ } catch (ShutdownException se) {
+ // nothing to do.
+ } catch (OutOfMemoryError ex) {
+ System.err.println("Out of memory");
+ System.exit(1);
} catch (Throwable ex) {
ex.printStackTrace();
- System.out.println(runningTask);
+ System.err.println(runningTask);
}
runningTask = null;
}
+ protected Task getNextTask(WorkerThread workerThread) throws ShutdownException {
+ Task t = null;
+ while (true) {
+ if (scheduler.isShutdown())
+ throw new ShutdownException();
+
+ t = getNextTask();
+ if (t != null)
+ break;
+
+ // try loading from scheduler
+ scheduler.loadNextTask(this);
+ synchronized(this) { /////////////////////////////////////////
+ // Wait if still no task to execute.
+ t = tasks.get();
+ if (t != null)
+ break;
+
+ scheduler.addWaitingThread(this);
+ try {
+ wait();
+ } catch (InterruptedException ignore) {} // shutdown indicator checked above
+ } ////////////////////////////////////////////////////////////
+ }
+ assert t != null: "Returning null task";
+ return t;
+ }
+
public Task getCurrentTask() {
return runningTask;
}
View
2  src/kilim/YieldReason.java
@@ -13,6 +13,6 @@ public boolean isValid(Task t) {
}
@Override
public String toString() {
- return "yield";
+ return "yield";
}
}
Please sign in to comment.
Something went wrong with that request. Please try again.