Skip to content

Commit

Permalink
Re-check thread events immediately before blocking call.
Browse files Browse the repository at this point in the history
This is the likely cause of unreliable cross-thread events in
Queue and Fiber (which uses SizedQueue). The queue.pop logic
uses RubyThread.executeTask, which receives a function object for
unblocking and an argument to pass to that function. An interrupt
of the thread during this operation will call the function and
presumably wake the thread in some safe way. However, if the
interrupt triggered between the last event poll and the assignment
of the unblocker, it could be lost and the blocking call never
interrupted. This resulted in several thread/fiber tests having
unpredictable behavior. This also could trigger an improper
InterruptedException or ThreadError during a Fiber resume or
yield.

The fix here does an extra poll *after* assigning the unblocker,
so that any interrupts fired are executed before proceeding into
the blocking section.
  • Loading branch information
headius committed Dec 1, 2014
1 parent 3af5d23 commit 6ed286f
Showing 1 changed file with 5 additions and 0 deletions.
5 changes: 5 additions & 0 deletions core/src/main/java/org/jruby/RubyThread.java
Original file line number Diff line number Diff line change
Expand Up @@ -1258,7 +1258,12 @@ public <Data, Return> Return executeTask(ThreadContext context, Data data, Task<
try {
this.unblockFunc = task;
this.unblockArg = data;

enterSleep();

// check for interrupt before going into blocking call
context.pollThreadEvents();

return task.run(context, data);
} finally {
exitSleep();
Expand Down

0 comments on commit 6ed286f

Please sign in to comment.