| /* | 
 |  *  Copyright (c) 2012 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_STATIC_INSTANCE_H_ | 
 | #define WEBRTC_SYSTEM_WRAPPERS_INTERFACE_STATIC_INSTANCE_H_ | 
 |  | 
 | #include <assert.h> | 
 |  | 
 | #include "webrtc/system_wrappers/interface/critical_section_wrapper.h" | 
 | #ifdef _WIN32 | 
 | #include "webrtc/system_wrappers/interface/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 new_value = InterlockedDecrement(&instance_count); | 
 |     if (new_value == 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)) { | 
 |       InterlockedExchangePointer(reinterpret_cast<void * volatile*>(&instance), | 
 |                                  new_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_STATIC_INSTANCE_H_ |