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

mercurial