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_
 |