-
Notifications
You must be signed in to change notification settings - Fork 10.4k
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
EventEngine::Closure #27395
EventEngine::Closure #27395
Conversation
This introduces the new `Closure` type, and new cancellation semantics. I've also fixed a few bugs in the EventEngine iomgr implementation that had gone unnoticed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The API changes look good. I have a few comments about the implementation.
Please let me know if you have any questions. Thanks!
Reviewed 7 of 7 files at r1, all commit messages.
Reviewable status: all files reviewed, 3 unresolved discussions (waiting on @ctiller and @drfloob)
src/core/lib/iomgr/exec_ctx.cc, line 56 at r1 (raw file):
defined(GRPC_EVENT_ENGINE_REPLACE_EXEC_CTX) grpc_iomgr_event_engine()->Run( GrpcClosureToCallbackWithStatus(closure, error), {});
Does this actually work? EventEngine::Run()
now takes std::function<void()>
, not std::function<void(absl::Status)>
, but GrpcClosureToCallbackWithStatus()
returns the latter type.
src/core/lib/iomgr/event_engine/closure.h, line 28 at r1 (raw file):
/// Creates callbacks that take an error status argument. std::function<void(absl::Status)> GrpcClosureToCallbackWithStatus(
This API doesn't look quite right to me.
It looks like we're using this in two separate places, each of which actually needs something slightly different:
- The
on_shutdown
parameter toCreateListener()
. This is a case where the EE wants astd::function<void(absl::Status)>
and will generate theabsl::Status
parameter itself. In this case, there's no need to pass in thegrpc_error_handle
, because it won't be used; we just need thestd::function<>
to convert theabsl::Status
returned by the EE impl to agrpc_error_handle
before invoking thegrpc_closure
callback. - In
ExecCtx::Run()
, where we delegate toEventEngine::Run()
. This is a case where the EE wants astd::function<void()>
(note: noabsl::Status
parameter), and we want to just transparently pass thegrpc_error_handle
that was passed toExecCtx::Run()
to the resulting callback. In this case, the EE impl does not know or care about thegrpc_error_handle
; it's essentially just a pre-bound parameter in thestd::function<>
.
I think these two cases should be two different functions.
src/core/lib/iomgr/event_engine/timer.cc, line 41 at r1 (raw file):
auto handle = timer->ee_task_handle; if (!grpc_iomgr_event_engine()->Cancel(handle)) { // TODO(hork): This likely needs to be handled by the caller. An iomgr API
I think we can handle this here:
- In
timer_init()
, storeclosure
intimer->closure
. - Here in
timer_cancel()
, ifEventEngine::Cancel()
returns true, then we can callExecCtx::Run(timer->closure, GRPC_ERROR_CANCELLED)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks Mark, PTAL. All comments are addressed, and it now builds fine with bazel build --cxxopt='-DGRPC_USE_EVENT_ENGINE=1' --cxxopt="-DGRPC_EVENT_ENGINE_REPLACE_EXEC_CTX" ...
I wrote a simple Closure implementation, but stashed it for later when we have an EventEngine implementation to test against.
Reviewable status: all files reviewed, 3 unresolved discussions (waiting on @ctiller and @markdroth)
src/core/lib/iomgr/exec_ctx.cc, line 56 at r1 (raw file):
Previously, markdroth (Mark D. Roth) wrote…
Does this actually work?
EventEngine::Run()
now takesstd::function<void()>
, notstd::function<void(absl::Status)>
, butGrpcClosureToCallbackWithStatus()
returns the latter type.
Right, that wouldn't have worked. Fixed.
src/core/lib/iomgr/event_engine/closure.h, line 28 at r1 (raw file):
Previously, markdroth (Mark D. Roth) wrote…
This API doesn't look quite right to me.
It looks like we're using this in two separate places, each of which actually needs something slightly different:
- The
on_shutdown
parameter toCreateListener()
. This is a case where the EE wants astd::function<void(absl::Status)>
and will generate theabsl::Status
parameter itself. In this case, there's no need to pass in thegrpc_error_handle
, because it won't be used; we just need thestd::function<>
to convert theabsl::Status
returned by the EE impl to agrpc_error_handle
before invoking thegrpc_closure
callback.- In
ExecCtx::Run()
, where we delegate toEventEngine::Run()
. This is a case where the EE wants astd::function<void()>
(note: noabsl::Status
parameter), and we want to just transparently pass thegrpc_error_handle
that was passed toExecCtx::Run()
to the resulting callback. In this case, the EE impl does not know or care about thegrpc_error_handle
; it's essentially just a pre-bound parameter in thestd::function<>
.I think these two cases should be two different functions.
Thanks. There are 3 places we need closure conversions, and all have different requirements. I've split out 3 conversion functions:
std::function<void(Status)> GrpcClosureToStatusCallback(closure)
with no pre-bound error. Used inCreateListener
call, as you pointed out.std::function <void()> GrpcClosureToCallback(callback, error)
with a pre-bound argument. Used inExecCtx::Run
, as you pointed out.std::function <void()> GrpcClosureToCallback(callback)
used intimer_init
, without need for a bound error argument.
If we didn't mind binding an extra (possibly unnecessary) grpc_error_handle bound in the timer callback, we could reuse version 2 for timers.
src/core/lib/iomgr/event_engine/timer.cc, line 41 at r1 (raw file):
Previously, markdroth (Mark D. Roth) wrote…
I think we can handle this here:
- In
timer_init()
, storeclosure
intimer->closure
.- Here in
timer_cancel()
, ifEventEngine::Cancel()
returns true, then we can callExecCtx::Run(timer->closure, GRPC_ERROR_CANCELLED)
.
Nice. That lets us defer migrating callers to the new cancelation flow, which is helpful to say the least.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good. Just one remaining comment.
Reviewed 6 of 6 files at r2, all commit messages.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on @ctiller and @drfloob)
include/grpc/event_engine/event_engine.h, line 84 at r1 (raw file):
class Closure { public: // Closure's are an interface, and thus non-copyable.
Why are we making this copyable now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on @ctiller and @markdroth)
include/grpc/event_engine/event_engine.h, line 84 at r1 (raw file):
Previously, markdroth (Mark D. Roth) wrote…
Why are we making this copyable now?
The best alternative is to explicitly define a default constructor for the interface, which is not constructible (the default is implicitly deleted). I'll add that in, and make it non-copyable again. That's maybe preferable to allowing accidental copies of the Closure ... but I'm not certain the type should be non-copyable. gRPC doesn't have a use for copied Closures at the moment, but we're forcing that restriction on all public uses as well by putting it in the interface.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reviewed 1 of 1 files at r3, all commit messages.
Reviewable status: complete! all files reviewed, all discussions resolved (waiting on @ctiller)
include/grpc/event_engine/event_engine.h, line 84 at r1 (raw file):
Previously, drfloob (AJ Heller) wrote…
The best alternative is to explicitly define a default constructor for the interface, which is not constructible (the default is implicitly deleted). I'll add that in, and make it non-copyable again. That's maybe preferable to allowing accidental copies of the Closure ... but I'm not certain the type should be non-copyable. gRPC doesn't have a use for copied Closures at the moment, but we're forcing that restriction on all public uses as well by putting it in the interface.
Given that the whole point of introducing the Closure
type is to be able to use a pointer to the object as an identity, allowing the object to be copied would be counter to the intended use.
Anyway, this looks good.
Errors:
|
This introduces the new `Closure` type, and new cancellation semantics. I've also fixed a few bugs in the EventEngine iomgr implementation that had gone unnoticed.
This introduces the new
EventEngine::Closure
type, and new cancellation semantics. I'll update the gRFC and ping the mailing list with a notification of it, since this is a significant change.I've also fixed a few bugs in the EventEngine iomgr implementation that had gone unnoticed.
CC @Vignesh2208 @nicolasnoble
This change is