security/sandbox/chromium/base/threading/thread_collision_warner.h

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
     2 // Use of this source code is governed by a BSD-style license that can be
     3 // found in the LICENSE file.
     5 #ifndef BASE_THREADING_THREAD_COLLISION_WARNER_H_
     6 #define BASE_THREADING_THREAD_COLLISION_WARNER_H_
     8 #include <memory>
    10 #include "base/atomicops.h"
    11 #include "base/base_export.h"
    12 #include "base/compiler_specific.h"
    14 // A helper class alongside macros to be used to verify assumptions about thread
    15 // safety of a class.
    16 //
    17 // Example: Queue implementation non thread-safe but still usable if clients
    18 //          are synchronized somehow.
    19 //
    20 //          In this case the macro DFAKE_SCOPED_LOCK has to be
    21 //          used, it checks that if a thread is inside the push/pop then
    22 //          noone else is still inside the pop/push
    23 //
    24 // class NonThreadSafeQueue {
    25 //  public:
    26 //   ...
    27 //   void push(int) { DFAKE_SCOPED_LOCK(push_pop_); ... }
    28 //   int pop() { DFAKE_SCOPED_LOCK(push_pop_); ... }
    29 //   ...
    30 //  private:
    31 //   DFAKE_MUTEX(push_pop_);
    32 // };
    33 //
    34 //
    35 // Example: Queue implementation non thread-safe but still usable if clients
    36 //          are synchronized somehow, it calls a method to "protect" from
    37 //          a "protected" method
    38 //
    39 //          In this case the macro DFAKE_SCOPED_RECURSIVE_LOCK
    40 //          has to be used, it checks that if a thread is inside the push/pop
    41 //          then noone else is still inside the pop/push
    42 //
    43 // class NonThreadSafeQueue {
    44 //  public:
    45 //   void push(int) {
    46 //     DFAKE_SCOPED_LOCK(push_pop_);
    47 //     ...
    48 //   }
    49 //   int pop() {
    50 //     DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_);
    51 //     bar();
    52 //     ...
    53 //   }
    54 //   void bar() { DFAKE_SCOPED_RECURSIVE_LOCK(push_pop_); ... }
    55 //   ...
    56 //  private:
    57 //   DFAKE_MUTEX(push_pop_);
    58 // };
    59 //
    60 //
    61 // Example: Queue implementation not usable even if clients are synchronized,
    62 //          so only one thread in the class life cycle can use the two members
    63 //          push/pop.
    64 //
    65 //          In this case the macro DFAKE_SCOPED_LOCK_THREAD_LOCKED pins the
    66 //          specified
    67 //          critical section the first time a thread enters push or pop, from
    68 //          that time on only that thread is allowed to execute push or pop.
    69 //
    70 // class NonThreadSafeQueue {
    71 //  public:
    72 //   ...
    73 //   void push(int) { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
    74 //   int pop() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(push_pop_); ... }
    75 //   ...
    76 //  private:
    77 //   DFAKE_MUTEX(push_pop_);
    78 // };
    79 //
    80 //
    81 // Example: Class that has to be contructed/destroyed on same thread, it has
    82 //          a "shareable" method (with external synchronization) and a not
    83 //          shareable method (even with external synchronization).
    84 //
    85 //          In this case 3 Critical sections have to be defined
    86 //
    87 // class ExoticClass {
    88 //  public:
    89 //   ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
    90 //   ~ExoticClass() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
    91 //
    92 //   void Shareable() { DFAKE_SCOPED_LOCK(shareable_section_); ... }
    93 //   void NotShareable() { DFAKE_SCOPED_LOCK_THREAD_LOCKED(ctor_dtor_); ... }
    94 //   ...
    95 //  private:
    96 //   DFAKE_MUTEX(ctor_dtor_);
    97 //   DFAKE_MUTEX(shareable_section_);
    98 // };
   101 #if !defined(NDEBUG)
   103 // Defines a class member that acts like a mutex. It is used only as a
   104 // verification tool.
   105 #define DFAKE_MUTEX(obj) \
   106      mutable base::ThreadCollisionWarner obj
   107 // Asserts the call is never called simultaneously in two threads. Used at
   108 // member function scope.
   109 #define DFAKE_SCOPED_LOCK(obj) \
   110      base::ThreadCollisionWarner::ScopedCheck s_check_##obj(&obj)
   111 // Asserts the call is never called simultaneously in two threads. Used at
   112 // member function scope. Same as DFAKE_SCOPED_LOCK but allows recursive locks.
   113 #define DFAKE_SCOPED_RECURSIVE_LOCK(obj) \
   114      base::ThreadCollisionWarner::ScopedRecursiveCheck sr_check_##obj(&obj)
   115 // Asserts the code is always executed in the same thread.
   116 #define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) \
   117      base::ThreadCollisionWarner::Check check_##obj(&obj)
   119 #else
   121 #define DFAKE_MUTEX(obj) typedef void InternalFakeMutexType##obj
   122 #define DFAKE_SCOPED_LOCK(obj) ((void)0)
   123 #define DFAKE_SCOPED_RECURSIVE_LOCK(obj) ((void)0)
   124 #define DFAKE_SCOPED_LOCK_THREAD_LOCKED(obj) ((void)0)
   126 #endif
   128 namespace base {
   130 // The class ThreadCollisionWarner uses an Asserter to notify the collision
   131 // AsserterBase is the interfaces and DCheckAsserter is the default asserter
   132 // used. During the unit tests is used another class that doesn't "DCHECK"
   133 // in case of collision (check thread_collision_warner_unittests.cc)
   134 struct BASE_EXPORT AsserterBase {
   135   virtual ~AsserterBase() {}
   136   virtual void warn() = 0;
   137 };
   139 struct BASE_EXPORT DCheckAsserter : public AsserterBase {
   140   virtual ~DCheckAsserter() {}
   141   virtual void warn() OVERRIDE;
   142 };
   144 class BASE_EXPORT ThreadCollisionWarner {
   145  public:
   146   // The parameter asserter is there only for test purpose
   147   explicit ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
   148       : valid_thread_id_(0),
   149         counter_(0),
   150         asserter_(asserter) {}
   152   ~ThreadCollisionWarner() {
   153     delete asserter_;
   154   }
   156   // This class is meant to be used through the macro
   157   // DFAKE_SCOPED_LOCK_THREAD_LOCKED
   158   // it doesn't leave the critical section, as opposed to ScopedCheck,
   159   // because the critical section being pinned is allowed to be used only
   160   // from one thread
   161   class BASE_EXPORT Check {
   162    public:
   163     explicit Check(ThreadCollisionWarner* warner)
   164         : warner_(warner) {
   165       warner_->EnterSelf();
   166     }
   168     ~Check() {}
   170    private:
   171     ThreadCollisionWarner* warner_;
   173     DISALLOW_COPY_AND_ASSIGN(Check);
   174   };
   176   // This class is meant to be used through the macro
   177   // DFAKE_SCOPED_LOCK
   178   class BASE_EXPORT ScopedCheck {
   179    public:
   180     explicit ScopedCheck(ThreadCollisionWarner* warner)
   181         : warner_(warner) {
   182       warner_->Enter();
   183     }
   185     ~ScopedCheck() {
   186       warner_->Leave();
   187     }
   189    private:
   190     ThreadCollisionWarner* warner_;
   192     DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
   193   };
   195   // This class is meant to be used through the macro
   196   // DFAKE_SCOPED_RECURSIVE_LOCK
   197   class BASE_EXPORT ScopedRecursiveCheck {
   198    public:
   199     explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner)
   200         : warner_(warner) {
   201       warner_->EnterSelf();
   202     }
   204     ~ScopedRecursiveCheck() {
   205       warner_->Leave();
   206     }
   208    private:
   209     ThreadCollisionWarner* warner_;
   211     DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
   212   };
   214  private:
   215   // This method stores the current thread identifier and does a DCHECK
   216   // if a another thread has already done it, it is safe if same thread
   217   // calls this multiple time (recursion allowed).
   218   void EnterSelf();
   220   // Same as EnterSelf but recursion is not allowed.
   221   void Enter();
   223   // Removes the thread_id stored in order to allow other threads to
   224   // call EnterSelf or Enter.
   225   void Leave();
   227   // This stores the thread id that is inside the critical section, if the
   228   // value is 0 then no thread is inside.
   229   volatile subtle::Atomic32 valid_thread_id_;
   231   // Counter to trace how many time a critical section was "pinned"
   232   // (when allowed) in order to unpin it when counter_ reaches 0.
   233   volatile subtle::Atomic32 counter_;
   235   // Here only for class unit tests purpose, during the test I need to not
   236   // DCHECK but notify the collision with something else.
   237   AsserterBase* asserter_;
   239   DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
   240 };
   242 }  // namespace base
   244 #endif  // BASE_THREADING_THREAD_COLLISION_WARNER_H_

mercurial