Fix context in protocol callbacks#348
Conversation
|
My memory here is a little rusty, but can we instead change Lines 338 to 421 in 465717f |
|
Maybe yes - they're intended to bridge the native callbacks anyways, right? Submitted a commit to try this approach. I had to hack in the |
I think we need parallel APIs like |
|
Or add a trailing argument to all |
|
Got it, that makes sense - I'll then try to propose something more complete. |
|
/me is trying to fix this one now. |
Nice, what's the latest? ;) |
5f36d64 to
32979f8
Compare
uvloop/handles/handle.pyx
Outdated
| | +- UnixServer (pipe) | ||
| +- UVTimer (timer) | ||
| """ | ||
|
|
There was a problem hiding this comment.
This is awesome, thanks for adding it
70b6ae4 to
81d3900
Compare
6f41c33 to
e9b4056
Compare
ab49e7a to
b41a50d
Compare
This is a combined fix to correct contexts from which protocal callbacks are invoked. In short, callbacks like data_received() should always be invoked from consistent contexts which are copied from the context where the underlying UVHandle is created or started. The new test case covers also asyncio, but skipping the failing ones.
6c2d403 to
41844b6
Compare
A quick recap of uvloop core:
Loopis the uvloop-version of an asyncio event loop, exposing APIs to createUVHandles like TCP transports.UVHandleis the base class of uvloop wrappers of the libuvuv_handle_tstructs, see the full family below.UVHandlereferencesonezero or moreHandleinstances that encapsulate the actual callback, its arguments, and a PEP-567 context.cdeffunction perUVHandlethat is registered to the libuvuv_handle_tstruct. This function usually just triggers running theHandle.UVHandleusesHandlefor callbacks, and we don't want to change that.What is missing is e.g. thelisten_handleof someUVHandlesubclasses like theUVStreamServer. For now, it calls the actual callback (_on_listen) directly without PEP-567 context. So this PR should add those missingHandles.The tricky part is, the currentHandlesupports only fixed parameters provided at initialization, what is needed for callbacks like_on_listenor__uv_stream_on_readis a partial-likeHandle._run_with_param().List of
UVHandles to check:UVAsyncUVCheckUVIdleUVPollUVProcessUVProcessTransportUDPTransportUVStreamUVStreamServerUVTimerPrincipals
UVHandleinstance (including transports, servers, etc) sticks to one context where it was created from and/or started to take effect.UVHandle(mostly protocol callbacks, but also protocol factory) runs in the same context.UVHandleinstances share the same context - for example, protocol callbacks are always called in the same context even though the transport is upgraded bystart_tls()in a different context (even multiple times, a.k.a. SSL over SSL).Contextinstance - it can be a copied instance. Therefore, changes to aContextVarare not always carried between different protocol callbacks. But all callbacks could see the same inherited value from the context where theUVHandlewas created or started.Context.copy()orcopy_context()in user-triggered events, and reuse existingContextinstances for uvloop-triggered events, so as to avoid re-entering the same context twice.copy_context()is only applied to direct method calls, callbacks through e.g.loop.call_soon()are not considered necessary to copy the context.Example 1: Client Protocol
Expected result:
Example 2: Server Protocol
Expected result:
Example 3:
start_servingSimilar to example 2, but start serving in a different context:
Expected result:
Example 4: TLS Upgrade
Expected result: