OLD | NEW |
1 /* | 1 /* |
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. | 2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license | 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 | 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 | 6 * tree. An additional intellectual property rights grant can be found |
7 * in the file PATENTS. All contributing project authors may | 7 * in the file PATENTS. All contributing project authors may |
8 * be found in the AUTHORS file in the root of the source tree. | 8 * be found in the AUTHORS file in the root of the source tree. |
9 */ | 9 */ |
10 | 10 |
11 #ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STATIC_INSTANCE_H_ | 11 #ifndef WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STATIC_INSTANCE_H_ |
12 #define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STATIC_INSTANCE_H_ | 12 #define WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STATIC_INSTANCE_H_ |
13 | 13 |
14 #include <assert.h> | 14 #include <assert.h> |
15 | 15 |
16 #include "webrtc/system_wrappers/include/critical_section_wrapper.h" | 16 #include "webrtc/base/criticalsection.h" |
17 #ifdef _WIN32 | 17 #ifdef _WIN32 |
18 #include "webrtc/system_wrappers/include/fix_interlocked_exchange_pointer_win.h" | 18 #include "webrtc/system_wrappers/include/fix_interlocked_exchange_pointer_win.h" |
19 #endif | 19 #endif |
20 | 20 |
21 namespace webrtc { | 21 namespace webrtc { |
22 | 22 |
23 enum CountOperation { | 23 enum CountOperation { |
24 kRelease, | 24 kRelease, |
25 kAddRef, | 25 kAddRef, |
26 kAddRefNoCreate | 26 kAddRefNoCreate |
27 }; | 27 }; |
28 enum CreateOperation { | 28 enum CreateOperation { |
29 kInstanceExists, | 29 kInstanceExists, |
30 kCreate, | 30 kCreate, |
31 kDestroy | 31 kDestroy |
32 }; | 32 }; |
33 | 33 |
34 template <class T> | 34 template <class T> |
35 // Construct On First Use idiom. Avoids | 35 // Construct On First Use idiom. Avoids |
36 // "static initialization order fiasco". | 36 // "static initialization order fiasco". |
37 static T* GetStaticInstance(CountOperation count_operation) { | 37 static T* GetStaticInstance(CountOperation count_operation) { |
38 // TODO (hellner): use atomic wrapper instead. | 38 // TODO (hellner): use atomic wrapper instead. |
39 static volatile long instance_count = 0; | 39 static volatile long instance_count = 0; |
40 static T* volatile instance = NULL; | 40 static T* volatile instance = NULL; |
41 CreateOperation state = kInstanceExists; | 41 CreateOperation state = kInstanceExists; |
42 #ifndef _WIN32 | 42 #ifndef _WIN32 |
43 // This memory is staticly allocated once. The application does not try to | 43 rtc::CriticalSection crit_sect; |
44 // free this memory. This approach is taken to avoid issues with | 44 rtc::CritScope lock(&crit_sect); |
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 | 45 |
52 if (count_operation == | 46 if (count_operation == |
53 kAddRefNoCreate && instance_count == 0) { | 47 kAddRefNoCreate && instance_count == 0) { |
54 return NULL; | 48 return NULL; |
55 } | 49 } |
56 if (count_operation == | 50 if (count_operation == |
57 kAddRef || | 51 kAddRef || |
58 count_operation == kAddRefNoCreate) { | 52 count_operation == kAddRefNoCreate) { |
59 instance_count++; | 53 instance_count++; |
60 if (instance_count == 1) { | 54 if (instance_count == 1) { |
61 state = kCreate; | 55 state = kCreate; |
62 } | 56 } |
63 } else { | 57 } else { |
64 instance_count--; | 58 instance_count--; |
65 if (instance_count == 0) { | 59 if (instance_count == 0) { |
66 state = kDestroy; | 60 state = kDestroy; |
67 } | 61 } |
68 } | 62 } |
69 if (state == kCreate) { | 63 if (state == kCreate) { |
70 instance = T::CreateInstance(); | 64 instance = T::CreateInstance(); |
71 } else if (state == kDestroy) { | 65 } else if (state == kDestroy) { |
72 T* old_instance = instance; | 66 T* old_instance = instance; |
73 instance = NULL; | 67 instance = NULL; |
74 // The state will not change past this point. Release the critical | 68 // The state will not change past this point. Release the critical |
75 // section while deleting the object in case it would be blocking on | 69 // 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 | 70 // access back to this object. (This is the case for the tracing class |
77 // since the thread owned by the tracing class also traces). | 71 // 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 | 72 // TODO(hellner): this is a bit out of place but here goes, de-couple |
79 // thread implementation with trace implementation. | 73 // thread implementation with trace implementation. |
80 crit_sect->Leave(); | 74 crit_sect.Leave(); |
81 if (old_instance) { | 75 if (old_instance) { |
82 delete old_instance; | 76 delete old_instance; |
83 } | 77 } |
84 // Re-acquire the lock since the scoped critical section will release | 78 // Re-acquire the lock since the scoped critical section will release |
85 // it. | 79 // it. |
86 crit_sect->Enter(); | 80 crit_sect.Enter(); |
87 return NULL; | 81 return NULL; |
88 } | 82 } |
89 #else // _WIN32 | 83 #else // _WIN32 |
90 if (count_operation == | 84 if (count_operation == |
91 kAddRefNoCreate && instance_count == 0) { | 85 kAddRefNoCreate && instance_count == 0) { |
92 return NULL; | 86 return NULL; |
93 } | 87 } |
94 if (count_operation == kAddRefNoCreate) { | 88 if (count_operation == kAddRefNoCreate) { |
95 if (1 == InterlockedIncrement(&instance_count)) { | 89 if (1 == InterlockedIncrement(&instance_count)) { |
96 // The instance has been destroyed by some other thread. Rollback. | 90 // The instance has been destroyed by some other thread. Rollback. |
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
144 } | 138 } |
145 return NULL; | 139 return NULL; |
146 } | 140 } |
147 #endif // #ifndef _WIN32 | 141 #endif // #ifndef _WIN32 |
148 return instance; | 142 return instance; |
149 } | 143 } |
150 | 144 |
151 } // namspace webrtc | 145 } // namspace webrtc |
152 | 146 |
153 #endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STATIC_INSTANCE_H_ | 147 #endif // WEBRTC_SYSTEM_WRAPPERS_INCLUDE_STATIC_INSTANCE_H_ |
OLD | NEW |