Skip to content

impl Debug for Atomic types #27129

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

Merged
merged 1 commit into from
Jul 21, 2015
Merged

impl Debug for Atomic types #27129

merged 1 commit into from
Jul 21, 2015

Conversation

arthurprs
Copy link
Contributor

I'm being constantly bitten by the lack of this implementation.

I'm unsure if there's a reason to avoid these implementations though.

Since we have a "lossy" implementation for both Mutex and RWLock (RWLock {{ locked }}) I don't think there's a big reason for not having a Debug implementation for the atomic types, even if the user can't specify the ordering.

@rust-highfive
Copy link
Contributor

Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @alexcrichton (or someone else) soon.

If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. The way Github handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes.

Please see the contribution instructions for more information.


macro_rules! impl_Debug {
($($t:ident)*) => ($(
impl fmt::Debug for $t {
Copy link
Member

Choose a reason for hiding this comment

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

I believe these would need a stability attribute (#[stable(feature = "atomic_debug", since = "1.3.0")])

Copy link
Contributor

Choose a reason for hiding this comment

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

Trait impls are insta-stable, so it seems kinda useless...?

I feel like I've had this conversation a ton of times and keep forgetting why it might be useful.

Copy link
Member

Choose a reason for hiding this comment

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

Other impls are still marked, though. Even if it's insta-stable having the version information of when an impl appeared can be useful for understanding the version requirements of your code.

Copy link
Contributor

Choose a reason for hiding this comment

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

Does it though? Either you have a compiler that can build it, or you don't. I suppose if you have one that can build it, you can query if you can use an older one...?

Copy link
Member

Choose a reason for hiding this comment

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

So in order to determine the oldest Rust version I support, I should do I binary search on all Rust releases to determine which can build my project?

@emberian
Copy link
Member

Seems fine to me, in terms of the impl existing.

($($t:ident)*) => ($(
impl fmt::Debug for $t {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Atomic {{ {:?} }}", self.load(Ordering::Relaxed))
Copy link
Member

Choose a reason for hiding this comment

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

I believe this should be write!(f, concat!(stringify!($t), "{{ {:?} }}", ...) so as to actually print which type this is.

Copy link
Member

Choose a reason for hiding this comment

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

These implementations should match the relevant RFC. I'm not sure if these should be treated like smart pointers, in which case this would just be self.load(Ordering::Relaxed).fmt(fmt), or a struct, in which case something like this should suffice:

fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
    f.debug_tuple(stringify!($t)).field(&self.load(Ordering::Relaxed)).finish()
}

@arthurprs
Copy link
Contributor Author

Updated the commit. I tried to address all points raised in the comments.

macro_rules! impl_Debug {
($($t:ident)*) => ($(
impl fmt::Debug for $t {
#[stable(feature = "atomic_debug", since = "1.3.0")]
Copy link
Member

Choose a reason for hiding this comment

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

These attributes go on the impl, not the method.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh, of course. Amending it right away

@arielb1
Copy link
Contributor

arielb1 commented Jul 19, 2015

Why Relaxed rather than SeqCst? Seems like SeqCst should always be preferred unless there is a performance reason.

#[stable(feature = "atomic_debug", since = "1.3.0")]
impl<T: fmt::Debug> fmt::Debug for AtomicPtr<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_tuple(stringify!($t)).field(&self.load(Ordering::Relaxed)).finish()
Copy link
Member

Choose a reason for hiding this comment

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

This looks wrong. Especially the stringify!($t) part.

Copy link
Member

Choose a reason for hiding this comment

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

Why?

Copy link
Member

Choose a reason for hiding this comment

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

This is not inside a macro, therefore at least the $t part is invalid.

Copy link
Member

Choose a reason for hiding this comment

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

Oh right, I just realized this is the real impl :)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

duh, I gotta remind myself of these failures when I try to fast amend things

@emberian
Copy link
Member

@arielb1 on hardware with a weak memory model, SeqCst would force synchronization between cores running this code and cores modifying the data, which is unnecessary since this code doesn't have synchronization requirements. It'd still be racy even with SeqCst (since by the time the value is formatted it could have changed)

impl_Debug!{ AtomicUsize AtomicIsize AtomicBool }

#[stable(feature = "atomic_debug", since = "1.3.0")]
impl<T: fmt::Debug> fmt::Debug for AtomicPtr<T> {
Copy link
Member

Choose a reason for hiding this comment

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

I believe this doesn't need the bound on fmt::Debug as that impl isn't used

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good catch. Fixed.

@arthurprs
Copy link
Contributor Author

We still have to figure out the default Ordering for it. I'm with @cmr on this one since even with strong ordering semantics there's no guarantee whatsoever that the underlining value didn't change after the load.

@arielb1
Copy link
Contributor

arielb1 commented Jul 20, 2015

@cmr

Debug isn't supposed to be a performance bottleneck. Using a weak memory model (esp. Relaxed) can only lead to trouble. Even on weak-memory-model processors (at least the ones I know of - ARM), SeqCst does not affect the performance of the other side.

@arthurprs
Copy link
Contributor Author

@arielb1 what kind of trouble?

@arielb1
Copy link
Contributor

arielb1 commented Jul 20, 2015

@arthurprs

Unpredictable results. If you do have some kind of synchronization, Relaxed-stores can still return a random-ish value.

@arthurprs
Copy link
Contributor Author

@arielb1
It's not random, relaxed loads are still atomic, so in the worst possible case it'll return the valid value as seen by that core (possibly a few nanoseconds away from the newest value).

@alexcrichton
Copy link
Member

@arthurprs let's switch it to SeqCst. If thorough research is done at a later date to determine that it's not necessary, it's backwards compatible to switch. All atomic operations in the standard library are as conservative as possible until proven otherwise, so these need to be SeqCst.

@arthurprs
Copy link
Contributor Author

Commit updated to use SeqCst.

@alexcrichton
Copy link
Member

@bors: r+ 225ad17

Thanks!

bors added a commit that referenced this pull request Jul 21, 2015
I'm being constantly bitten by the lack of this implementation.

I'm unsure if there's a reason to avoid these implementations though.

Since we have a "lossy" implementation for both Mutex and RWLock (RWLock {{ locked }}) I don't think there's a big reason for not having a Debug implementation for the atomic types, even if the user can't specify the ordering.
@bors
Copy link
Collaborator

bors commented Jul 21, 2015

⌛ Testing commit 225ad17 with merge 118a5c4...

@bors bors merged commit 225ad17 into rust-lang:master Jul 21, 2015
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.

9 participants