Index: chrome_frame/scoped_initialization_manager.h |
diff --git a/chrome_frame/scoped_initialization_manager.h b/chrome_frame/scoped_initialization_manager.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..3b57e2c1f2cba5f8751654998fda1d0656db5809 |
--- /dev/null |
+++ b/chrome_frame/scoped_initialization_manager.h |
@@ -0,0 +1,105 @@ |
+// Copyright 2013 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 CHROME_FRAME_SCOPED_INITIALIZATION_MANAGER_H_ |
+#define CHROME_FRAME_SCOPED_INITIALIZATION_MANAGER_H_ |
+ |
+#include "base/basictypes.h" |
+#include "base/lazy_instance.h" |
+#include "base/synchronization/lock.h" |
+ |
+namespace chrome_frame { |
+ |
+// A class intended to be instantiated on the stack in a dyanmically loaded |
+// shared object to initialize and shutdown the object's dependencies. |Traits| |
+// must be a type with two public static void(void) functions named Initialize |
+// and Shutdown. Traits::Initialize will be invoked when the first instance of |
+// this class is created and Traits::Shutdown will ordinarily be invoked when |
+// the last one is destroyed. Shutdown will be deferred if any instance's Commit |
+// method is invoked, causing whatever was initialized to outlive all instances |
+// of this class. Decommit can be invoked later to restore the original behavior |
+// (i.e., Shutdown will be invoked once all instances are destroyed). |
robertshield
2013/03/12 03:16:49
Consider mentioning that multiple Commit() calls a
grt (UTC plus 2)
2013/03/12 14:45:51
Done.
|
+template<class Traits> |
+class ScopedInitializationManager { |
+ public: |
+ ScopedInitializationManager() : manager_(manager_instance_.Get()) { |
+ manager_.AddRef(); |
+ } |
+ ~ScopedInitializationManager() { |
+ manager_.Release(); |
+ } |
+ |
+ // Causes crash reporting to outlive this and all other instances. |
+ void Commit() { |
+ manager_.Commit(); |
+ } |
+ |
+ // Causes crash reporting to be stopped once this and all other instances have |
+ // been destroyed. |
+ void Decommit() { |
+ manager_.Decommit(); |
+ } |
+ |
+ private: |
+ // The long-lived manager class. A single instance of this is lazily created |
+ // when the first scoper is created and is never destroyed. Each scoper takes |
+ // a reference on the manager. The initialize function is invoked when the |
+ // first reference is taken. The Shutdown method is invoked when the last |
+ // reference is released if Commit has not been invoked. |
robertshield
2013/03/12 03:16:49
Nit: You could write this without the inner class,
grt (UTC plus 2)
2013/03/12 14:45:51
Hmm. The base::Lock would need to be lazy-initiali
robertshield
2013/03/12 16:06:12
Not overly complicated, just felt a little longer
|
+ class CrashReportingManager { |
+ public: |
+ CrashReportingManager() : ref_count_(0), committed_(false) {} |
+ ~CrashReportingManager() { |
+ // Instances of this class are leaked. |
+ NOTREACHED(); |
+ } |
+ |
+ void AddRef() { |
+ base::AutoLock auto_lock(lock_); |
+ DCHECK_LT(ref_count_, kuint32max); |
+ if (++ref_count_ == 1 && !committed_) |
robertshield
2013/03/12 03:16:49
nit: I mildly prefer to have the increment operati
grt (UTC plus 2)
2013/03/12 14:45:51
I disagree just enough to want to leave it this wa
robertshield
2013/03/12 16:06:12
I suspected you might :-)
|
+ Traits::Initialize(); |
+ } |
+ |
+ void Release() { |
+ base::AutoLock auto_lock(lock_); |
+ DCHECK_GT(ref_count_, 0U); |
+ if (--ref_count_ == 0 && !committed_) |
+ Traits::Shutdown(); |
+ } |
+ |
+ void Commit() { |
+ base::AutoLock auto_lock(lock_); |
+ DCHECK_NE(ref_count_, 0U); |
+ committed_ = true; |
+ } |
+ |
+ void Decommit() { |
+ base::AutoLock auto_lock(lock_); |
+ DCHECK_NE(ref_count_, 0U); |
+ committed_ = false; |
+ } |
+ |
+ base::Lock lock_; |
+ uint32 ref_count_; |
+ bool committed_; |
+ DISALLOW_COPY_AND_ASSIGN(CrashReportingManager); |
+ }; |
+ |
+ static typename base::LazyInstance<CrashReportingManager>::Leaky |
+ manager_instance_; |
+ |
+ CrashReportingManager& manager_; |
+ DISALLOW_COPY_AND_ASSIGN(ScopedInitializationManager); |
+}; |
+ |
+template<class Traits> |
+typename base::LazyInstance< |
+ typename ScopedInitializationManager<Traits>::CrashReportingManager>::Leaky |
+ ScopedInitializationManager<Traits>::manager_instance_ = |
+ LAZY_INSTANCE_INITIALIZER; |
+ |
+} // namespace chrome_frame |
+ |
+#endif // CHROME_FRAME_SCOPED_INITIALIZATION_MANAGER_H_ |