tl;dr; Thread-safety is provided by sequences (base::SequenceChecker) and doesn't require thread-affinity (base::ThreadChecker). I will make that change in the coming days.Most classes in Chromium merely care about thread-safety, not thread-affinity. Most classes use thread-affine checks today for legacy reasons (until now, things mostly ran on dedicated threads where thread-safety == thread-affinity). But this is changing and having thread-affine checks is slowing the progress of migrating code to run on TaskScheduler sequences.
If your class truly requires thread-affinity (i.e. uses thread-local storage or third-party APIs that are thread-affine), update it to use a base::ThreadChecker (and make sure to add an in-code comment so others know why when running into that check in the future).
--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CACvaWvZ1hkRdmpbj_nKftkdGOjsWAxuUH9mTo%2BjREd5AEcTrNA%40mail.gmail.com.
On Thu, Apr 20, 2017 at 12:55 PM, Gabriel Charette <g...@chromium.org> wrote:tl;dr; Thread-safety is provided by sequences (base::SequenceChecker) and doesn't require thread-affinity (base::ThreadChecker). I will make that change in the coming days.Most classes in Chromium merely care about thread-safety, not thread-affinity. Most classes use thread-affine checks today for legacy reasons (until now, things mostly ran on dedicated threads where thread-safety == thread-affinity). But this is changing and having thread-affine checks is slowing the progress of migrating code to run on TaskScheduler sequences.Can you clarify what, particularly, is slowing things down?From reading this message, it sounds like you're saying the process of ensuring code intended thread-affine versus sequence-affine is slowing things down. The proposed solution is to assume things are all sequence-affine, and that everyone should check code to see if it meant thread-affine. That doesn't sound like a very scalable/safe approach, although it is consistent with moving quickly (even if things break), but perhaps I've misunderstood the message?
If your class truly requires thread-affinity (i.e. uses thread-local storage or third-party APIs that are thread-affine), update it to use a base::ThreadChecker (and make sure to add an in-code comment so others know why when running into that check in the future).One concern here is that it assumes there is someone who is responsible for every line of code/every class, and that within "the coming days" will inspect all such classes to ensure they're properly thread-affine versus sequence-affine. I don't think that assumption holds - that is, there's a non-trivial amount of code that might be best phrased as "in maintenance mode," so do you have a plan to address that?Or is the supposition that if it truly was in maintenance mode, it would have a sufficient number of tests that ensure all of its necessary preconditions, and as a consequence, this change is safe to make? Would these changes perhaps change the precondition testing of those tests, and thus allow them to pass, even though the precondition is now violated?I highlight all of this because historically we've seemed to avoid changing such core invariants of classes, and instead introduced transition classes, migrated callers as appropriate, and then deprecated the existing class (and/or updated to the 'alternative' new class). This was certainly true with things like the introduction of MessageLoop/MessageLoopProxy and then later, the introduction of the TaskRunner. Similarly, base::SequenceChecker and base::ThreadChecker provide difference invariants, with the former being introduced and having converted many (but not all) of the latter's users over.Given that we're talking thread-safety, the issues it causes may be subtle and difficult to attribute to this change, so it seems there is higher-than-normal risk, and less-than-usual assurance of its safety.
I said it's slowing the migration of code to run on TaskScheduler sequences (not that it's affecting product performance) -- i.e. it forces sequence-friendly components to request a SingleThreadTaskRunner instead of a SequencedTaskRunner from the TaskScheduler because a leaf deep down its dependency tree -- inherited from its members -- incorrectly uses a thread-affine check when it merely needs thread-safety.
I mostly sent this PSA to shake out thoughts on this issue, to be honest, I'm not really comfortable with either option but am more annoyed by having to make things single-threaded per bogus checks than I think we really have thread-affine classes around that depend on base::NonThreadSafe (note: it's not the same thing for a class to be thread-affine and for your embedder to decide to run you in a single-threaded environment -- e.g. say //net/foo had a single truly thread-affine class but every other class in //net/foo needs to be mutually exclusive with it: then other classes are all sequence-friendly but happen to be forced to run on the same sequence as that class which is single-threaded (threads are also sequences)). Each class should encode its minimum self requirements, not the environment it expects to inherit from its embedder.
On Thu, Apr 20, 2017 at 2:18 PM, Gabriel Charette <g...@chromium.org> wrote:I said it's slowing the migration of code to run on TaskScheduler sequences (not that it's affecting product performance) -- i.e. it forces sequence-friendly components to request a SingleThreadTaskRunner instead of a SequencedTaskRunner from the TaskScheduler because a leaf deep down its dependency tree -- inherited from its members -- incorrectly uses a thread-affine check when it merely needs thread-safety.Right, apologies, but we were saying the same thing. It sounds from your later message that you confirmed it - that this was an attempt to skip a step for expediency. I wanted to confirm, because I don't think we should skip that step, since it's easy to mask incorrectness by doing so.I mostly sent this PSA to shake out thoughts on this issue, to be honest, I'm not really comfortable with either option but am more annoyed by having to make things single-threaded per bogus checks than I think we really have thread-affine classes around that depend on base::NonThreadSafe (note: it's not the same thing for a class to be thread-affine and for your embedder to decide to run you in a single-threaded environment -- e.g. say //net/foo had a single truly thread-affine class but every other class in //net/foo needs to be mutually exclusive with it: then other classes are all sequence-friendly but happen to be forced to run on the same sequence as that class which is single-threaded (threads are also sequences)). Each class should encode its minimum self requirements, not the environment it expects to inherit from its embedder.While I disagree with your statement there (and perhaps due to a misunderstanding of your message), I do want to highlight that the proposed resolution - moving to base::ThreadChecker - doesn't really change that.
In general, I'm not a fan of base::NonThreadSafe, if only because it's a concrete interface that implements a particular behaviour, rather than being a type annotation or abstract interface. Thus everything implementing base::NonThreadSafe (versus having a base::ThreadChecker or base::SequenceChecker) which also implements another interface is violating our "multiple concrete inheritance is bad" rule. To date, we've all just sort of agreed to look the other way, because it'd be a lot of code churn and the benefits aren't that clear, beyond consistency.I think given the precedent, and the risk, doing the option of introducing the migration class, and working through the cases, does sound like a more desirable outcome. You could further improve this outcome by moving to explicit members rather than multiple concrete inheritance - two birds, one stone - but that's a bonus-add, not a must-have.
--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CAJTZ7LKHHTf6za%2BPKaonufvC%2B7R-562mQEHusZp0zN_c2ksCAw%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CAGD3t5H2Zc3fxHqVVJf%3DJ%2BptQcqQDOiqSKNABQs6_2KA6yc-OA%40mail.gmail.com.
Do most people agree with these statements?:1) A class shouldn't check for thread affinity unless it really needs it (e.g. because it uses thread-local storage or an external API which requires thread affinity). A class that merely needs mutual exclusion between accesses should check for *sequence* affinity.2) base::NonThreadSafe causes violation of the "multiple concrete inheritance is bad" rule.3) base::NonThreadSafe and base::ThreadChecker are two different ways of doing the same thing.4) The compiler has to allocate non-zero space for base::ThreadChecker and base::SequenceChecker members.If people agree with this, what do you think of this migration plan?:1) Introduce THREAD/SEQUENCE_CHECKER and ASSERT_CALLED_ON_VALID_THREAD/SEQUENCE macros that can be used like this:class A {public:void MyMethod() {ASSERT_CALLED_ON_VALID_THREAD(thread_checker_);}private:THREAD_CHECKER(thread_checker_);};These macros are expanded to nothing when !DCHECK_IS_ON().2) Move existing uses of ThreadChecker and SequenceChecker to these macros.3) For every ~230 instance of base::NonThreadSafe (https://cs.chromium.org/search/?q=base::NonThreadSafe&p=2&type=cs), upload a CL that replaces the base::NonThreadSafe inheritance with a SEQUENCE_CHECKER member. In the CL message, ask the reviewer to validate that the use of SEQUENCE_CHECKER instead of THREAD_CHECKER is appropriate (with documentation of differences between the two options). Use an automated script to switch to THREAD_CHECKER when the reviewer asks for it.4) Remove base::NonThreadSafe.Yes, to expedite the migration, I skipped the step of adding a base::SequenceAffine base class. Since I believe we all agree that we don't want to keep it in the long term (cf 2) and 3) at the top of this message), what's the benefit of exposing many reviewers to it during the migration?
On Fri, Apr 21, 2017 at 12:34 PM, François Doray <fdo...@chromium.org> wrote:Do most people agree with these statements?:1) A class shouldn't check for thread affinity unless it really needs it (e.g. because it uses thread-local storage or an external API which requires thread affinity). A class that merely needs mutual exclusion between accesses should check for *sequence* affinity.2) base::NonThreadSafe causes violation of the "multiple concrete inheritance is bad" rule.3) base::NonThreadSafe and base::ThreadChecker are two different ways of doing the same thing.4) The compiler has to allocate non-zero space for base::ThreadChecker and base::SequenceChecker members.If people agree with this, what do you think of this migration plan?:1) Introduce THREAD/SEQUENCE_CHECKER and ASSERT_CALLED_ON_VALID_THREAD/SEQUENCE macros that can be used like this:class A {public:void MyMethod() {ASSERT_CALLED_ON_VALID_THREAD(thread_checker_);}private:THREAD_CHECKER(thread_checker_);};These macros are expanded to nothing when !DCHECK_IS_ON().2) Move existing uses of ThreadChecker and SequenceChecker to these macros.3) For every ~230 instance of base::NonThreadSafe (https://cs.chromium.org/search/?q=base::NonThreadSafe&p=2&type=cs), upload a CL that replaces the base::NonThreadSafe inheritance with a SEQUENCE_CHECKER member. In the CL message, ask the reviewer to validate that the use of SEQUENCE_CHECKER instead of THREAD_CHECKER is appropriate (with documentation of differences between the two options). Use an automated script to switch to THREAD_CHECKER when the reviewer asks for it.4) Remove base::NonThreadSafe.Yes, to expedite the migration, I skipped the step of adding a base::SequenceAffine base class. Since I believe we all agree that we don't want to keep it in the long term (cf 2) and 3) at the top of this message), what's the benefit of exposing many reviewers to it during the migration?I think this is a wonderful proposal. Thanks for working on this.
--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CALekkJfMmwZAbTOdGKXKnUf1MheYrdBJ8%2BGb080vA1-C77ZfnA%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CAEmk%3DMbA8o5GzraY8RpWi3ZceFSJoQBGtsy_iE-809nrpj8Rsw%40mail.gmail.com.
Thanks all for the feedback, I had also considered Francois' proposal but had initially opted against it in an attempt to dodge a bigger refactor than necessary to solve my immediate problem.
After further thoughts and discussions though, Francois and I concluded that the mass rename to base::SequenceAffine is almost as hard as moving directly from base::NonThreadSafe to SEQUENCE_CHECKER macros (both require renaming methods in matching .cc files, the latter merely requires an extra script method to find the matching closing bracket to drop the member at end of class definition instead of renaming in place).
I'll take a stab at this.
Cheers,
Gab
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CAJTZ7LKNAG9HyypzUWvxC%2Bc4o_aKoobApvxRV5DJh54HTyXUnA%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CAJTZ7LKyF4Z9xqN_HEmkHKUOcwUjW%2BJ-%2B7gd9HGGYyi1vxgHSQ%40mail.gmail.com.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CALekkJcrTVpmMOtvEpApSBiwmJfT9hM0kEeveY25wPqRF74S-w%40mail.gmail.com.
Now thread-safe base::WeakPtr's make a lot more sense, eh? :)
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CAJTZ7L%2B%3D-W_g45o371iqVfMSV%3Ddb8YLhU9iv3%2Bd__Sb7veFX3Q%40mail.gmail.com.To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev+unsubscribe@chromium.org.
Best effort cross-thread task cancellation likely is useful to have mind you, however it's implemented.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev...@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CAJTZ7LKeZfPSRAUGQS5Os%3DV34q%2BocUkFx47wgE0R1Tj-xv7MHQ%40mail.gmail.com.
Is that a valid operation? What if the owner deletes the object immediately after the check?
Fwiw, I would be really happy to see SupportsWeakPtr go away. However, I poked at this awhile back and it's tricky to automate because SupportsWeakPtr allows automatic downcasting from WeakPtr<Base> to WeakPtr<T> where T is a subclass that inherits SupportWeakPtr<T> from an ancestor class Base.
Daniel
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev+unsubscribe@chromium.org.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CAJTZ7L%2B%3D-W_g45o371iqVfMSV%3Ddb8YLhU9iv3%2Bd__Sb7veFX3Q%40mail.gmail.com.
--
--
Chromium Developers mailing list: chromi...@chromium.org
View archives, change email options, or unsubscribe:
http://groups.google.com/a/chromium.org/group/chromium-dev
---
You received this message because you are subscribed to the Google Groups "Chromium-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-dev+unsubscribe@chromium.org.
Any chance you got a link to an example off hand here?
It's just the way WeakPtrFactory & SupportsWeakPtr work:- To allow WeakPtr<sub-class> to be dispensed by SupportsWeakPtr<base-class>, WeakPtrs contain a raw pointer to the target (rather than that being stored in the internal Flag).- Because of that, WeakPtrFactory holds both a reference to the Flag, and a raw pointer to the target object.- SupportsWeakPtr knows that the target object is |this|, so only needs to store the Flag reference. It just down-casts |this| to the derived object's type, and populates dispensed WeakPtrs with that.=> SupportsWeakPtr saves sizeof(ptr_t) bytes in each object. :)
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-dev/CALekkJeTVH2cgxtE3Npz7%3D85xR-%3DXcQX0jLzxPHnzbjfq6zBnA%40mail.gmail.com.