InitOnce.h 1.1 KB

12345678910111213141516171819202122232425262728293031323334353637
  1. #pragma once
  2. #include <stdint.h>
  3. #include "Baselib.h"
  4. #include "C/Baselib_Atomic_TypeSafe.h"
  5. #include "Cpp/ReentrantLock.h"
  6. namespace il2cpp
  7. {
  8. namespace utils
  9. {
  10. // Initializes a pointer from NULL to non-NULL exactly once.
  11. // Uses double checked locking to avoid taking the lock after the pointer has been initialized.
  12. template<typename T, typename InitBlock>
  13. static inline T* InitOnce(T** value, baselib::ReentrantLock* lock, InitBlock init)
  14. {
  15. // Based on double checked locking implementation in https://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
  16. T* tmp = (T*)Baselib_atomic_load_ptr_relaxed((intptr_t*)value);
  17. Baselib_atomic_thread_fence_acquire();
  18. if (tmp == nullptr)
  19. {
  20. os::FastAutoLock autoLock(lock);
  21. tmp = (T*)Baselib_atomic_load_ptr_relaxed((intptr_t*)value);
  22. if (tmp == nullptr)
  23. {
  24. tmp = init(autoLock);
  25. Baselib_atomic_thread_fence_release();
  26. Baselib_atomic_store_ptr_relaxed((intptr_t*)value, (intptr_t)tmp);
  27. }
  28. }
  29. return tmp;
  30. }
  31. }
  32. }