You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			154 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
			
		
		
	
	
			154 lines
		
	
	
		
			4.8 KiB
		
	
	
	
		
			C++
		
	
| /*
 | |
|  *  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_
 |