Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1919)

Unified Diff: base/thread_collision_warner.h

Issue 6258: This CL is due the thread I have made on chromium-dev:... (Closed) Base URL: http://src.chromium.org/svn/trunk/src/
Patch Set: '' Created 12 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « base/stack_container.h ('k') | base/thread_collision_warner.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: base/thread_collision_warner.h
===================================================================
--- base/thread_collision_warner.h (revision 0)
+++ base/thread_collision_warner.h (revision 0)
@@ -0,0 +1,239 @@
+// Copyright (c) 2008 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef THREAD_COLLISION_WARNER_H_
+#define THREAD_COLLISION_WARNER_H_
+
+#include "base/atomicops.h"
+#include "base/platform_thread.h"
+
+#include <memory>
+
+// A helper class used to mark/define critical section in a class and then
+// install controls to check that those critical sections are not violated
+
+// Example: Queue implementation non thread-safe but still usable if clients
+// are synchronized somehow.
+//
+// In this case the macro D_SCOPED_BOOK_CRITICAL_SECTION has to be
+// used, it checks that if a thread is inside the push/pop then
+// noone else is still inside the pop/push
+//
+// class NonThreadSafeQueue {
+// public:
+// ...
+// void push(int) { D_SCOPED_BOOK_CRITICAL_SECTION(push_pop_); ... }
+// int pop() { D_SCOPED_BOOK_CRITICAL_SECTION(push_pop_); ... }
+// ...
+// private:
+// D_DEFINE_CRITICAL_SECTION(push_pop_);
+// };
+//
+//
+//
+// Example: Queue implementation non thread-safe but still usable if clients
+// are synchronized somehow, it calls a method to "protect" from
+// a "protected" method
+//
+// In this case the macro D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION
+// has to be used, it checks that if a thread is inside the push/pop
+// then noone else is still inside the pop/push
+//
+// class NonThreadSafeQueue {
+// public:
+// ...
+// void push(int) {
+// D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(push_pop_);
+// ...
+// }
+// int pop() {
+// D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(push_pop_);
+// bar();
+// ...
+// }
+// void bar() { D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(push_pop_); ... }
+// ...
+// private:
+// D_DEFINE_CRITICAL_SECTION(push_pop_);
+// };
+//
+//
+//
+// Example: Queue implementation not usable even if clients are synchronized,
+// so only one thread in the class life cycle can use the two members
+// push/pop
+//
+// In this case the macro D_BOOK_CRITICAL_SECTION pins the specified
+// critical section the first time a thread enters push or pop, from
+// that time on only that thread is allowed to execute push or pop.
+//
+// class NonThreadSafeQueue {
+// public:
+// ...
+// void push(int) { D_BOOK_CRITICAL_SECTION(push_pop_); ... }
+// int pop() { D_BOOK_CRITICAL_SECTION(push_pop_); ... }
+// ...
+// private:
+// D_DEFINE_CRITICAL_SECTION(push_pop_);
+// };
+//
+//
+//
+// Example: Class that has to be contructed/destroyed on same thread, it has
+// a "shareable" method (with external syncronization) and a not
+// shareable method (even with external syncronization).
+//
+// In this case 3 Critical sections have to be defined
+//
+// class ExoticClass {
+// public:
+// ExoticClass() { D_BOOK_CRITICAL_SECTION(ctor_dtor_); ... }
+// ~ExoticClass() { D_BOOK_CRITICAL_SECTION(ctor_dtor_); ... }
+//
+// void Sharable() { D_SCOPED_BOOK_CRITICAL_SECTION(sharable_section_); ... }
+// void NotSharable() { D_BOOK_CRITICAL_SECTION(not_sharable_section_); ... }
+// ...
+// private:
+// D_DEFINE_CRITICAL_SECTION(ctor_dtor_);
+// D_DEFINE_CRITICAL_SECTION(sharable_section_);
+// D_DEFINE_CRITICAL_SECTION(not_sharable_section_);
+// };
+
+
+#ifndef NDEBUG
+
+#define D_DEFINE_CRITICAL_SECTION(obj) \
+ mutable base::ThreadCollisionWarner obj
+#define D_SCOPED_BOOK_CRITICAL_SECTION(obj) \
+ base::ThreadCollisionWarner::ScopedCheck s_check_##obj(&obj)
+#define D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION(obj) \
+ base::ThreadCollisionWarner::ScopedRecursiveCheck sr_check_##obj(&obj)
+#define D_BOOK_CRITICAL_SECTION(obj) \
+ base::ThreadCollisionWarner::Check check_##obj(&obj)
+
+#else
+
+#define D_DEFINE_CRITICAL_SECTION(obj)
+#define D_SCOPED_BOOK_CRITICAL_SECTION(obj)
+#define D_BOOK_CRITICAL_SECTION(obj)
+
+#endif
+
+namespace base {
+
+// The class ThreadCollisionWarner uses an Asserter to notify the collision
+// AsserterBase is the interfaces and DCheckAsserter is the default asserter
+// used. During the unit tests is used another class that doesn't "DCHECK"
+// in case of collision (check thread_collision_warner_unittests.cc)
+struct AsserterBase {
+ virtual ~AsserterBase() {}
+ virtual void warn() = 0;
+};
+
+struct DCheckAsserter : AsserterBase {
+ virtual ~DCheckAsserter() {}
+ virtual void warn();
+};
+
+class ThreadCollisionWarner {
+ public:
+ // The parameter asserter is there only for test purpose
+ ThreadCollisionWarner(AsserterBase* asserter = new DCheckAsserter())
+ : valid_thread_id_(0),
+ counter_(0),
+ asserter_(asserter) {}
+
+ ~ThreadCollisionWarner() {
+ delete asserter_;
+ }
+
+ // This class is meant to be used through the macro D_BOOK_CRITICAL_SECTION
+ // it doesn't leave the critical section, as opposed to ScopedCheck,
+ // because the critical section being pinned is allowed to be used only
+ // from one thread
+ class Check {
+ public:
+ explicit Check(ThreadCollisionWarner* warner)
+ : warner_(warner) {
+ warner_->EnterSelf();
+ }
+
+ ~Check() {}
+
+ private:
+ ThreadCollisionWarner* warner_;
+
+ DISALLOW_COPY_AND_ASSIGN(Check);
+ };
+
+ // This class is meant to be used through the macro
+ // D_SCOPED_BOOK_CRITICAL_SECTION
+ class ScopedCheck {
+ public:
+ explicit ScopedCheck(ThreadCollisionWarner* warner)
+ : warner_(warner) {
+ warner_->Enter();
+ }
+
+ ~ScopedCheck() {
+ warner_->Leave();
+ }
+
+ private:
+ ThreadCollisionWarner* warner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedCheck);
+ };
+
+ // This class is meant to be used through the macro
+ // D_SCOPED_RECURSIVE_BOOK_CRITICAL_SECTION
+ class ScopedRecursiveCheck {
+ public:
+ explicit ScopedRecursiveCheck(ThreadCollisionWarner* warner)
+ : warner_(warner) {
+ warner_->EnterSelf();
+ }
+
+ ~ScopedRecursiveCheck() {
+ warner_->Leave();
+ }
+
+ private:
+ ThreadCollisionWarner* warner_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScopedRecursiveCheck);
+ };
+
+ private:
+ // This method stores the current thread identifier and does a DCHECK
+ // if a another thread has already done it, it'is safe if same thread
+ // calls this multiple time (recursion allowed).
+ void EnterSelf();
+
+ // Same as EnterSelf but recursion is not allowed
+ void Enter();
+
+ // Removes the thread_id stored in order to allow other threads to
+ // call EnterSelf or Enter
+ void Leave();
+
+ // This stores the thread id that is inside the critical section, if the
+ // value is 0 then no thread is inside
+ volatile int valid_thread_id_;
+
+ // Counter to trace how many time a critical section was "pinned"
+ // (when allowed) in order to unpin it when counter_ reaches 0
+ volatile subtle::Atomic32 counter_;
+
+ // Here only for class unit tests purpose, during the test I need to not
+ // DCHECK but notify the collision with something else
+ AsserterBase* asserter_;
+
+ DISALLOW_COPY_AND_ASSIGN(ThreadCollisionWarner);
+};
+
+} // namespace base
+
+#endif // THREAD_COLLISION_WARNER_H_
+
« no previous file with comments | « base/stack_container.h ('k') | base/thread_collision_warner.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698