Skip to content
Permalink
Browse files
Re-check thread events immediately before blocking call.
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 6ed286f178c0c536bf56cf899f3f19de965299ca
Showing with 5 additions and 0 deletions.
  1. +5 −0 core/src/main/java/org/jruby/RubyThread.java
@@ -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();

0 comments on commit 6ed286f

Please sign in to comment.