This is an archive of the discontinued LLVM Phabricator instance.

shared_ptr : atomic ref-counts (TSan)
Needs ReviewPublic

Authored by os12 on Mar 7 2015, 7:59 PM.

Details

Reviewers
mclow.lists
Summary

This is to do with TSan instrumentation, see http://llvm.org/bugs/show_bug.cgi?id=22836

Diff Detail

Event Timeline

os12 updated this revision to Diff 21443.Mar 7 2015, 7:59 PM
os12 retitled this revision from to shared_ptr : atomic ref-counts (TSan).
os12 updated this object.
os12 edited the test plan for this revision. (Show Details)
EricWF added a subscriber: EricWF.Mar 7 2015, 8:06 PM

This patch breaks the ABI.

os12 added a comment.Mar 7 2015, 8:11 PM

OK, two questions:

  1. Are there means to evolve the ABI?
  2. There are always people who build their world from scratch. Is there a way to enable such a change conditionally?

__sync_add_and_fetch is lowered to atomicrmw add with seq_cst ordering, just like std::atomic<>::operator++. Same with __sync_add_and_fetch and std::atomic<>::operator-- and __sync_bool_compare_and_swap and std::atomic<>:: compare_exchange_strong

What is the functional difference here?

os12 added a comment.Mar 7 2015, 9:29 PM

Every load of the counter is now atomic and that is both correct and pleasing to TSan.

Eg, as per the aforementioned bug report:

99	__shared_weak_count*
100	__shared_weak_count::lock() _NOEXCEPT
101	{
102	    long object_owners = __shared_owners_;
103	    while (object_owners != -1)
104	    {
105	        if (__sync_bool_compare_and_swap(&__shared_owners_,
106	                                         object_owners,
107	                                         object_owners+1))
108	            return this;
109	        object_owners = __shared_owners_;
110	    }
111	    return 0;
112	}
In D8147#136216, @os12 wrote:

Every load of the counter is now atomic and that is both correct and pleasing to TSan.

Eg, as per the aforementioned bug report:

99	__shared_weak_count*
100	__shared_weak_count::lock() _NOEXCEPT
101	{
102	    long object_owners = __shared_owners_;
103	    while (object_owners != -1)
104	    {
105	        if (__sync_bool_compare_and_swap(&__shared_owners_,
106	                                         object_owners,
107	                                         object_owners+1))
108	            return this;
109	        object_owners = __shared_owners_;
110	    }
111	    return 0;
112	}

Ah, so it is our crummy attempt at a relaxed load. Would the implementation be correct if we kept everything the same but used __atomic_load to do the loads of _shared_owners_?

os12 added a comment.Mar 8 2015, 9:41 AM

Unfortunately I don't know whether that is going to be picked up by TSan. Could you ask in the bug please? (so that we avoid playing the broken telephone game).

P.S. I have anecdotal evidence that TSan is pacified with the full std::atomic annotations, but that is quite a different thing.

majnemer added a subscriber: Unknown Object (MLST).Mar 10 2015, 1:46 PM

Adding cfe-commits to the review.

  1. Are there means to evolve the ABI?

I started a discussion about this a month or so ago, but it petered out w/o a conclusion.
There are users of libc++ for whom *any* ABI change is unacceptable.
There are also users of libc++ who (as you say), "build the world from scratch" regularly, for whom ABI change is a non-issue.

We need a scheme that satisfies the first group w/o limiting the second.

As for this change, would "fixing" the load on line #102 fix the observed problem?

I was recently corrected. The change for long to std::atomic<long> doesn't break the ABI because they are layout compatible and there is no constructor code.

However

  1. <atomic> only compiles with clang in c++11 mode and with some GCC versions. This restriction is somewhat artificial.
  2. This is a pessimization when the program is single threaded. Not much we can do about that at this point though.

Neither of these things should block the patch but we should be aware.

@mclow.lists This looks like a good reason to lift the restrictions on atomic.

EricWF edited edge metadata.May 21 2015, 7:54 PM

I think a much safer change would be to use the __atomic_foo builtins. It means we wouldn't have to change the type stored in __shared_count and __shared_weak_count and we wouldn't depend on the <atomic> header.

Is there a reason this approach was not taken?

EricWF resigned from this revision.Jul 7 2015, 1:29 PM
EricWF removed a reviewer: EricWF.

Yep, This patch was superseded by D10406 which has been committed. I'm going to go ahead and resign from this revision but it should be closed.