Skip to content

Waking a sleep triggers an expensive InterruptedException #9140

Description

@headius

RubyThread.sleep with a Lock currently uses a Condition to release and await that lock's signal:

public void sleep(Lock lock, long millis) throws InterruptedException {
assert Thread.currentThread() == getNativeThread();
executeTaskBlocking(getContext(), lock.newCondition(), Status.NATIVE, new Task<Condition, Object>() {
@Override
public Object run(ThreadContext context, Condition condition) throws InterruptedException {
if (millis == 0) {
condition.await();
} else {
condition.await(millis, TimeUnit.MILLISECONDS);
}
return null;
}
@Override
public void wakeup(RubyThread thread, Condition condition) {
thread.getNativeThread().interrupt();
}
});
}

In order to wake up the sleeping thread, this logic calls interrupt. This effectively terminates the sleep, but also raises an InterruptedException, which in turn requires a full stack trace and greatly adds to the overhead of a sleep wake-up.

This logic is used many places, such as for Mutex#sleep and ConditionVariable#await (which uses Mutex#sleep). The result is that the throughput of any sleep/wakeup or await/signal systems has much more overhead than it should. Waking a sleeping thread should require no more than signalling the sleep lock to unpark the sleeping thread and attempt to reacquire the lock.

This is a source of overhead in the Puma thread pool, resulting in excess allocation, GC, and VM synchronization overhead (to build the stack trace). See puma/puma#3788 for some discussion of this.

We need to fix this to do a simple condition-based signal to wake the sleeping thread.

This may also require some rework of how Mutex and ConditionVariable are implemented.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions