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

feat(s2n-quic-core): add sync::worker module #1728

Merged
merged 1 commit into from
Apr 27, 2023
Merged

Conversation

camshaft
Copy link
Contributor

Description of changes:

The change adds a synchronization module that I've extracted from the AF_XDP work. The module is useful for scenarios where a worker needs a mechanism to know if it has outstanding work to do and a way for work producers to wake it up if it's gone to sleep.

In the AF_XDP provider, there isn't a mechanism to poll on the completion queue so we're left with busy polling. The problem is we only need to busy poll while there is outstanding packets in the TX queue.

Call-outs:

I've refactored some of the spsc code to make it easier to share the testing facilities between the two modules.

Testing:

This includes a few loom tests to check that it behaves correctly in all ordering interleavings. It actually caught an error where the Sender didn't implement drop and notified the Receiver, thus resulting in a deadlock. Pretty cool!

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@camshaft camshaft marked this pull request as ready for review April 25, 2023 20:32
@harrisonkaiser harrisonkaiser self-requested a review April 25, 2023 23:45
@camshaft camshaft merged commit 992ca37 into main Apr 27, 2023
@camshaft camshaft deleted the camshaft/sync-worker branch April 27, 2023 00:27
}

struct State {
remaining: CachePadded<AtomicUsize>,
Copy link
Contributor

Choose a reason for hiding this comment

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

Did you test with and without CachePadded and did it make a noticeable difference in performance?

Note that N is just a reasonable guess and is not guaranteed to match the actual cache line length of the machine the program is running on.

From the crate, which makes me a bit wary of premature optimization.

macro_rules! acquire {
() => {{
// take the credits that we've been given by the senders
self.credits += state.remaining.swap(0, Ordering::Acquire);
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you want AcqRel since swap does a store and load

Copy link
Contributor

Choose a reason for hiding this comment

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

spoke offline: in the swap operation itself is atomic so the load and store happen atomically. We read the credits and reset them to 0.

The ordering simply implies ordering with other atomic store operations, which is not critical to correct operation and happen in a relaxed manner.

Note that using Acquire makes the store part of this operation Relaxed

Comment on lines +62 to +64
// make one last effort to acquire credits in case a sender submitted some while we were
// registering the waker
acquire!();
Copy link
Contributor

Choose a reason for hiding this comment

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

What happens if we dont call this? We would just wake up right? Should we de-register the waker if we were able to acquire credits?

Copy link
Contributor

Choose a reason for hiding this comment

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

spoke offline: we need to check otherwise it possible to deadlock. sender tried waking receive but since it wasnt registered, it will never wake.

It not critical to de-register since we will simply wake up pre-maturely at worse, but thats not expected to happen or be detrimental.

Comment on lines +179 to +183
// loom tests will still run after returning so we don't need to join
if cfg!(not(loom)) {
sender.join().unwrap();
receiver.join().unwrap();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

what does this mean? how do they keep running after returning?

Copy link
Contributor

Choose a reason for hiding this comment

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

spoke offline: these tests can be run under loom or not. under loom we dont need to join, without it we do.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants