OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | |
3 * | |
4 * Use of this source code is governed by a BSD-style license | |
5 * that can be found in the LICENSE file in the root of the source | |
6 * tree. An additional intellectual property rights grant can be found | |
7 * in the file PATENTS. All contributing project authors may | |
8 * be found in the AUTHORS file in the root of the source tree. | |
9 */ | |
10 | |
11 #ifndef WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_ | |
12 #define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_ | |
13 | |
14 #include <assert.h> | |
15 | |
16 #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" | |
17 #ifdef _WIN32 | |
18 #include "webrtc/system_wrappers/interface/fix_interlocked_exchange_pointer_win.
h" | |
19 #endif | |
20 | |
21 namespace webrtc { | |
22 | |
23 enum CountOperation { | |
24 kRelease, | |
25 kAddRef, | |
26 kAddRefNoCreate | |
27 }; | |
28 enum CreateOperation { | |
29 kInstanceExists, | |
30 kCreate, | |
31 kDestroy | |
32 }; | |
33 | |
34 template <class T> | |
35 // Construct On First Use idiom. Avoids | |
36 // "static initialization order fiasco". | |
37 static T* GetStaticInstance(CountOperation count_operation) { | |
38 // TODO (hellner): use atomic wrapper instead. | |
39 static volatile long instance_count = 0; | |
40 static T* volatile instance = NULL; | |
41 CreateOperation state = kInstanceExists; | |
42 #ifndef _WIN32 | |
43 // This memory is staticly allocated once. The application does not try to | |
44 // free this memory. This approach is taken to avoid issues with | |
45 // destruction order for statically allocated memory. The memory will be | |
46 // reclaimed by the OS and memory leak tools will not recognize memory | |
47 // reachable from statics leaked so no noise is added by doing this. | |
48 static CriticalSectionWrapper* crit_sect( | |
49 CriticalSectionWrapper::CreateCriticalSection()); | |
50 CriticalSectionScoped lock(crit_sect); | |
51 | |
52 if (count_operation == | |
53 kAddRefNoCreate && instance_count == 0) { | |
54 return NULL; | |
55 } | |
56 if (count_operation == | |
57 kAddRef || | |
58 count_operation == kAddRefNoCreate) { | |
59 instance_count++; | |
60 if (instance_count == 1) { | |
61 state = kCreate; | |
62 } | |
63 } else { | |
64 instance_count--; | |
65 if (instance_count == 0) { | |
66 state = kDestroy; | |
67 } | |
68 } | |
69 if (state == kCreate) { | |
70 instance = T::CreateInstance(); | |
71 } else if (state == kDestroy) { | |
72 T* old_instance = instance; | |
73 instance = NULL; | |
74 // The state will not change past this point. Release the critical | |
75 // section while deleting the object in case it would be blocking on | |
76 // access back to this object. (This is the case for the tracing class | |
77 // since the thread owned by the tracing class also traces). | |
78 // TODO(hellner): this is a bit out of place but here goes, de-couple | |
79 // thread implementation with trace implementation. | |
80 crit_sect->Leave(); | |
81 if (old_instance) { | |
82 delete old_instance; | |
83 } | |
84 // Re-acquire the lock since the scoped critical section will release | |
85 // it. | |
86 crit_sect->Enter(); | |
87 return NULL; | |
88 } | |
89 #else // _WIN32 | |
90 if (count_operation == | |
91 kAddRefNoCreate && instance_count == 0) { | |
92 return NULL; | |
93 } | |
94 if (count_operation == kAddRefNoCreate) { | |
95 if (1 == InterlockedIncrement(&instance_count)) { | |
96 // The instance has been destroyed by some other thread. Rollback. | |
97 InterlockedDecrement(&instance_count); | |
98 assert(false); | |
99 return NULL; | |
100 } | |
101 // Sanity to catch corrupt state. | |
102 if (instance == NULL) { | |
103 assert(false); | |
104 InterlockedDecrement(&instance_count); | |
105 return NULL; | |
106 } | |
107 } else if (count_operation == kAddRef) { | |
108 if (instance_count == 0) { | |
109 state = kCreate; | |
110 } else { | |
111 if (1 == InterlockedIncrement(&instance_count)) { | |
112 // InterlockedDecrement because reference count should not be | |
113 // updated just yet (that's done when the instance is created). | |
114 InterlockedDecrement(&instance_count); | |
115 state = kCreate; | |
116 } | |
117 } | |
118 } else { | |
119 int new_value = InterlockedDecrement(&instance_count); | |
120 if (new_value == 0) { | |
121 state = kDestroy; | |
122 } | |
123 } | |
124 | |
125 if (state == kCreate) { | |
126 // Create instance and let whichever thread finishes first assign its | |
127 // local copy to the global instance. All other threads reclaim their | |
128 // local copy. | |
129 T* new_instance = T::CreateInstance(); | |
130 if (1 == InterlockedIncrement(&instance_count)) { | |
131 InterlockedExchangePointer(reinterpret_cast<void * volatile*>(&instance), | |
132 new_instance); | |
133 } else { | |
134 InterlockedDecrement(&instance_count); | |
135 if (new_instance) { | |
136 delete static_cast<T*>(new_instance); | |
137 } | |
138 } | |
139 } else if (state == kDestroy) { | |
140 T* old_value = static_cast<T*>(InterlockedExchangePointer( | |
141 reinterpret_cast<void * volatile*>(&instance), NULL)); | |
142 if (old_value) { | |
143 delete static_cast<T*>(old_value); | |
144 } | |
145 return NULL; | |
146 } | |
147 #endif // #ifndef _WIN32 | |
148 return instance; | |
149 } | |
150 | |
151 } // namspace webrtc | |
152 | |
153 #endif // WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_ | |
OLD | NEW |