aboutsummaryrefslogtreecommitdiff
path: root/src/system_wrappers/interface/static_instance.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/system_wrappers/interface/static_instance.h')
-rw-r--r--src/system_wrappers/interface/static_instance.h155
1 files changed, 155 insertions, 0 deletions
diff --git a/src/system_wrappers/interface/static_instance.h b/src/system_wrappers/interface/static_instance.h
new file mode 100644
index 0000000000..8fe91cc3e4
--- /dev/null
+++ b/src/system_wrappers/interface/static_instance.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATICINSTANCETEMPLATE_H_
+#define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATICINSTANCETEMPLATE_H_
+
+#include <assert.h>
+
+#include "critical_section_wrapper.h"
+#ifdef _WIN32
+#include "fix_interlocked_exchange_pointer_win.h"
+#endif
+
+namespace webrtc {
+
+enum CountOperation {
+ kRelease,
+ kAddRef,
+ kAddRefNoCreate
+};
+enum CreateOperation {
+ kInstanceExists,
+ kCreate,
+ kDestroy
+};
+
+template <class T>
+// Construct On First Use idiom. Avoids
+// "static initialization order fiasco".
+static T* GetStaticInstance(CountOperation count_operation) {
+ // TODO (hellner): use atomic wrapper instead.
+ static volatile long instance_count = 0;
+ static T* volatile instance = NULL;
+ CreateOperation state = kInstanceExists;
+#ifndef _WIN32
+ // This memory is staticly allocated once. The application does not try to
+ // free this memory. This approach is taken to avoid issues with
+ // destruction order for statically allocated memory. The memory will be
+ // reclaimed by the OS and memory leak tools will not recognize memory
+ // reachable from statics leaked so no noise is added by doing this.
+ static CriticalSectionWrapper* crit_sect(
+ CriticalSectionWrapper::CreateCriticalSection());
+ CriticalSectionScoped lock(crit_sect);
+
+ if (count_operation ==
+ kAddRefNoCreate && instance_count == 0) {
+ return NULL;
+ }
+ if (count_operation ==
+ kAddRef ||
+ count_operation == kAddRefNoCreate) {
+ instance_count++;
+ if (instance_count == 1) {
+ state = kCreate;
+ }
+ } else {
+ instance_count--;
+ if (instance_count == 0) {
+ state = kDestroy;
+ }
+ }
+ if (state == kCreate) {
+ instance = T::CreateInstance();
+ } else if (state == kDestroy) {
+ T* old_instance = instance;
+ instance = NULL;
+ // The state will not change past this point. Release the critical
+ // section while deleting the object in case it would be blocking on
+ // access back to this object. (This is the case for the tracing class
+ // since the thread owned by the tracing class also traces).
+ // TODO(hellner): this is a bit out of place but here goes, de-couple
+ // thread implementation with trace implementation.
+ crit_sect->Leave();
+ if (old_instance) {
+ delete old_instance;
+ }
+ // Re-acquire the lock since the scoped critical section will release
+ // it.
+ crit_sect->Enter();
+ return NULL;
+ }
+#else // _WIN32
+ if (count_operation ==
+ kAddRefNoCreate && instance_count == 0) {
+ return NULL;
+ }
+ if (count_operation == kAddRefNoCreate) {
+ if (1 == InterlockedIncrement(&instance_count)) {
+ // The instance has been destroyed by some other thread. Rollback.
+ InterlockedDecrement(&instance_count);
+ assert(false);
+ return NULL;
+ }
+ // Sanity to catch corrupt state.
+ if (instance == NULL) {
+ assert(false);
+ InterlockedDecrement(&instance_count);
+ return NULL;
+ }
+ } else if (count_operation == kAddRef) {
+ if (instance_count == 0) {
+ state = kCreate;
+ } else {
+ if (1 == InterlockedIncrement(&instance_count)) {
+ // InterlockedDecrement because reference count should not be
+ // updated just yet (that's done when the instance is created).
+ InterlockedDecrement(&instance_count);
+ state = kCreate;
+ }
+ }
+ } else {
+ int newValue = InterlockedDecrement(&instance_count);
+ if (newValue == 0) {
+ state = kDestroy;
+ }
+ }
+
+ if (state == kCreate) {
+ // Create instance and let whichever thread finishes first assign its
+ // local copy to the global instance. All other threads reclaim their
+ // local copy.
+ T* new_instance = T::CreateInstance();
+ if (1 == InterlockedIncrement(&instance_count)) {
+ T* old_value = static_cast<T*> (InterlockedExchangePointer(
+ reinterpret_cast<void* volatile*>(&instance), new_instance));
+ assert(old_value == NULL);
+ assert(instance);
+ } else {
+ InterlockedDecrement(&instance_count);
+ if (new_instance) {
+ delete static_cast<T*>(new_instance);
+ }
+ }
+ } else if (state == kDestroy) {
+ T* old_value = static_cast<T*> (InterlockedExchangePointer(
+ reinterpret_cast<void* volatile*>(&instance), NULL));
+ if (old_value) {
+ delete static_cast<T*>(old_value);
+ }
+ return NULL;
+ }
+#endif // #ifndef _WIN32
+ return instance;
+}
+
+} // namspace webrtc
+
+#endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATICINSTANCETEMPLATE_H_