Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes #7240 - Clarify and javadoc InvocationType. #7241

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

import java.util.concurrent.Callable;

import org.eclipse.jetty.util.Callback;

/**
* <p>A task (typically either a {@link Runnable} or {@link Callable}
* that declares how it will behave when invoked:</p>
Expand All @@ -33,9 +35,45 @@ public interface Invocable
{
static ThreadLocal<Boolean> __nonBlocking = new ThreadLocal<>();

/**
* <p>The behavior of an {@link Invocable} when it is invoked.</p>
* <p>Typically, {@link Runnable}s or {@link Callback}s declare their
* invocation type; this information is then used by the code that should
* invoke the {@code Runnable} or {@code Callback} to decide whether to
* invoke it directly, or submit it to a thread pool to be invoked by
* a different thread.</p>
*/
enum InvocationType
{
BLOCKING, NON_BLOCKING, EITHER
/**
* <p>Invoking the {@link Invocable} may block the invoker thread,
* and the invocation may be performed immediately (possibly blocking
* the invoker thread) or deferred to a later time, for example
* by submitting the {@code Invocable} to a thread pool.</p>
* <p>This invocation type is suitable for {@code Invocable}s that
* call application code, for example to process an HTTP request.</p>
*/
BLOCKING,
/**
* <p>Invoking the {@link Invocable} does not block the invoker thread,
* and the invocation may be performed immediately in the invoker thread.</p>
* <p>This invocation type is suitable for {@code Invocable}s that
* call implementation code that is guaranteed to never block the
* invoker thread.</p>
*/
NON_BLOCKING,
/**
* <p>Invoking the {@link Invocable} may block the invoker thread,
* but the invocation cannot be deferred to a later time, differently
* from {@link #BLOCKING}.</p>
* <p>This invocation type is suitable for {@code Invocable}s that
* themselves produce other {@code Invocable}s.</p>
* <p>The invocation of this {@code Invocable} causes the
* production of other, nested, {@code Invocable}s, which may be
* of type {@link #NON_BLOCKING} and therefore are invoked
* immediately, thus advancing a possibly stalled system.</p>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is too specific.
It is for tasks that can do useful/important work without blocking, but may block in some sub-tasks if allowed to do so by the invocation.

*/
EITHER
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -296,26 +296,26 @@ private SubStrategy selectSubStrategy(Runnable task, boolean nonBlocking)
case EITHER:
// The produced task may be run either as blocking or non blocking.

// If the calling producing thread may also block
if (!nonBlocking)
// If the calling producing thread is already non-blocking, use PC.
if (nonBlocking)
return SubStrategy.PRODUCE_CONSUME;

// Take the lock to atomically check if a pending producer is available.
try (AutoLock l = _lock.lock())
{
// Take the lock to atomically check if a pending producer is available.
try (AutoLock l = _lock.lock())
// If a pending producer is available or one can be started
if (_pending || _tryExecutor.tryExecute(_runPendingProducer))
{
// If a pending producer is available or one can be started
if (_pending || _tryExecutor.tryExecute(_runPendingProducer))
{
// use EPC: The producer directly consumes the task, which may block
// and then races with the pending producer to resume production.
_pending = true;
_state = State.IDLE;
return SubStrategy.EXECUTE_PRODUCE_CONSUME;
}
// Use EPC: the producer directly consumes the task, which may block
// and then races with the pending producer to resume production.
_pending = true;
_state = State.IDLE;
return SubStrategy.EXECUTE_PRODUCE_CONSUME;
}
}

// otherwise use PIC: The producer consumers the task in non-blocking mode
// and then resumes production.
// Otherwise use PIC: the producer consumes the task
// in non-blocking mode and then resumes production.
return SubStrategy.PRODUCE_INVOKE_CONSUME;

case BLOCKING:
Expand Down