LCOV - code coverage report
Current view: directory - ipc/chromium/src/base - thread_collision_warner.h (source / functions) Found Hit Coverage
Test: app.info Lines: 9 4 44.4 %
Date: 2012-06-02 Functions: 8 3 37.5 %

       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.
       4                 : 
       5                 : #ifndef BASE_THREAD_COLLISION_WARNER_H_
       6                 : #define BASE_THREAD_COLLISION_WARNER_H_
       7                 : 
       8                 : #include <memory.h>
       9                 : 
      10                 : #include "base/atomicops.h"
      11                 : 
      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                 : // };
      97                 : 
      98                 : 
      99                 : #if !defined(NDEBUG)
     100                 : 
     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)
     116                 : 
     117                 : #else
     118                 : 
     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)
     123                 : 
     124                 : #endif
     125                 : 
     126                 : namespace base {
     127                 : 
     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               1 : struct AsserterBase {
     133               0 :   virtual ~AsserterBase() {}
     134                 :   virtual void warn() = 0;
     135                 : };
     136                 : 
     137               1 : struct DCheckAsserter : public AsserterBase {
     138               0 :   virtual ~DCheckAsserter() {}
     139                 :   virtual void warn();
     140                 : };
     141                 : 
     142                 : class ThreadCollisionWarner {
     143                 :  public:
     144                 :   // The parameter asserter is there only for test purpose
     145               1 :   ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
     146                 :       : valid_thread_id_(0),
     147                 :         counter_(0),
     148               1 :         asserter_(asserter) {}
     149                 : 
     150               0 :   ~ThreadCollisionWarner() {
     151               0 :     delete asserter_;
     152               0 :   }
     153                 : 
     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                 :     }
     165                 : 
     166                 :     ~Check() {}
     167                 : 
     168                 :    private:
     169                 :     ThreadCollisionWarner* warner_;
     170                 : 
     171                 :     DISALLOW_COPY_AND_ASSIGN(Check);
     172                 :   };
     173                 : 
     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                 :     }
     182                 : 
     183                 :     ~ScopedCheck() {
     184                 :       warner_->Leave();
     185                 :     }
     186                 : 
     187                 :    private:
     188                 :     ThreadCollisionWarner* warner_;
     189                 : 
     190                 :     DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
     191                 :   };
     192                 : 
     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                 :     }
     201                 : 
     202                 :     ~ScopedRecursiveCheck() {
     203                 :       warner_->Leave();
     204                 :     }
     205                 : 
     206                 :    private:
     207                 :     ThreadCollisionWarner* warner_;
     208                 : 
     209                 :     DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
     210                 :   };
     211                 : 
     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();
     217                 : 
     218                 :   // Same as EnterSelf but recursion is not allowed.
     219                 :   void Enter();
     220                 : 
     221                 :   // Removes the thread_id stored in order to allow other threads to
     222                 :   // call EnterSelf or Enter.
     223                 :   void Leave();
     224                 : 
     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_;
     228                 : 
     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_;
     232                 : 
     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_;
     236                 : 
     237                 :   DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
     238                 : };
     239                 : 
     240                 : }  // namespace base
     241                 : 
     242                 : #endif  // BASE_THREAD_COLLISION_WARNER_H_

Generated by: LCOV version 1.7