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

Use semaphores for thread parking on Apple platforms #102773

Merged
merged 4 commits into from
Oct 15, 2022

Conversation

joboet
Copy link
Member

@joboet joboet commented Oct 7, 2022

Currently we use a mutex-condvar pair for thread parking on Apple systems. Unfortunately, pthread_cond_timedwait uses the real-time clock for measuring time, which causes problems when the system time changes. The parking implementation in this PR uses a semaphore instead, which measures monotonic time by default, avoiding these issues. As a further benefit, this has the potential to improve performance a bit, since unpark does not need to wait for a lock to be released.

Since the Mach semaphores are poorly documented (I could not find availability or stability guarantees for instance), this uses a dispatch semaphore instead. While it adds a layer of indirection (it uses Mach semaphores internally), the overhead is probably negligible.

Tested on macOS 12.5.

r? @thomcc

@rustbot rustbot added the T-libs Relevant to the library team, which will review and decide on the PR/issue. label Oct 7, 2022
@rustbot
Copy link
Collaborator

rustbot commented Oct 7, 2022

Hey! It looks like you've submitted a new PR for the library teams!

If this PR contains changes to any rust-lang/rust public library APIs then please comment with @rustbot label +T-libs-api -T-libs to tag it appropriately. If this PR contains changes to any unstable APIs please edit the PR description to add a link to the relevant API Change Proposal or create one if you haven't already. If you're unsure where your change falls no worries, just leave it as is and the reviewer will take a look and make a decision to forward on if necessary.

Examples of T-libs-api changes:

  • Stabilizing library features
  • Introducing insta-stable changes such as new implementations of existing stable traits on existing stable types
  • Introducing new or changing existing unstable library APIs (excluding permanently unstable features / features without a tracking issue)
  • Changing public documentation in ways that create new stability guarantees
  • Changing observable runtime behavior of library APIs

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Oct 7, 2022
Copy link
Member

@thomcc thomcc left a comment

Choose a reason for hiding this comment

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

I prefer us using dispatch semaphores to mach ones here. Mach semaphores are much heavier weight, and I'm not sure it's as well-integrated into the QOS system as dispatch_semaphore (I think that stuff is done somewhat manually from libdispatch).

The impl looks like a nearly complete match to the futex version (makes sense given that the futex is being used as a semaphore). That makes it pretty easy to review, not that it's unclear anyway.

I'm very happy to see another platform have the SeqCst barrier removed -- not because of performance though, but because we don't guarantee it's SeqCst, so I'd been a bit worried that people would start to rely on park() providing that to avoid races! This impl provides correct/optimal orderings that we guarantee, which is nice to see.

I'd like to avoid breaking miri for now, so won't R+ quite yet (and there are a few other nits). I may also run some benchmarks in the meantime (I know usync has benchmarks and heavily leverages stdlib parking, so I'm curious if it's impacted -- there are probably others too). A concern is that dispatch_semaphores are... quite heavyweight. For one, they're fair, which (at least if you implement a Mutex using a semaphore and counter), often makes their use come with a bit of a throughput loss...

I hope not though, it's a really nice impl with several benefits!

library/std/src/sys/unix/thread_parker/darwin.rs Outdated Show resolved Hide resolved
library/std/src/sys/unix/thread_parker/mod.rs Outdated Show resolved Hide resolved

#[link(name = "System", kind = "dylib")]
extern "C" {
fn dispatch_time(when: dispatch_time_t, delta: i64) -> dispatch_time_t;
Copy link
Member

Choose a reason for hiding this comment

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

Arguably these bindings should be in libc. I guess a reason not to put it there is that libdispatch can be used on other OSes (linux, windows, freebsd, ...), but needs a separate lib -- it's only part of libc libSystem on darwin-based OSes. Anyway, this is tiny, so I'm not that concerned.

// decrementing the count because of a timeout, it means another
// thread is about to call semaphore_signal. We must wait for that
// to happen to ensure the semaphore count is reset.
while dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER) != 0 {}
Copy link
Member Author

Choose a reason for hiding this comment

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

Note that this is technically a priority hole: if a high-priority thread uses park_timeout while a low priority thread tries to unpark it, a medium-priority thread could prevent the unpark from completing, so the high-priority thread would wait indefinitely. I doubt that anyone relies on this, but still... By the way, libdispatch itself is vulnerable to this.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, that's a fundamental issue with stuff like semaphores.

@thomcc
Copy link
Member

thomcc commented Oct 8, 2022

I'm not able to find any changes when benchmarking parker throughput before/after, and this is significantly cleaner (so maybe we'd want it anyway) so we should be good to go.

@bors r+

@bors
Copy link
Contributor

bors commented Oct 8, 2022

📌 Commit c320ab9 has been approved by thomcc

It is now in the queue for this repository.

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Oct 8, 2022
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Oct 11, 2022
Use semaphores for thread parking on Apple platforms

