-
Notifications
You must be signed in to change notification settings - Fork 12.7k
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
std::uv::global_loop and std::timer #2261
Closed
Closed
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
adding two pointers fields to rust_kernel :( .. have to do manual malloc/free for one of the fields, which feels wrong
- starting/stoping the loop based on client work is functioning, correctly - the issue appears to be that, when the process is about to exit, the signal to let weak tasks know that they need to exit isn't getting fired.
.. seeing an occasional valgrind/barf spew on some invalid read/writes.. need to investigate further.. i think its related to my poor citizen conduct, re: pointers stashed in rust_kernel..
- moved global loop tests, as well.. will add tests in uv_hl that encompass rolling your own high_level_loop via uv::hl::run_high_level_loop() - also whitespace cleanups and misc warning cleanup.. - doesn't work on 32bit linux
.. fixes issue, in previous commit, with global loop test hanging on 32bit linux (this was because the struct was too small, so (presumably), the data member was garbled.. yippy)
.. leveraging std::uv, we have: timer::delayed_send - send a value over a provided channel after the timeout has passed timer::sleep - block the current task for the specified period both of these fns (and everything that goes in timer.rs) leverage the uv_timer_* API
Thanks for all this work and for providing such a thorough description in the pull request! |
Merged. |
bors
added a commit
to rust-lang-ci/rust
that referenced
this pull request
Sep 22, 2022
make rustfmt mandatory and used pinned toolchain Looks like this is what most people prefer/expect, and using a pinned toolchain for formatting avoids some (rare and so far mostly hypothetical) formatting inconsistency issues.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
At a high-level, this pull request contains:
std::uv::hl
module (provides stuff needed to run a "high-level", rust-managed loop with hooks for user-supplied logic/environmentstd::uv::global_loop
module, which provides a single, process-wide event loop leverage the types and functions built out instd::uv::hl
std::timer
module, which usesstd::uv::global_loop
to provide a high-level interface to the libuvuv_timer_*
API.std::uv::hl
A set of functions and types to interact safely with a libuv, primarily from rust code. The test and functions in the test module provide a pretty good overview of how to do work it (including the bare minimum to roll-your-own
high_level_loop
)std::uv::global_loop
As mentioned above, this is the process-wide event loop that (presumably) stdlib developers can use to expose high-level functionality to libuv.
There are two, full implementations that are present at this time:
get_single_task_gl
function (exported but hidden in docs) provides a libuv loop that consumes a single task/single-threaded-scheduler. This was my original implementation and, while (ostensibly) lighter-weighter in message/task traffic, it most likely has some race conditions.get_monitor_task_gl
function (also exported but hidden in docs) gives access to a libuv loop that's implemented over two tasks (each running in their own single-threaded scheduler). This is the implementation that is wired up touv::global_loop::get()
, which is the only fn from this module that appears in the docsI want to work on the single-task global loop a bit more and, eventually, set up some profiling between the two versions (to test under load). But for now we're shipping what (should) be a race-free version.
NOTE: Do not use both of the above functions within the scope of a single-process lifetime (always use one or the other, but not both). Using just
std::uv::global_loop::get
should (obviously) be your first choice 99.999999% of the time.If we're satisfied, relatively speaking, with the perf of the
get_monitor_task_gl()
impl I'll just drop theget_single_task_loop
impl.std::timer
Provides a few useful functions that use libuv's timer API. Currently only three exported functions:
timer::delayed_send
- send a msg after the provided timeouttimer::sleep
- block the task this is called in for the specified time periodtimer::recv_timeout
- block on recv for up to the specified timeout. If a msg is recv'd on the provided port before the timeout expires, we returnsome(T)
, otherwise if the timeout period passes without a msg on the provided port, we returnnone
.Interestingly, it seems like
timer::delayed_send
is the primitive upon which you can build everything else in the module, AFAIK.I also wanted to add a more tradition timer interface that just takes a cb and calls it repeatedly in a new task until it returns false, but didn't get around to it.
The implementation, here, is the first non-infrastructure/proof-of-concept use of
std::uv::*
. hooray!still unresolved
high_level_loop
's internal reference counting scheme (that sits atop the libuv refcount scheme). I think I have something in mind (a resource, stored in a shared box, that will tie the struct value to a given task.. with some automated setup/teardown), but it's not quite ironed out yet (and places its own burden on the user). For now, we have theuv::hl::ref
,uv::hl::unref
anduv::hl::unref_and_close
fns. Any code that uses libuv structs, on the stack should make sure to:ref
at or before the time you make auv_init_*
call with the ptr to the struct value.unref
anduv_close
before the task containing the struct exits. This is not always straightforward and requires some thoughtful synchronization via ports/msgs that I'm still working. The tests inhl
,global_loop
and the impl instd::timer
should different examples/approaches for doing this safely. It's an ongoing thing.core
? Probably want to let it prove itself, first.up next
std::uv::ll
) and write tests