38 lines
1.1 KiB
C
38 lines
1.1 KiB
C
![]() |
#pragma once
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include "Baselib.h"
|
||
|
#include "C/Baselib_Atomic_TypeSafe.h"
|
||
|
#include "Cpp/ReentrantLock.h"
|
||
|
|
||
|
namespace il2cpp
|
||
|
{
|
||
|
namespace utils
|
||
|
{
|
||
|
// Initializes a pointer from NULL to non-NULL exactly once.
|
||
|
// Uses double checked locking to avoid taking the lock after the pointer has been initialized.
|
||
|
|
||
|
template<typename T, typename InitBlock>
|
||
|
static inline T* InitOnce(T** value, baselib::ReentrantLock* lock, InitBlock init)
|
||
|
{
|
||
|
// Based on double checked locking implementation in https://preshing.com/20130930/double-checked-locking-is-fixed-in-cpp11/
|
||
|
|
||
|
T* tmp = (T*)Baselib_atomic_load_ptr_relaxed((intptr_t*)value);
|
||
|
Baselib_atomic_thread_fence_acquire();
|
||
|
if (tmp == nullptr)
|
||
|
{
|
||
|
os::FastAutoLock autoLock(lock);
|
||
|
tmp = (T*)Baselib_atomic_load_ptr_relaxed((intptr_t*)value);
|
||
|
if (tmp == nullptr)
|
||
|
{
|
||
|
tmp = init(autoLock);
|
||
|
Baselib_atomic_thread_fence_release();
|
||
|
Baselib_atomic_store_ptr_relaxed((intptr_t*)value, (intptr_t)tmp);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return tmp;
|
||
|
}
|
||
|
}
|
||
|
}
|