Currently we use a mutex-condvar pair for thread parking on Apple systems. Unfortunately, `pthread_cond_timedwait` uses the real-time clock for measuring time, which causes problems when the system time changes. The parking implementation in this PR uses a semaphore instead, which measures monotonic time by default, avoiding these issues. As a further benefit, this has the potential to improve performance a bit, since `unpark` does not need to wait for a lock to be released.

Since the Mach semaphores are poorly documented (I could not find availability or stability guarantees for instance), this uses a [dispatch semaphore](https://developer.apple.com/documentation/dispatch/dispatch_semaphore?language=objc) instead. While it adds a layer of indirection (it uses Mach semaphores internally), the overhead is probably negligible.

Tested on macOS 12.5.

r? `@thomcc`
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request Oct 11, 2022
Use semaphores for thread parking on Apple platforms

Currently we use a mutex-condvar pair for thread parking on Apple systems. Unfortunately, `pthread_cond_timedwait` uses the real-time clock for measuring time, which causes problems when the system time changes. The parking implementation in this PR uses a semaphore instead, which measures monotonic time by default, avoiding these issues. As a further benefit, this has the potential to improve performance a bit, since `unpark` does not need to wait for a lock to be released.

Since the Mach semaphores are poorly documented (I could not find availability or stability guarantees for instance), this uses a [dispatch semaphore](https://developer.apple.com/documentation/dispatch/dispatch_semaphore?language=objc) instead. While it adds a layer of indirection (it uses Mach semaphores internally), the overhead is probably negligible.

Tested on macOS 12.5.

r? ``@thomcc``
matthiaskrgr added a commit to matthiaskrgr/rust that referenced this pull request Oct 11, 2022
Use semaphores for thread parking on Apple platforms

Currently we use a mutex-condvar pair for thread parking on Apple systems. Unfortunately, `pthread_cond_timedwait` uses the real-time clock for measuring time, which causes problems when the system time changes. The parking implementation in this PR uses a semaphore instead, which measures monotonic time by default, avoiding these issues. As a further benefit, this has the potential to improve performance a bit, since `unpark` does not need to wait for a lock to be released.

Since the Mach semaphores are poorly documented (I could not find availability or stability guarantees for instance), this uses a [dispatch semaphore](https://developer.apple.com/documentation/dispatch/dispatch_semaphore?language=objc) instead. While it adds a layer of indirection (it uses Mach semaphores internally), the overhead is probably negligible.

Tested on macOS 12.5.

r? ```@thomcc```
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request Oct 15, 2022
Use semaphores for thread parking on Apple platforms

Currently we use a mutex-condvar pair for thread parking on Apple systems. Unfortunately, `pthread_cond_timedwait` uses the real-time clock for measuring time, which causes problems when the system time changes. The parking implementation in this PR uses a semaphore instead, which measures monotonic time by default, avoiding these issues. As a further benefit, this has the potential to improve performance a bit, since `unpark` does not need to wait for a lock to be released.

Since the Mach semaphores are poorly documented (I could not find availability or stability guarantees for instance), this uses a [dispatch semaphore](https://developer.apple.com/documentation/dispatch/dispatch_semaphore?language=objc) instead. While it adds a layer of indirection (it uses Mach semaphores internally), the overhead is probably negligible.

Tested on macOS 12.5.

r? ````@thomcc````
Dylan-DPC added a commit to Dylan-DPC/rust that referenced this pull request Oct 15, 2022
Use semaphores for thread parking on Apple platforms

Currently we use a mutex-condvar pair for thread parking on Apple systems. Unfortunately, `pthread_cond_timedwait` uses the real-time clock for measuring time, which causes problems when the system time changes. The parking implementation in this PR uses a semaphore instead, which measures monotonic time by default, avoiding these issues. As a further benefit, this has the potential to improve performance a bit, since `unpark` does not need to wait for a lock to be released.

Since the Mach semaphores are poorly documented (I could not find availability or stability guarantees for instance), this uses a [dispatch semaphore](https://developer.apple.com/documentation/dispatch/dispatch_semaphore?language=objc) instead. While it adds a layer of indirection (it uses Mach semaphores internally), the overhead is probably negligible.

Tested on macOS 12.5.

r? `````@thomcc`````
bors added a commit to rust-lang-ci/rust that referenced this pull request Oct 15, 2022
Rollup of 6 pull requests

Successful merges:

 - rust-lang#102773 (Use semaphores for thread parking on Apple platforms)
 - rust-lang#102884 (resolve: Some cleanup, asserts and tests for lifetime ribs)
 - rust-lang#102954 (Add missing checks for `doc(cfg_hide(...))`)
 - rust-lang#102998 (Drop temporaries created in a condition, even if it's a let chain)
 - rust-lang#103003 (Fix `suggest_floating_point_literal` ICE)
 - rust-lang#103041 (Update cargo)

Failed merges:

r? `@ghost`
`@rustbot` modify labels: rollup
@bors bors merged commit cbe5e7b into rust-lang:master Oct 15, 2022
@rustbot rustbot added this to the 1.66.0 milestone Oct 15, 2022
@joboet joboet deleted the apple_parker branch October 15, 2022 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants