Use C++11 atomics in place of AngelScript's implementation

AngelScript's implementation uses now-deprecated `OSAtomicIncrement32`
and generates compiler warnings.
This commit is contained in:
yvt 2018-12-31 21:56:21 +09:00
parent c7fb662f77
commit 6426247f09
12 changed files with 38 additions and 167 deletions

View File

@ -444,14 +444,14 @@ int CScriptAny::AddRef() const
{
// Increase counter and clear flag set by GC
gcFlag = false;
return asAtomicInc(refCount);
return refCount.fetch_add(1) + 1;
}
int CScriptAny::Release() const
{
// Decrease the ref counter
gcFlag = false;
if( asAtomicDec(refCount) == 0 )
if( refCount.fetch_sub(1) == 1 )
{
// Delete this object as no more references to it exists
delete this;

View File

@ -6,6 +6,7 @@
#include "angelscript.h"
#endif
#include <atomic>
BEGIN_AS_NAMESPACE
@ -48,7 +49,7 @@ protected:
virtual ~CScriptAny();
void FreeObject();
mutable int refCount;
mutable std::atomic<int> refCount;
mutable bool gcFlag;
asIScriptEngine *engine;

View File

@ -1719,14 +1719,14 @@ void CScriptArray::AddRef() const
{
// Clear the GC flag then increase the counter
gcFlag = false;
asAtomicInc(refCount);
refCount.fetch_add(1);
}
void CScriptArray::Release() const
{
// Clearing the GC flag then descrease the counter
gcFlag = false;
if( asAtomicDec(refCount) == 0 )
if( refCount.fetch_sub(1) == 1 )
{
// When reaching 0 no more references to this instance
// exists and the object should be destroyed

View File

@ -6,6 +6,8 @@
#include "angelscript.h"
#endif
#include <atomic>
// Sometimes it may be desired to use the same method names as used by C++ STL.
// This may for example reduce time when converting code from script to C++ or
// back.
@ -100,7 +102,7 @@ public:
void ReleaseAllHandles(asIScriptEngine *engine);
protected:
mutable int refCount;
mutable std::atomic<int> refCount;
mutable bool gcFlag;
asITypeInfo *objType;
SArrayBuffer *buffer;

View File

@ -186,14 +186,14 @@ void CScriptDictionary::AddRef() const
{
// We need to clear the GC flag
gcFlag = false;
asAtomicInc(refCount);
refCount.fetch_add(1);
}
void CScriptDictionary::Release() const
{
// We need to clear the GC flag
gcFlag = false;
if( asAtomicDec(refCount) == 0 )
if( refCount.fetch_sub(1) == 1 )
{
this->~CScriptDictionary();
asFreeMem(const_cast<CScriptDictionary*>(this));

View File

@ -10,6 +10,8 @@
#include "angelscript.h"
#endif
#include <atomic>
// By default the CScriptDictionary use the std::string for the keys.
// If the application uses a custom string type, then this typedef
// can be changed accordingly. Remember, if the application uses
@ -218,7 +220,7 @@ protected:
// Our properties
asIScriptEngine *engine;
mutable int refCount;
mutable std::atomic<int> refCount;
mutable bool gcFlag;
dictMap_t dict;
};

View File

@ -568,8 +568,6 @@ extern "C"
AS_API void asReleaseExclusiveLock();
AS_API void asAcquireSharedLock();
AS_API void asReleaseSharedLock();
AS_API int asAtomicInc(int &value);
AS_API int asAtomicDec(int &value);
AS_API int asThreadCleanup();
// Memory management

View File

@ -38,142 +38,5 @@
BEGIN_AS_NAMESPACE
asCAtomic::asCAtomic()
{
value = 0;
}
asDWORD asCAtomic::get() const
{
// A very high ref count is highly unlikely. It most likely a problem with
// memory that has been overwritten or is being accessed after it was deleted.
asASSERT(value < 1000000);
return value;
}
void asCAtomic::set(asDWORD val)
{
// A very high ref count is highly unlikely. It most likely a problem with
// memory that has been overwritten or is being accessed after it was deleted.
asASSERT(value < 1000000);
value = val;
}
asDWORD asCAtomic::atomicInc()
{
// A very high ref count is highly unlikely. It most likely a problem with
// memory that has been overwritten or is being accessed after it was deleted.
asASSERT(value < 1000000);
return asAtomicInc((int&)value);
}
asDWORD asCAtomic::atomicDec()
{
// A very high ref count is highly unlikely. It most likely a problem with
// memory that has been overwritten or is being accessed after it was deleted.
asASSERT(value < 1000000);
return asAtomicDec((int&)value);
}
//
// The following code implements the atomicInc and atomicDec on different platforms
//
#if defined(AS_NO_THREADS) || defined(AS_NO_ATOMIC)
int asAtomicInc(int &value)
{
return ++value;
}
int asAtomicDec(int &value)
{
return --value;
}
#elif defined(AS_XENON) /// XBox360
END_AS_NAMESPACE
#include <xtl.h>
BEGIN_AS_NAMESPACE
int asAtomicInc(int &value)
{
return InterlockedIncrement((LONG*)&value);
}
int asAtomicDec(int &value)
{
return InterlockedDecrement((LONG*)&value);
}
#elif defined(AS_WIN)
END_AS_NAMESPACE
#define WIN32_MEAN_AND_LEAN
#include <windows.h>
BEGIN_AS_NAMESPACE
int asAtomicInc(int &value)
{
return InterlockedIncrement((LONG*)&value);
}
int asAtomicDec(int &value)
{
asASSERT(value > 0);
return InterlockedDecrement((LONG*)&value);
}
#elif defined(AS_LINUX) || defined(AS_BSD) || defined(AS_ILLUMOS) || defined(AS_ANDROID)
//
// atomic_inc_and_test() and atomic_dec_and_test() from asm/atomic.h is not meant
// to be used outside the Linux kernel. Instead we should use the GNUC provided
// __sync_add_and_fetch() and __sync_sub_and_fetch() functions.
//
// Reference: http://golubenco.org/blog/atomic-operations/
//
// These are only available in GCC 4.1 and above, so for older versions we
// use the critical sections, though it is a lot slower.
//
int asAtomicInc(int &value)
{
return __sync_add_and_fetch(&value, 1);
}
int asAtomicDec(int &value)
{
return __sync_sub_and_fetch(&value, 1);
}
#elif defined(AS_MAC) || defined(AS_IPHONE)
END_AS_NAMESPACE
#include <libkern/OSAtomic.h>
BEGIN_AS_NAMESPACE
int asAtomicInc(int &value)
{
return OSAtomicIncrement32((int32_t*)&value);
}
int asAtomicDec(int &value)
{
return OSAtomicDecrement32((int32_t*)&value);
}
#else
// If we get here, then the configuration in as_config.h
// is wrong for the compiler/platform combination.
int ERROR_PleaseFixTheConfig[-1];
#endif
END_AS_NAMESPACE

View File

@ -42,6 +42,7 @@
#ifndef AS_ATOMIC_H
#define AS_ATOMIC_H
#include <atomic>
#include "as_config.h"
BEGIN_AS_NAMESPACE
@ -49,19 +50,19 @@ BEGIN_AS_NAMESPACE
class asCAtomic
{
public:
asCAtomic();
asCAtomic() {}
asDWORD get() const;
void set(asDWORD val);
asDWORD get() const { return value.load(); }
void set(asDWORD val) { value.store(val); }
// Increase and return new value
asDWORD atomicInc();
asDWORD atomicInc() { return value.fetch_add(1) + 1; }
// Decrease and return new value
asDWORD atomicDec();
asDWORD atomicDec() { return value.fetch_sub(1) - 1; }
protected:
asDWORD value;
std::atomic<asDWORD> value {0};
};
END_AS_NAMESPACE

View File

@ -28,20 +28,20 @@ namespace spades {
RefCountedObject::~RefCountedObject() {}
void RefCountedObject::AddRef() { asAtomicInc(refCount); }
void RefCountedObject::AddRef() { refCount.fetch_add(1); }
void RefCountedObject::Release() {
#if DEBUG_REFCOUNTED_OBJECT_LAST_RELEASE
AutoLocker guard(&releaseInfoMutex);
#endif
int cnt = asAtomicDec(refCount);
if (cnt == 0) {
int cnt = refCount.fetch_sub(1);
if (cnt == 1) {
#if DEBUG_REFCOUNTED_OBJECT_LAST_RELEASE
#else
delete this;
#endif
} else if (cnt < 0)
} else if (cnt < 1)
#if DEBUG_REFCOUNTED_OBJECT_LAST_RELEASE
SPRaise("Attempted to release already destroyed object\n===== LAST RELEASE BACKTRACE "
"=====\n%s\n===== SECOND LAST RELEASE BACKTRACE =====\n%s\n===== LAST RELEASE "

View File

@ -20,6 +20,7 @@
#pragma once
#include <atomic>
#include <type_traits>
#include <typeinfo>
@ -31,7 +32,7 @@
namespace spades {
class RefCountedObject {
int refCount;
std::atomic<int> refCount;
#if DEBUG_REFCOUNTED_OBJECT_LAST_RELEASE
reflection::BacktraceRecord lastRelease;
reflection::BacktraceRecord secondLastRelease;

View File

@ -19,6 +19,7 @@
*/
#include "ScriptManager.h"
#include <atomic>
#include <vector>
#include <Core/Debug.h>
#include <Core/Math.h>
@ -29,7 +30,8 @@ namespace spades {
template <typename T>
class PrimitiveArray {
std::vector<T> inner;
int refCount = 1;
std::atomic<int> refCount {1};
bool gcFlag = false;
public:
static asITypeInfo *scrType;
typedef PrimitiveArray<T> ArrayType;
@ -83,23 +85,24 @@ namespace spades {
}
void AddRef() {
refCount &= 0x7fffffff;
asAtomicInc(refCount);
gcFlag = false;
refCount.fetch_add(1);
}
void Release() {
refCount &= 0x7fffffff;
gcFlag = false;
if(asAtomicDec(refCount) <= 0)
if(refCount.fetch_sub(1) == 1) {
delete this;
}
}
void SetGCFlag() {
refCount |= 0x80000000;
gcFlag = true;
}
bool GetGCFlag() {
return (refCount & 0x80000000) != 0;
return gcFlag;
}
int GetRefCount() {
return refCount & 0x7fffffff;
return refCount;
}
void EnumReferences(asIScriptEngine *eng) {}
void ReleaseAllReferences(asIScriptEngine *eng){}