Initial commit.
This commit is contained in:
@@ -0,0 +1,175 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "utils/NonCopyable.h"
|
||||
#include "c-api/Atomic-c-api.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class Atomic : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
// All 32bit atomics must be performed on 4-byte aligned addresses. All 64bit atomics must be
|
||||
// performed on 8-byte aligned addresses.
|
||||
|
||||
// Add and Add64 return the *result* of the addition, not the old value! (i.e. they work like
|
||||
// InterlockedAdd and __sync_add_and_fetch).
|
||||
|
||||
static inline void FullMemoryBarrier();
|
||||
|
||||
static inline int32_t Add(volatile int32_t* location1, int32_t value)
|
||||
{
|
||||
return UnityPalAdd(location1, value);
|
||||
}
|
||||
|
||||
static inline uint32_t Add(volatile uint32_t* location1, uint32_t value)
|
||||
{
|
||||
return (uint32_t)Add((volatile int32_t*)location1, (int32_t)value);
|
||||
}
|
||||
|
||||
static inline int64_t Add64(volatile int64_t* location1, int64_t value)
|
||||
{
|
||||
return UnityPalAdd64(location1, value);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T* CompareExchangePointer(T* volatile* dest, T* newValue, T* oldValue)
|
||||
{
|
||||
return static_cast<T*>(UnityPalCompareExchangePointer((void*volatile*)dest, newValue, oldValue));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T* ExchangePointer(T* volatile* dest, T* newValue)
|
||||
{
|
||||
return static_cast<T*>(UnityPalExchangePointer((void*volatile*)dest, newValue));
|
||||
}
|
||||
|
||||
static inline int64_t Read64(volatile int64_t* addr)
|
||||
{
|
||||
return UnityPalRead64(addr);
|
||||
}
|
||||
|
||||
static inline uint64_t Read64(volatile uint64_t* addr)
|
||||
{
|
||||
return (uint64_t)Read64((volatile int64_t*)addr);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
static inline T* ReadPointer(T* volatile* pointer)
|
||||
{
|
||||
#if IL2CPP_SIZEOF_VOID_P == 4
|
||||
return reinterpret_cast<T*>(Add(reinterpret_cast<volatile int32_t*>(pointer), 0));
|
||||
#else
|
||||
return reinterpret_cast<T*>(Add64(reinterpret_cast<volatile int64_t*>(pointer), 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline int32_t Increment(volatile int32_t* value)
|
||||
{
|
||||
return UnityPalIncrement(value);
|
||||
}
|
||||
|
||||
static inline uint32_t Increment(volatile uint32_t* value)
|
||||
{
|
||||
return (uint32_t)Increment((volatile int32_t*)value);
|
||||
}
|
||||
|
||||
static inline int64_t Increment64(volatile int64_t* value)
|
||||
{
|
||||
return UnityPalIncrement64(value);
|
||||
}
|
||||
|
||||
static inline uint64_t Increment64(volatile uint64_t* value)
|
||||
{
|
||||
return (uint64_t)Increment64((volatile int64_t*)value);
|
||||
}
|
||||
|
||||
static inline int32_t Decrement(volatile int32_t* value)
|
||||
{
|
||||
return UnityPalDecrement(value);
|
||||
}
|
||||
|
||||
static inline uint32_t Decrement(volatile uint32_t* value)
|
||||
{
|
||||
return (uint32_t)Decrement((volatile int32_t*)value);
|
||||
}
|
||||
|
||||
static inline int64_t Decrement64(volatile int64_t* value)
|
||||
{
|
||||
return UnityPalDecrement64(value);
|
||||
}
|
||||
|
||||
static inline uint64_t Decrement64(volatile uint64_t* value)
|
||||
{
|
||||
return (uint64_t)Decrement64((volatile int64_t*)value);
|
||||
}
|
||||
|
||||
static inline int32_t CompareExchange(volatile int32_t* dest, int32_t exchange, int32_t comparand)
|
||||
{
|
||||
return UnityPalCompareExchange(dest, exchange, comparand);
|
||||
}
|
||||
|
||||
static inline uint32_t CompareExchange(volatile uint32_t* value, uint32_t newValue, uint32_t oldValue)
|
||||
{
|
||||
return (uint32_t)CompareExchange((volatile int32_t*)value, newValue, oldValue);
|
||||
}
|
||||
|
||||
static inline int64_t CompareExchange64(volatile int64_t* dest, int64_t exchange, int64_t comparand)
|
||||
{
|
||||
return UnityPalCompareExchange64(dest, exchange, comparand);
|
||||
}
|
||||
|
||||
static inline uint64_t CompareExchange64(volatile uint64_t* value, uint64_t newValue, uint64_t oldValue)
|
||||
{
|
||||
return (uint64_t)CompareExchange64((volatile int64_t*)value, newValue, oldValue);
|
||||
}
|
||||
|
||||
static inline int32_t Exchange(volatile int32_t* dest, int32_t exchange)
|
||||
{
|
||||
return UnityPalExchange(dest, exchange);
|
||||
}
|
||||
|
||||
static inline uint32_t Exchange(volatile uint32_t* value, uint32_t newValue)
|
||||
{
|
||||
return (uint32_t)Exchange((volatile int32_t*)value, newValue);
|
||||
}
|
||||
|
||||
static inline int64_t Exchange64(volatile int64_t* dest, int64_t exchange)
|
||||
{
|
||||
return UnityPalExchange64(dest, exchange);
|
||||
}
|
||||
|
||||
static inline uint64_t Exchange64(volatile uint64_t* value, uint64_t newValue)
|
||||
{
|
||||
return (uint64_t)Exchange64((volatile int64_t*)value, newValue);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#if !IL2CPP_SUPPORT_THREADS
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
inline void Atomic::FullMemoryBarrier()
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#elif IL2CPP_TARGET_WINDOWS
|
||||
#include "os/Win32/AtomicImpl.h"
|
||||
#elif IL2CPP_TARGET_PS4
|
||||
#include "os/AtomicImpl.h" // has to come earlier than posix
|
||||
#elif IL2CPP_TARGET_PSP2
|
||||
#include "os/PSP2/AtomicImpl.h"
|
||||
#elif IL2CPP_TARGET_POSIX
|
||||
#include "os/Posix/AtomicImpl.h"
|
||||
#else
|
||||
#include "os/AtomicImpl.h"
|
||||
#endif
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include "il2cpp-config.h"
|
||||
#include "il2cpp-object-internals.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class COM
|
||||
{
|
||||
public:
|
||||
static il2cpp_hresult_t CreateInstance(const Il2CppGuid& clsid, Il2CppIUnknown** object);
|
||||
static il2cpp_hresult_t CreateFreeThreadedMarshaler(Il2CppIUnknown* outer, Il2CppIUnknown** marshal);
|
||||
|
||||
// variant
|
||||
|
||||
static void VariantInit(Il2CppVariant* variant);
|
||||
static il2cpp_hresult_t VariantClear(Il2CppVariant* variant);
|
||||
|
||||
// safe array
|
||||
|
||||
static Il2CppSafeArray* SafeArrayCreate(uint16_t type, uint32_t dimension_count, Il2CppSafeArrayBound* bounds);
|
||||
static il2cpp_hresult_t SafeArrayDestroy(Il2CppSafeArray* safeArray);
|
||||
static il2cpp_hresult_t SafeArrayAccessData(Il2CppSafeArray* safeArray, void** data);
|
||||
static il2cpp_hresult_t SafeArrayUnaccessData(Il2CppSafeArray* safeArray);
|
||||
static il2cpp_hresult_t SafeArrayGetVartype(Il2CppSafeArray* safeArray, uint16_t* type);
|
||||
static uint32_t SafeArrayGetDim(Il2CppSafeArray* safeArray);
|
||||
static il2cpp_hresult_t SafeArrayGetLBound(Il2CppSafeArray* safeArray, uint32_t dimention, int32_t* bound);
|
||||
static il2cpp_hresult_t SafeArrayGetUBound(Il2CppSafeArray* safeArray, uint32_t dimention, int32_t* bound);
|
||||
};
|
||||
} /* namespace os */
|
||||
} /* namespace il2cpp*/
|
||||
#pragma once
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
#if NET_4_0
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class FastMutex;
|
||||
class ConditionVariableImpl;
|
||||
|
||||
class ConditionVariable : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
ConditionVariable();
|
||||
~ConditionVariable();
|
||||
|
||||
int Wait(FastMutex* lock);
|
||||
int TimedWait(FastMutex* lock, uint32_t timeout_ms);
|
||||
void Broadcast();
|
||||
void Signal();
|
||||
|
||||
private:
|
||||
ConditionVariableImpl* m_ConditionVariable;
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
struct FileHandle;
|
||||
struct Il2CppArray;
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
namespace Console
|
||||
{
|
||||
// Isatty is in File class
|
||||
int32_t InternalKeyAvailable(int32_t ms_timeout);
|
||||
bool SetBreak(bool wantBreak);
|
||||
bool SetEcho(bool wantEcho);
|
||||
bool TtySetup(const std::string& keypadXmit, const std::string& teardown, uint8_t* control_characters, int32_t** size);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
#if NET_4_0
|
||||
#include <stdint.h>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class CpuInfo
|
||||
{
|
||||
public:
|
||||
static void* Create();
|
||||
|
||||
/*
|
||||
* This function returns the cpu usage in percentage,
|
||||
* normalized on the number of cores.
|
||||
*
|
||||
* Warning : the percentage returned can be > 100%. This
|
||||
* might happens on systems like Android which, for
|
||||
* battery and performance reasons, shut down cores and
|
||||
* lie about the number of active cores.
|
||||
*/
|
||||
static int32_t Usage(void* previous);
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif // NET_4_0
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class Cryptography
|
||||
{
|
||||
public:
|
||||
/* Returns a handle the cryptography provider to use in other calls on this API. */
|
||||
static void* GetCryptographyProvider();
|
||||
|
||||
/* Open the cryptogrpahy provider. */
|
||||
static bool OpenCryptographyProvider();
|
||||
|
||||
/* Indicate that the cyrptography provider is no longer in use. */
|
||||
static void ReleaseCryptographyProvider(void* provider);
|
||||
|
||||
/* Use the provider to fill the buffer with cryptographically random bytes. */
|
||||
static bool FillBufferWithRandomBytes(void* provider, uint32_t length, unsigned char* data);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "il2cpp-config.h"
|
||||
#include "utils/StringView.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class Debug
|
||||
{
|
||||
public:
|
||||
static bool IsDebuggerPresent();
|
||||
static void WriteString(const utils::StringView<Il2CppNativeChar>& message);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include "il2cpp-string-types.h"
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "utils/StringView.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class Directory
|
||||
{
|
||||
public:
|
||||
static std::string GetCurrent(int* error);
|
||||
static bool SetCurrent(const std::string& path, int* error);
|
||||
static bool Create(const std::string& path, int *error);
|
||||
static bool Remove(const std::string& path, int *error);
|
||||
static std::set<std::string> GetFileSystemEntries(const std::string& path, const std::string& pathWithPattern, int32_t attrs, int32_t mask, int* error);
|
||||
|
||||
struct FindHandle
|
||||
{
|
||||
void* osHandle;
|
||||
Il2CppNativeString directoryPath;
|
||||
Il2CppNativeString pattern;
|
||||
|
||||
FindHandle(const utils::StringView<Il2CppNativeChar>& searchPathWithPattern);
|
||||
~FindHandle();
|
||||
|
||||
inline void SetOSHandle(void* osHandle) { this->osHandle = osHandle; }
|
||||
int32_t CloseOSHandle();
|
||||
};
|
||||
|
||||
static os::ErrorCode FindFirstFile(FindHandle* findHandle, const utils::StringView<Il2CppNativeChar>& searchPathWithPattern, Il2CppNativeString* resultFileName, int32_t* resultAttributes);
|
||||
static os::ErrorCode FindNextFile(FindHandle* findHandle, Il2CppNativeString* resultFileName, int32_t* resultAttributes);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
namespace Encoding
|
||||
{
|
||||
std::string GetCharSet();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
#include "il2cpp-config.h"
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
|
||||
struct Il2CppArray;
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class Environment
|
||||
{
|
||||
public:
|
||||
static std::string GetMachineName();
|
||||
static int32_t GetProcessorCount();
|
||||
static std::string GetOsVersionString();
|
||||
static std::string GetOsUserName();
|
||||
static std::string GetEnvironmentVariable(const std::string& name);
|
||||
static void SetEnvironmentVariable(const std::string& name, const std::string& value);
|
||||
static std::vector<std::string> GetEnvironmentVariableNames();
|
||||
static std::string GetHomeDirectory();
|
||||
static std::vector<std::string> GetLogicalDrives();
|
||||
static void Exit(int result);
|
||||
static NORETURN void Abort();
|
||||
static std::string GetWindowsFolderPath(int32_t folder);
|
||||
|
||||
#if NET_4_0
|
||||
static bool Is64BitOs();
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class Error
|
||||
{
|
||||
public:
|
||||
static ErrorCode GetLastError();
|
||||
static void SetLastError(ErrorCode code);
|
||||
};
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/Handle.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class EventImpl;
|
||||
|
||||
class Event : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
Event(bool manualReset = false, bool signaled = false);
|
||||
~Event();
|
||||
|
||||
ErrorCode Set();
|
||||
ErrorCode Reset();
|
||||
WaitStatus Wait(bool interruptible = false);
|
||||
WaitStatus Wait(uint32_t ms, bool interruptible = false);
|
||||
|
||||
private:
|
||||
EventImpl* m_Event;
|
||||
};
|
||||
|
||||
class EventHandle : public Handle
|
||||
{
|
||||
public:
|
||||
EventHandle(Event* event)
|
||||
: m_Event(event) {}
|
||||
|
||||
virtual ~EventHandle() { delete m_Event; }
|
||||
virtual bool Wait() { m_Event->Wait(true); return true; }
|
||||
virtual bool Wait(uint32_t ms) { return m_Event->Wait(ms, true) != kWaitStatusTimeout; }
|
||||
virtual WaitStatus Wait(bool interruptible) { return m_Event->Wait(interruptible); }
|
||||
virtual WaitStatus Wait(uint32_t ms, bool interruptible) { return m_Event->Wait(ms, interruptible); }
|
||||
virtual void Signal() { m_Event->Set(); }
|
||||
Event& Get() { return *m_Event; }
|
||||
|
||||
private:
|
||||
Event* m_Event;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
#include "il2cpp-config.h"
|
||||
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/c-api/OSGlobalEnums.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
// File enums and structs
|
||||
struct FileHandle;
|
||||
|
||||
struct FileStat
|
||||
{
|
||||
std::string name;
|
||||
int32_t attributes;
|
||||
int64_t length;
|
||||
int64_t creation_time;
|
||||
int64_t last_access_time;
|
||||
int64_t last_write_time;
|
||||
};
|
||||
|
||||
class LIBIL2CPP_CODEGEN_API File
|
||||
{
|
||||
public:
|
||||
|
||||
|
||||
static bool Isatty(FileHandle* fileHandle);
|
||||
static FileHandle* GetStdInput();
|
||||
static FileHandle* GetStdOutput();
|
||||
static FileHandle* GetStdError();
|
||||
static bool CreatePipe(FileHandle** read_handle, FileHandle** write_handle);
|
||||
static bool CreatePipe(FileHandle** read_handle, FileHandle** write_handle, int* error);
|
||||
static FileType GetFileType(FileHandle* handle);
|
||||
static UnityPalFileAttributes GetFileAttributes(const std::string& path, int* error);
|
||||
static bool SetFileAttributes(const std::string& path, UnityPalFileAttributes attributes, int* error);
|
||||
static bool GetFileStat(const std::string& path, FileStat * stat, int* error);
|
||||
static bool CopyFile(const std::string& src, const std::string& dest, bool overwrite, int* error);
|
||||
static bool MoveFile(const std::string& src, const std::string& dest, int* error);
|
||||
static bool DeleteFile(const std::string& path, int *error);
|
||||
static bool ReplaceFile(const std::string& sourceFileName, const std::string& destinationFileName, const std::string& destinationBackupFileName, bool ignoreMetadataErrors, int* error);
|
||||
static FileHandle* Open(const std::string& path, int openMode, int accessMode, int shareMode, int options, int *error);
|
||||
static bool Close(FileHandle* handle, int *error);
|
||||
static bool SetFileTime(FileHandle* handle, int64_t creation_time, int64_t last_access_time, int64_t last_write_time, int* error);
|
||||
static int64_t GetLength(FileHandle* handle, int *error);
|
||||
static bool SetLength(FileHandle* handle, int64_t length, int *error);
|
||||
static int64_t Seek(FileHandle* handle, int64_t offset, int origin, int *error);
|
||||
static int Read(FileHandle* handle, char *dest, int count, int *error);
|
||||
static int32_t Write(FileHandle* handle, const char* buffer, int count, int *error);
|
||||
static bool Flush(FileHandle* handle, int* error);
|
||||
static void Lock(FileHandle* handle, int64_t position, int64_t length, int* error);
|
||||
static void Unlock(FileHandle* handle, int64_t position, int64_t length, int* error);
|
||||
static bool IsExecutable(const std::string& path);
|
||||
static bool Truncate(FileHandle* handle, int *error);
|
||||
|
||||
static bool DuplicateHandle(FileHandle* source_process_handle, FileHandle* source_handle, FileHandle* target_process_handle,
|
||||
FileHandle** target_handle, int access, int inherit, int options, int* error);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
namespace FileSystemWatcher
|
||||
{
|
||||
int IsSupported();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_USE_GENERIC_SOCKET_IMPL
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "os/Socket.h"
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class SocketImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
typedef int32_t SocketDescriptor;
|
||||
|
||||
SocketImpl(ThreadStatusCallback thread_status_callback);
|
||||
~SocketImpl();
|
||||
|
||||
inline SocketDescriptor GetDescriptor()
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
ErrorCode GetLastError() const;
|
||||
|
||||
WaitStatus Create(SocketDescriptor fd, int32_t family, int32_t type, int32_t protocol);
|
||||
WaitStatus Create(AddressFamily family, SocketType type, ProtocolType protocol);
|
||||
WaitStatus Close();
|
||||
|
||||
bool IsClosed()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
WaitStatus SetBlocking(bool blocking);
|
||||
|
||||
WaitStatus Listen(int32_t blacklog);
|
||||
|
||||
WaitStatus Bind(const char *path);
|
||||
WaitStatus Bind(const char *address, uint16_t port);
|
||||
WaitStatus Bind(uint32_t address, uint16_t port);
|
||||
WaitStatus Bind(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port);
|
||||
|
||||
WaitStatus Connect(const char *path);
|
||||
WaitStatus Connect(uint32_t address, uint16_t port);
|
||||
WaitStatus Connect(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port);
|
||||
|
||||
WaitStatus Disconnect(bool reuse);
|
||||
WaitStatus Shutdown(int32_t how);
|
||||
|
||||
WaitStatus GetLocalEndPointInfo(EndPointInfo &info);
|
||||
WaitStatus GetRemoteEndPointInfo(EndPointInfo &info);
|
||||
|
||||
WaitStatus Receive(const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
|
||||
WaitStatus Send(const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
|
||||
WaitStatus SendArray(WSABuf *wsabufs, int32_t count, int32_t *sent, SocketFlags c_flags);
|
||||
WaitStatus ReceiveArray(WSABuf *wsabufs, int32_t count, int32_t *len, SocketFlags c_flags);
|
||||
|
||||
WaitStatus SendTo(uint32_t address, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
WaitStatus SendTo(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
WaitStatus SendTo(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
|
||||
WaitStatus RecvFrom(uint32_t address, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
|
||||
WaitStatus RecvFrom(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
|
||||
WaitStatus RecvFrom(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
|
||||
|
||||
WaitStatus Accept(os::Socket **socket);
|
||||
|
||||
WaitStatus Available(int32_t *amount);
|
||||
|
||||
WaitStatus Ioctl(int32_t command, const uint8_t *in_data, int32_t in_len, uint8_t *out_data, int32_t out_len, int32_t *written);
|
||||
|
||||
WaitStatus GetSocketOption(SocketOptionLevel level, SocketOptionName name, uint8_t *buffer, int32_t *length);
|
||||
WaitStatus GetSocketOptionFull(SocketOptionLevel level, SocketOptionName name, int32_t *first, int32_t *second);
|
||||
|
||||
WaitStatus SetSocketOption(SocketOptionLevel level, SocketOptionName name, int32_t value);
|
||||
WaitStatus SetSocketOptionLinger(SocketOptionLevel level, SocketOptionName name, bool enabled, int32_t seconds);
|
||||
WaitStatus SetSocketOptionArray(SocketOptionLevel level, SocketOptionName name, const uint8_t *buffer, int32_t length);
|
||||
WaitStatus SetSocketOptionMembership(SocketOptionLevel level, SocketOptionName name, uint32_t group_address, uint32_t local_address);
|
||||
#if IL2CPP_SUPPORT_IPV6
|
||||
WaitStatus SetSocketOptionMembership(SocketOptionLevel level, SocketOptionName name, IPv6Address ipv6, uint64_t interfaceOffset);
|
||||
#endif
|
||||
|
||||
WaitStatus SendFile(const char *filename, TransmitFileBuffers *buffers, TransmitFileOptions options);
|
||||
|
||||
static WaitStatus Poll(std::vector<PollRequest> &requests, int32_t count, int32_t timeout, int32_t *result, int32_t *error);
|
||||
static WaitStatus Poll(std::vector<PollRequest> &requests, int32_t timeout, int32_t *result, int32_t *error);
|
||||
static WaitStatus Poll(PollRequest& request, int32_t timeout, int32_t *result, int32_t *error);
|
||||
|
||||
static WaitStatus GetHostName(std::string &name);
|
||||
static WaitStatus GetHostByName(const std::string &host, std::string &name, std::vector<std::string> &aliases, std::vector<std::string> &addresses);
|
||||
static WaitStatus GetHostByName(const std::string &host, std::string &name, int32_t &family, std::vector<std::string> &aliases, std::vector<void*> &addr_list, int32_t &addr_size);
|
||||
static WaitStatus GetHostByAddr(const std::string &address, std::string &name, std::vector<std::string> &aliases, std::vector<std::string> &addr_list);
|
||||
|
||||
static void Startup();
|
||||
static void Cleanup();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <vector>
|
||||
#include "utils/NonCopyable.h"
|
||||
#include "os/WaitStatus.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class Handle : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
virtual ~Handle() {}
|
||||
virtual bool Wait() = 0;
|
||||
virtual bool Wait(uint32_t ms) = 0;
|
||||
virtual WaitStatus Wait(bool interruptible) = 0;
|
||||
virtual WaitStatus Wait(uint32_t ms, bool interruptible) = 0;
|
||||
virtual void Signal() = 0;
|
||||
|
||||
static int32_t WaitAny(const std::vector<Handle*>& handles, int32_t ms);
|
||||
static bool WaitAll(std::vector<Handle*>& handles, int32_t ms);
|
||||
private:
|
||||
static const int m_waitIntervalMs = 10;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
namespace Image
|
||||
{
|
||||
void Initialize();
|
||||
void* GetImageBase();
|
||||
#if IL2CPP_PLATFORM_SUPPORTS_CUSTOM_SECTIONS
|
||||
bool IsInManagedSection(void*ip);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
void Initialize();
|
||||
void Uninitialize();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class LastError
|
||||
{
|
||||
public:
|
||||
static uint32_t GetLastError();
|
||||
};
|
||||
} /* namespace os */
|
||||
} /* namespace il2cpp*/
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include "il2cpp-config.h"
|
||||
#include "utils/StringView.h"
|
||||
#include <string>
|
||||
|
||||
struct PInvokeArguments;
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class LibraryLoader
|
||||
{
|
||||
public:
|
||||
static Il2CppMethodPointer GetHardcodedPInvokeDependencyFunctionPointer(const il2cpp::utils::StringView<Il2CppNativeChar>& nativeDynamicLibrary, const il2cpp::utils::StringView<char>& entryPoint);
|
||||
static void* LoadDynamicLibrary(const utils::StringView<Il2CppNativeChar>& nativeDynamicLibrary);
|
||||
static void* LoadDynamicLibrary(const utils::StringView<Il2CppNativeChar>& nativeDynamicLibrary, int flags);
|
||||
static Il2CppMethodPointer GetFunctionPointer(void* dynamicLibrary, const PInvokeArguments& pinvokeArgs);
|
||||
static Il2CppMethodPointer GetFunctionPointer(void* dynamicLibrary, const char* functionName);
|
||||
static void CleanupLoadedLibraries();
|
||||
static bool CloseLoadedLibrary(void*& dynamicLibrary);
|
||||
};
|
||||
} /* namespace os */
|
||||
} /* namespace il2cpp*/
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class Locale
|
||||
{
|
||||
public:
|
||||
static void Initialize();
|
||||
static void UnInitialize();
|
||||
|
||||
static std::string GetLocale();
|
||||
#if IL2CPP_SUPPORT_LOCALE_INDEPENDENT_PARSING
|
||||
static double DoubleParseLocaleIndependentImpl(char *ptr, char** endptr);
|
||||
#endif
|
||||
};
|
||||
} /* namespace os */
|
||||
} /* namespace il2cpp */
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class MarshalAlloc
|
||||
{
|
||||
public:
|
||||
static void* Allocate(size_t size);
|
||||
static void* ReAlloc(void* ptr, size_t size);
|
||||
static void Free(void* ptr);
|
||||
};
|
||||
} /* namespace os */
|
||||
} /* namespace il2cpp*/
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class MarshalStringAlloc
|
||||
{
|
||||
public:
|
||||
static il2cpp_hresult_t AllocateBStringLength(const Il2CppChar* text, int32_t length, Il2CppChar** bstr);
|
||||
static il2cpp_hresult_t GetBStringLength(const Il2CppChar* bstr, int32_t* length);
|
||||
static il2cpp_hresult_t FreeBString(Il2CppChar* bstr);
|
||||
};
|
||||
} /* namespace os */
|
||||
} /* namespace il2cpp*/
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
namespace Memory
|
||||
{
|
||||
void* AlignedAlloc(size_t size, size_t alignment);
|
||||
void* AlignedReAlloc(void* memory, size_t newSize, size_t alignment);
|
||||
void AlignedFree(void* memory);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "File.h"
|
||||
#include <map>
|
||||
#include "os/Mutex.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
// This enum must match the same enum in the Mono code, as it is used on the icall boundary.
|
||||
enum MemoryMappedFileAccess
|
||||
{
|
||||
MMAP_FILE_ACCESS_READ_WRITE = 0,
|
||||
MMAP_FILE_ACCESS_READ = 1,
|
||||
MMAP_FILE_ACCESS_WRITE = 2,
|
||||
MMAP_FILE_ACCESS_COPY_ON_WRITE = 3,
|
||||
MMAP_FILE_ACCESS_READ_EXECUTE = 4,
|
||||
MMAP_FILE_ACCESS_READ_WRITE_EXECUTE = 5,
|
||||
};
|
||||
|
||||
// This enum must match the same enum in the Mono code, as it is used on the icall boundary.
|
||||
enum MemoryMappedFileError
|
||||
{
|
||||
NO_MEMORY_MAPPED_FILE_ERROR = 0,
|
||||
BAD_CAPACITY_FOR_FILE_BACKED,
|
||||
CAPACITY_SMALLER_THAN_FILE_SIZE,
|
||||
FILE_NOT_FOUND,
|
||||
FILE_ALREADY_EXISTS,
|
||||
PATH_TOO_LONG,
|
||||
COULD_NOT_OPEN,
|
||||
CAPACITY_MUST_BE_POSITIVE,
|
||||
INVALID_FILE_MODE,
|
||||
COULD_NOT_MAP_MEMORY,
|
||||
ACCESS_DENIED,
|
||||
CAPACITY_LARGER_THAN_LOGICAL_ADDRESS_SPACE
|
||||
};
|
||||
|
||||
// This enum must match the same enum in the Mono code, as it is used on the icall boundary.
|
||||
enum MemoryMappedFileMode
|
||||
{
|
||||
FILE_MODE_CREATE_NEW = 1,
|
||||
FILE_MODE_CREATE = 2,
|
||||
FILE_MODE_OPEN = 3,
|
||||
FILE_MODE_OPEN_OR_CREATE = 4,
|
||||
FILE_MODE_TRUNCATE = 5,
|
||||
FILE_MODE_APPEND = 6,
|
||||
};
|
||||
|
||||
class MemoryMappedFile
|
||||
{
|
||||
public:
|
||||
typedef void* MemoryMappedFileHandle;
|
||||
|
||||
static FileHandle* Create(FileHandle* file, const char* mapName, int32_t mode, int64_t *capacity, MemoryMappedFileAccess access, int32_t options, MemoryMappedFileError* error);
|
||||
static MemoryMappedFileHandle View(FileHandle* mappedFileHandle, int64_t* length, int64_t offset, MemoryMappedFileAccess access, int64_t* actualOffset, MemoryMappedFileError* error);
|
||||
static void Flush(MemoryMappedFileHandle memoryMappedFileData, int64_t length);
|
||||
static bool UnmapView(MemoryMappedFileHandle memoryMappedFileData, int64_t length);
|
||||
static bool Close(FileHandle* file);
|
||||
static void ConfigureHandleInheritability(FileHandle* file, bool inheritability);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#include "il2cpp-config.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
struct ErrorDesc
|
||||
{
|
||||
ErrorCode code;
|
||||
const char *message;
|
||||
};
|
||||
|
||||
extern ErrorDesc common_messages[];
|
||||
|
||||
#ifndef IL2CPP_DISABLE_FULL_MESSAGES
|
||||
extern ErrorDesc messages[];
|
||||
#endif
|
||||
|
||||
class Messages
|
||||
{
|
||||
public:
|
||||
static std::string FromCode(ErrorCode code);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
#pragma once
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/Handle.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class MutexImpl;
|
||||
class FastMutexImpl;
|
||||
|
||||
class Mutex : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
Mutex(bool initiallyOwned = false);
|
||||
~Mutex();
|
||||
|
||||
void Lock(bool interruptible = false);
|
||||
bool TryLock(uint32_t milliseconds = 0, bool interruptible = false);
|
||||
void Unlock();
|
||||
|
||||
private:
|
||||
MutexImpl* m_Mutex;
|
||||
};
|
||||
|
||||
struct AutoLock : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
AutoLock(Mutex* mutex) : m_Mutex(mutex) { m_Mutex->Lock(); }
|
||||
~AutoLock() { m_Mutex->Unlock(); }
|
||||
private:
|
||||
Mutex* m_Mutex;
|
||||
};
|
||||
|
||||
class MutexHandle : public Handle
|
||||
{
|
||||
public:
|
||||
MutexHandle(Mutex* mutex) : m_Mutex(mutex) {}
|
||||
virtual ~MutexHandle() { delete m_Mutex; }
|
||||
virtual bool Wait() { m_Mutex->Lock(true); return true; }
|
||||
virtual bool Wait(uint32_t ms) { return m_Mutex->TryLock(ms, true); }
|
||||
virtual WaitStatus Wait(bool interruptible) { m_Mutex->Lock(interruptible); return kWaitStatusSuccess; }
|
||||
virtual WaitStatus Wait(uint32_t ms, bool interruptible) { return m_Mutex->TryLock(ms, interruptible) ? kWaitStatusSuccess : kWaitStatusFailure; }
|
||||
virtual void Signal() { m_Mutex->Unlock(); }
|
||||
Mutex* Get() { return m_Mutex; }
|
||||
|
||||
private:
|
||||
Mutex* m_Mutex;
|
||||
};
|
||||
|
||||
|
||||
/// Lightweight mutex that has no support for interruption or timed waits. Meant for
|
||||
/// internal use only.
|
||||
class FastMutex
|
||||
{
|
||||
public:
|
||||
FastMutex();
|
||||
~FastMutex();
|
||||
|
||||
void Lock();
|
||||
void Unlock();
|
||||
|
||||
FastMutexImpl* GetImpl();
|
||||
|
||||
private:
|
||||
FastMutexImpl* m_Impl;
|
||||
};
|
||||
|
||||
struct FastAutoLock : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
FastAutoLock(FastMutex* mutex)
|
||||
: m_Mutex(mutex)
|
||||
{
|
||||
m_Mutex->Lock();
|
||||
}
|
||||
|
||||
~FastAutoLock()
|
||||
{
|
||||
m_Mutex->Unlock();
|
||||
}
|
||||
|
||||
private:
|
||||
FastMutex* m_Mutex;
|
||||
};
|
||||
|
||||
|
||||
struct FastAutoUnlock : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
FastAutoUnlock(FastMutex* mutex)
|
||||
: m_Mutex(mutex)
|
||||
{
|
||||
m_Mutex->Unlock();
|
||||
}
|
||||
|
||||
~FastAutoUnlock()
|
||||
{
|
||||
m_Mutex->Lock();
|
||||
}
|
||||
|
||||
private:
|
||||
FastMutex* m_Mutex;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "os/Process.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class NativeMethods
|
||||
{
|
||||
public:
|
||||
static bool CloseProcess(ProcessHandle* handle);
|
||||
static bool GetExitCodeProcess(ProcessHandle* handle, int32_t* exitCode);
|
||||
static int32_t GetCurrentProcessId();
|
||||
static ProcessHandle* GetCurrentProcess();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class Path
|
||||
{
|
||||
public:
|
||||
static std::string GetExecutablePath();
|
||||
static std::string GetTempPath();
|
||||
static bool IsAbsolute(const std::string& path);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
// Assumes clang or gcc as compiler.
|
||||
#if IL2CPP_TARGET_POSIX
|
||||
|
||||
#include "os/c-api/Atomic-c-api.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
inline void Atomic::FullMemoryBarrier()
|
||||
{
|
||||
__sync_synchronize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#if NET_4_0
|
||||
#if IL2CPP_THREADS_PTHREAD
|
||||
|
||||
#include <pthread.h>
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
class FastMutexImpl;
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ConditionVariableImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
ConditionVariableImpl();
|
||||
~ConditionVariableImpl();
|
||||
|
||||
int Wait(FastMutexImpl* lock);
|
||||
int TimedWait(FastMutexImpl* lock, uint32_t timeout_ms);
|
||||
void Broadcast();
|
||||
void Signal();
|
||||
|
||||
private:
|
||||
pthread_cond_t m_ConditionVariable;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include "os/ErrorCodes.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
ErrorCode SocketErrnoToErrorCode(int32_t code);
|
||||
ErrorCode FileErrnoToErrorCode(int32_t code);
|
||||
ErrorCode PathErrnoToErrorCode(const std::string& path, int32_t code);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_THREADS_PTHREAD
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "PosixWaitObject.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class EventImpl : public posix::PosixWaitObject
|
||||
{
|
||||
public:
|
||||
EventImpl(bool manualReset = false, bool signaled = false);
|
||||
|
||||
ErrorCode Set();
|
||||
ErrorCode Reset();
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include "il2cpp-config.h"
|
||||
|
||||
#if IL2CPP_TARGET_POSIX
|
||||
|
||||
#include <string>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include "os/File.h"
|
||||
#include "os/c-api/OSGlobalEnums.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
struct FileHandle
|
||||
{
|
||||
int fd;
|
||||
FileType type;
|
||||
std::string path;
|
||||
int options;
|
||||
int shareMode;
|
||||
int accessMode;
|
||||
|
||||
// The defaukt value of this field should be false,
|
||||
// meaning we _do_ own the file descriptor, and therefore
|
||||
// can close it. Zero-allocating this struct is something
|
||||
// we want to support, so make sure the default is 0.
|
||||
bool doesNotOwnFd;
|
||||
|
||||
// device and inode are used as key for finding file handles
|
||||
dev_t device;
|
||||
ino_t inode;
|
||||
|
||||
// Linked list of file handles
|
||||
FileHandle *prev;
|
||||
FileHandle *next;
|
||||
|
||||
FileHandle() : prev(NULL), next(NULL)
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,73 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_THREADS_PTHREAD
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "PosixWaitObject.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class Thread;
|
||||
|
||||
class MutexImpl : public posix::PosixWaitObject
|
||||
{
|
||||
public:
|
||||
MutexImpl();
|
||||
|
||||
void Lock(bool interruptible);
|
||||
bool TryLock(uint32_t milliseconds, bool interruptible);
|
||||
void Unlock();
|
||||
|
||||
private:
|
||||
/// Thread that currently owns the object. Used for recursion checks.
|
||||
Thread* m_OwningThread;
|
||||
|
||||
/// Number of recursive locks on the owning thread.
|
||||
uint32_t m_RecursionCount;
|
||||
};
|
||||
|
||||
class FastMutexImpl
|
||||
{
|
||||
public:
|
||||
|
||||
FastMutexImpl()
|
||||
{
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
|
||||
pthread_mutex_init(&m_Mutex, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
}
|
||||
|
||||
~FastMutexImpl()
|
||||
{
|
||||
pthread_mutex_destroy(&m_Mutex);
|
||||
}
|
||||
|
||||
void Lock()
|
||||
{
|
||||
pthread_mutex_lock(&m_Mutex);
|
||||
}
|
||||
|
||||
void Unlock()
|
||||
{
|
||||
pthread_mutex_unlock(&m_Mutex);
|
||||
}
|
||||
|
||||
pthread_mutex_t* GetOSHandle()
|
||||
{
|
||||
return &m_Mutex;
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_mutex_t m_Mutex;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,65 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_TARGET_POSIX
|
||||
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#include <sys/poll.h>
|
||||
#include "os/Thread.h"
|
||||
#include "os/Socket.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
namespace posix
|
||||
{
|
||||
inline timespec Ticks100NanosecondsToTimespec(int64_t ticks)
|
||||
{
|
||||
timespec result;
|
||||
result.tv_sec = ticks / 10000000;
|
||||
result.tv_nsec = (ticks % 10000000) * 100;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline timespec MillisecondsToTimespec(uint32_t ms)
|
||||
{
|
||||
timespec result;
|
||||
result.tv_sec = ms / 1000;
|
||||
result.tv_nsec = (ms % 1000) * 1000000;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline Thread::ThreadId PosixThreadIdToThreadId(pthread_t thread)
|
||||
{
|
||||
Thread::ThreadId threadId = 0;
|
||||
memcpy(&threadId, &thread, std::min(sizeof(threadId), sizeof(thread)));
|
||||
return threadId;
|
||||
}
|
||||
|
||||
struct PosixAutoLock
|
||||
{
|
||||
pthread_mutex_t* mutex;
|
||||
PosixAutoLock(pthread_mutex_t* m)
|
||||
: mutex(m) { pthread_mutex_lock(mutex); }
|
||||
~PosixAutoLock()
|
||||
{ pthread_mutex_unlock(mutex); }
|
||||
};
|
||||
|
||||
|
||||
inline short PollFlagsToPollEvents(PollFlags flags)
|
||||
{
|
||||
return (short)flags;
|
||||
}
|
||||
|
||||
inline PollFlags PollEventsToPollFlags(short events)
|
||||
{
|
||||
return (PollFlags)events;
|
||||
}
|
||||
|
||||
int Poll(pollfd* handles, int numHandles, int timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // IL2CPP_TARGET_POSIX
|
||||
@@ -0,0 +1,95 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_TARGET_POSIX
|
||||
|
||||
#include <pthread.h>
|
||||
#include <stdint.h>
|
||||
#include <limits.h>
|
||||
#include "utils/NonCopyable.h"
|
||||
#include "os/WaitStatus.h"
|
||||
|
||||
|
||||
#if (IL2CPP_USE_POSIX_COND_TIMEDWAIT_REL)
|
||||
int pthread_cond_timedwait_relative_np(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *spec);
|
||||
#endif
|
||||
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ThreadImpl;
|
||||
|
||||
namespace posix
|
||||
{
|
||||
const uint32_t kNoTimeout = UINT_MAX;
|
||||
|
||||
|
||||
////TODO: generalize this so that it can be used with c++11 condition variables
|
||||
|
||||
|
||||
/// Base class for all synchronization primitives when running on POSIX.
|
||||
///
|
||||
/// To support interruption and timeouts for all synchronization primitives (events, mutexes, and
|
||||
/// semaphores) we implement these primitives ourselves instead of using their standard POSIX/Mach
|
||||
/// system counterparts. See PosixWaitObject.cpp for an explanation why.
|
||||
class PosixWaitObject : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
|
||||
~PosixWaitObject();
|
||||
|
||||
WaitStatus Wait(bool interruptible = false);
|
||||
WaitStatus Wait(uint32_t ms, bool interruptible = false);
|
||||
|
||||
/// Cause an ongoing blocking wait on this object to exit and check for pending APCs.
|
||||
/// If the object is not currently being waited on, will cause the next wait to exit
|
||||
/// right away and check for APCs. After APCs have been handled, the object will go
|
||||
/// back to waiting except if the wait timeout has expired.
|
||||
void InterruptWait();
|
||||
|
||||
static void LockWaitObjectDeletion();
|
||||
static void UnlockWaitObjectDeletion();
|
||||
|
||||
protected:
|
||||
|
||||
enum Type
|
||||
{
|
||||
kMutex, /// All mutexes are recursive.
|
||||
kManualResetEvent,
|
||||
kAutoResetEvent,
|
||||
kSemaphore
|
||||
};
|
||||
|
||||
PosixWaitObject(Type type);
|
||||
|
||||
Type m_Type;
|
||||
|
||||
/// Always have to acquire this mutex to touch m_Count.
|
||||
pthread_mutex_t m_Mutex;
|
||||
|
||||
/// Signal other threads of changes to m_Count.
|
||||
pthread_cond_t m_Condition;
|
||||
|
||||
/// "Release" count for the primitive. Means different things depending on the type of primitive
|
||||
/// but for all primitives, we wait until this is zero. Semaphores are the only primitive for which
|
||||
/// this can go past 1.
|
||||
uint32_t m_Count;
|
||||
|
||||
/// Number of threads waiting on this object. This is used to prevent unnecessary signals
|
||||
/// on m_Condition.
|
||||
uint32_t m_WaitingThreadCount;
|
||||
|
||||
bool HaveWaitingThreads() const { return (m_WaitingThreadCount != 0); }
|
||||
};
|
||||
|
||||
struct AutoLockWaitObjectDeletion
|
||||
{
|
||||
AutoLockWaitObjectDeletion() { PosixWaitObject::LockWaitObjectDeletion(); }
|
||||
~AutoLockWaitObjectDeletion() { PosixWaitObject::UnlockWaitObjectDeletion(); }
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // IL2CPP_TARGET_POSIX
|
||||
@@ -0,0 +1,70 @@
|
||||
#pragma once
|
||||
|
||||
#include "il2cpp-config.h"
|
||||
|
||||
#if IL2CPP_THREADS_PTHREAD
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ReaderWriterLockImpl
|
||||
{
|
||||
public:
|
||||
|
||||
ReaderWriterLockImpl()
|
||||
{
|
||||
int result = pthread_rwlock_init(&m_Lock, NULL);
|
||||
NO_UNUSED_WARNING(result);
|
||||
IL2CPP_ASSERT(result == 0);
|
||||
}
|
||||
|
||||
~ReaderWriterLockImpl()
|
||||
{
|
||||
int result = pthread_rwlock_destroy(&m_Lock);
|
||||
NO_UNUSED_WARNING(result);
|
||||
IL2CPP_ASSERT(result == 0);
|
||||
}
|
||||
|
||||
void LockExclusive()
|
||||
{
|
||||
int result = pthread_rwlock_wrlock(&m_Lock);
|
||||
NO_UNUSED_WARNING(result);
|
||||
IL2CPP_ASSERT(result == 0);
|
||||
}
|
||||
|
||||
void LockShared()
|
||||
{
|
||||
int result = pthread_rwlock_rdlock(&m_Lock);
|
||||
NO_UNUSED_WARNING(result);
|
||||
IL2CPP_ASSERT(result == 0);
|
||||
}
|
||||
|
||||
void ReleaseExclusive()
|
||||
{
|
||||
int result = pthread_rwlock_unlock(&m_Lock);
|
||||
NO_UNUSED_WARNING(result);
|
||||
IL2CPP_ASSERT(result == 0);
|
||||
}
|
||||
|
||||
void ReleaseShared()
|
||||
{
|
||||
int result = pthread_rwlock_unlock(&m_Lock);
|
||||
NO_UNUSED_WARNING(result);
|
||||
IL2CPP_ASSERT(result == 0);
|
||||
}
|
||||
|
||||
pthread_rwlock_t* GetOSHandle()
|
||||
{
|
||||
return &m_Lock;
|
||||
}
|
||||
|
||||
private:
|
||||
pthread_rwlock_t m_Lock;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_THREADS_PTHREAD
|
||||
|
||||
#include "PosixWaitObject.h"
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/WaitStatus.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <semaphore.h>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class SemaphoreImpl : public posix::PosixWaitObject
|
||||
{
|
||||
public:
|
||||
SemaphoreImpl(int32_t initialValue, int32_t maximumValue);
|
||||
|
||||
bool Post(int32_t releaseCount, int32_t* previousCount);
|
||||
|
||||
protected:
|
||||
uint32_t m_MaximumValue;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,131 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_TARGET_POSIX
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "os/Socket.h"
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
struct sockaddr;
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class SocketImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
typedef int SocketDescriptor;
|
||||
|
||||
SocketImpl(ThreadStatusCallback thread_status_callback);
|
||||
~SocketImpl();
|
||||
|
||||
inline SocketDescriptor GetDescriptor()
|
||||
{
|
||||
return _fd;
|
||||
}
|
||||
|
||||
ErrorCode GetLastError() const;
|
||||
|
||||
WaitStatus Create(SocketDescriptor fd, int32_t family, int32_t type, int32_t protocol);
|
||||
WaitStatus Create(AddressFamily family, SocketType type, ProtocolType protocol);
|
||||
WaitStatus Close();
|
||||
|
||||
bool IsClosed()
|
||||
{
|
||||
return (_fd == -1);
|
||||
}
|
||||
|
||||
WaitStatus SetBlocking(bool blocking);
|
||||
|
||||
WaitStatus Listen(int32_t blacklog);
|
||||
|
||||
WaitStatus Bind(const char *path);
|
||||
WaitStatus Bind(const char *address, uint16_t port);
|
||||
WaitStatus Bind(uint32_t address, uint16_t port);
|
||||
WaitStatus Bind(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port);
|
||||
|
||||
WaitStatus Connect(const char *path);
|
||||
WaitStatus Connect(uint32_t address, uint16_t port);
|
||||
WaitStatus Connect(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port);
|
||||
|
||||
WaitStatus Disconnect(bool reuse);
|
||||
WaitStatus Shutdown(int32_t how);
|
||||
|
||||
WaitStatus GetLocalEndPointInfo(EndPointInfo &info);
|
||||
WaitStatus GetRemoteEndPointInfo(EndPointInfo &info);
|
||||
|
||||
WaitStatus Receive(const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
WaitStatus ReceiveFromInternal(const uint8_t *data, size_t count, int32_t flags, int32_t *len, struct sockaddr *from, int32_t *fromlen);
|
||||
|
||||
WaitStatus Send(const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
|
||||
WaitStatus SendArray(WSABuf *wsabufs, int32_t count, int32_t *sent, SocketFlags c_flags);
|
||||
WaitStatus ReceiveArray(WSABuf *wsabufs, int32_t count, int32_t *len, SocketFlags c_flags);
|
||||
|
||||
WaitStatus SendTo(uint32_t address, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
WaitStatus SendTo(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
WaitStatus SendTo(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
|
||||
WaitStatus RecvFrom(uint32_t address, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
|
||||
WaitStatus RecvFrom(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
|
||||
WaitStatus RecvFrom(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
|
||||
|
||||
WaitStatus Available(int32_t *amount);
|
||||
|
||||
WaitStatus Accept(os::Socket **socket);
|
||||
|
||||
WaitStatus Ioctl(int32_t command, const uint8_t *in_data, int32_t in_len, uint8_t *out_data, int32_t out_len, int32_t *written);
|
||||
|
||||
WaitStatus GetSocketOption(SocketOptionLevel level, SocketOptionName name, uint8_t *buffer, int32_t *length);
|
||||
WaitStatus GetSocketOptionFull(SocketOptionLevel level, SocketOptionName name, int32_t *first, int32_t *second);
|
||||
|
||||
WaitStatus SetSocketOption(SocketOptionLevel level, SocketOptionName name, int32_t value);
|
||||
WaitStatus SetSocketOptionLinger(SocketOptionLevel level, SocketOptionName name, bool enabled, int32_t seconds);
|
||||
WaitStatus SetSocketOptionArray(SocketOptionLevel level, SocketOptionName name, const uint8_t *buffer, int32_t length);
|
||||
WaitStatus SetSocketOptionMembership(SocketOptionLevel level, SocketOptionName name, uint32_t group_address, uint32_t local_address);
|
||||
#if IL2CPP_SUPPORT_IPV6
|
||||
WaitStatus SetSocketOptionMembership(SocketOptionLevel level, SocketOptionName name, IPv6Address ipv6, uint64_t interfaceOffset);
|
||||
#endif
|
||||
|
||||
WaitStatus SendFile(const char *filename, TransmitFileBuffers *buffers, TransmitFileOptions options);
|
||||
|
||||
static WaitStatus Poll(std::vector<PollRequest> &requests, int32_t count, int32_t timeout, int32_t *result, int32_t *error);
|
||||
static WaitStatus Poll(std::vector<PollRequest> &requests, int32_t timeout, int32_t *result, int32_t *error);
|
||||
static WaitStatus Poll(PollRequest& request, int32_t timeout, int32_t *result, int32_t *error);
|
||||
|
||||
static WaitStatus GetHostName(std::string &name);
|
||||
static WaitStatus GetHostByName(const std::string &host, std::string &name, std::vector<std::string> &aliases, std::vector<std::string> &addresses);
|
||||
static WaitStatus GetHostByName(const std::string &host, std::string &name, int32_t &family, std::vector<std::string> &aliases, std::vector<void*> &addr_list, int32_t &addr_size);
|
||||
static WaitStatus GetHostByAddr(const std::string &address, std::string &name, std::vector<std::string> &aliases, std::vector<std::string> &addr_list);
|
||||
|
||||
static void Startup();
|
||||
static void Cleanup();
|
||||
|
||||
private:
|
||||
|
||||
bool _is_valid;
|
||||
SocketDescriptor _fd;
|
||||
int32_t _domain;
|
||||
int32_t _type;
|
||||
int32_t _protocol;
|
||||
ErrorCode _saved_error;
|
||||
int32_t _still_readable;
|
||||
ThreadStatusCallback _thread_status_callback;
|
||||
|
||||
void StoreLastError();
|
||||
void StoreLastError(int32_t error_no);
|
||||
|
||||
WaitStatus ConnectInternal(struct sockaddr *sa, int32_t sa_size);
|
||||
WaitStatus SendToInternal(struct sockaddr *sa, int32_t sa_size, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
WaitStatus SetSocketOptionInternal(int32_t level, int32_t name, const void *value, int32_t len);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,113 @@
|
||||
#pragma once
|
||||
|
||||
#if !IL2CPP_THREADS_STD && IL2CPP_THREADS_PTHREAD
|
||||
|
||||
#include <pthread.h>
|
||||
#include <vector>
|
||||
|
||||
#include "PosixWaitObject.h"
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/Mutex.h"
|
||||
#include "os/Event.h"
|
||||
#include "os/Thread.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
#if defined(IL2CPP_ENABLE_PLATFORM_THREAD_AFFINTY)
|
||||
struct cpu_set_t;
|
||||
int pthread_attr_setaffinity_np(pthread_attr_t *attr, size_t cpusetsize, const cpu_set_t *cpuset);
|
||||
#endif
|
||||
|
||||
#if defined(IL2CPP_ENABLE_PLATFORM_THREAD_RENAME)
|
||||
int pthread_setname_np(pthread_t handle, const char *name);
|
||||
#endif
|
||||
|
||||
#if !defined(IL2CPP_DEFAULT_STACK_SIZE)
|
||||
#define IL2CPP_DEFAULT_STACK_SIZE ( 1 * 1024 * 1024) // default .NET stacksize is 1mb
|
||||
#endif
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
/// POSIX threads implementation. Supports APCs and interruptible waits.
|
||||
class ThreadImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
|
||||
ThreadImpl();
|
||||
~ThreadImpl();
|
||||
|
||||
uint64_t Id();
|
||||
ErrorCode Run(Thread::StartFunc func, void* arg);
|
||||
void QueueUserAPC(Thread::APCFunc func, void* context);
|
||||
void SetName(const std::string& name);
|
||||
void SetPriority(ThreadPriority priority);
|
||||
ThreadPriority GetPriority();
|
||||
void SetStackSize(size_t newsize);
|
||||
static int GetMaxStackSize();
|
||||
|
||||
/// Handle any pending APCs.
|
||||
/// NOTE: Can only be called on current thread.
|
||||
void CheckForUserAPCAndHandle();
|
||||
|
||||
static void Sleep(uint32_t milliseconds, bool interruptible);
|
||||
static uint64_t CurrentThreadId();
|
||||
static ThreadImpl* GetCurrentThread();
|
||||
static ThreadImpl* CreateForCurrentThread();
|
||||
|
||||
#if NET_4_0
|
||||
static bool YieldInternal();
|
||||
#endif
|
||||
|
||||
#if IL2CPP_HAS_NATIVE_THREAD_CLEANUP
|
||||
static void SetNativeThreadCleanup(Thread::ThreadCleanupFunc cleanupFunction);
|
||||
static void RegisterCurrentThreadForCleanup(void* arg);
|
||||
static void UnregisterCurrentThreadForCleanup();
|
||||
#endif
|
||||
|
||||
private:
|
||||
|
||||
friend class posix::PosixWaitObject; // SetWaitObject(), CheckForAPCAndHandle()
|
||||
|
||||
pthread_t m_Handle;
|
||||
|
||||
/// The synchronization primitive that this thread is currently blocked on.
|
||||
///
|
||||
/// NOTE: This field effectively turns these wait object into shared resources -- which makes deletion
|
||||
/// a tricky affair. To avoid one thread trying to interrupt a wait while the other thread already
|
||||
/// is in progress of deleting the wait object, we use a global mutex in PosixWaitObject.cpp that
|
||||
/// must be locked by any thread trying to trigger an interrupt.
|
||||
posix::PosixWaitObject* m_CurrentWaitObject;
|
||||
|
||||
/// Start data.
|
||||
Thread::StartFunc m_StartFunc;
|
||||
void* m_StartArg;
|
||||
|
||||
/// List of APC requests for this thread.
|
||||
struct APCRequest
|
||||
{
|
||||
Thread::APCFunc callback;
|
||||
void* context;
|
||||
|
||||
APCRequest(Thread::APCFunc callback, void* context) :
|
||||
callback(callback), context(context)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
pthread_mutex_t m_PendingAPCsMutex;
|
||||
std::vector<APCRequest> m_PendingAPCs;
|
||||
|
||||
size_t m_StackSize; // size of stack (can not be adjusted after thread creation)
|
||||
|
||||
/// Set the synchronization object the thread is about to wait on.
|
||||
/// NOTE: This can only be called on the current thread.
|
||||
void SetWaitObject(posix::PosixWaitObject* waitObject);
|
||||
|
||||
static void* ThreadStartWrapper(void* arg);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_THREADS_PTHREAD
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ThreadLocalValueImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
ThreadLocalValueImpl();
|
||||
~ThreadLocalValueImpl();
|
||||
ErrorCode SetValue(void* value);
|
||||
ErrorCode GetValue(void** value);
|
||||
private:
|
||||
pthread_key_t m_Key;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
struct ProcessHandle;
|
||||
|
||||
class Process
|
||||
{
|
||||
public:
|
||||
static int GetCurrentProcessId();
|
||||
static ProcessHandle* GetProcess(int processId);
|
||||
static void FreeProcess(ProcessHandle* handle);
|
||||
static std::string GetProcessName(ProcessHandle* handle);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ReaderWriterLockImpl;
|
||||
|
||||
class ReaderWriterLock
|
||||
{
|
||||
public:
|
||||
ReaderWriterLock();
|
||||
~ReaderWriterLock();
|
||||
|
||||
void LockExclusive();
|
||||
void LockShared();
|
||||
void ReleaseExclusive();
|
||||
void ReleaseShared();
|
||||
|
||||
ReaderWriterLockImpl* GetImpl();
|
||||
|
||||
private:
|
||||
ReaderWriterLockImpl* m_Impl;
|
||||
};
|
||||
|
||||
struct ReaderWriterAutoLock : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
ReaderWriterAutoLock(ReaderWriterLock* lock, bool exclusive = false)
|
||||
: m_Lock(lock), m_Exclusive(exclusive)
|
||||
{
|
||||
if (m_Exclusive)
|
||||
m_Lock->LockExclusive();
|
||||
else
|
||||
m_Lock->LockShared();
|
||||
}
|
||||
|
||||
~ReaderWriterAutoLock()
|
||||
{
|
||||
if (m_Exclusive)
|
||||
m_Lock->ReleaseExclusive();
|
||||
else
|
||||
m_Lock->ReleaseShared();
|
||||
}
|
||||
|
||||
private:
|
||||
ReaderWriterLock* m_Lock;
|
||||
bool m_Exclusive;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include "os/Mutex.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ReaderWriterLockImpl
|
||||
{
|
||||
public:
|
||||
void LockExclusive()
|
||||
{
|
||||
m_Mutex.Lock();
|
||||
}
|
||||
|
||||
void LockShared()
|
||||
{
|
||||
m_Mutex.Lock();
|
||||
}
|
||||
|
||||
void ReleaseExclusive()
|
||||
{
|
||||
m_Mutex.Unlock();
|
||||
}
|
||||
|
||||
void ReleaseShared()
|
||||
{
|
||||
m_Mutex.Unlock();
|
||||
}
|
||||
|
||||
FastMutex* GetOSHandle()
|
||||
{
|
||||
return &m_Mutex;
|
||||
}
|
||||
|
||||
private:
|
||||
FastMutex m_Mutex;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "os/Handle.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class SemaphoreImpl;
|
||||
|
||||
class Semaphore : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
Semaphore(int32_t initialValue = 0, int32_t maximumValue = 1);
|
||||
~Semaphore();
|
||||
|
||||
bool Post(int32_t releaseCount = 1, int32_t* previousCount = NULL);
|
||||
WaitStatus Wait(bool interruptible = false);
|
||||
WaitStatus Wait(uint32_t ms, bool interruptible = false);
|
||||
|
||||
private:
|
||||
SemaphoreImpl* m_Semaphore;
|
||||
};
|
||||
|
||||
class SemaphoreHandle : public Handle
|
||||
{
|
||||
public:
|
||||
SemaphoreHandle(Semaphore* semaphore) : m_Semaphore(semaphore) {}
|
||||
virtual ~SemaphoreHandle() { delete m_Semaphore; }
|
||||
virtual bool Wait() { m_Semaphore->Wait(true); return true; }
|
||||
virtual bool Wait(uint32_t ms) { return m_Semaphore->Wait(ms, true) != kWaitStatusTimeout; }
|
||||
virtual WaitStatus Wait(bool interruptible) { return m_Semaphore->Wait(interruptible); }
|
||||
virtual WaitStatus Wait(uint32_t ms, bool interruptible) { return m_Semaphore->Wait(ms, interruptible); }
|
||||
virtual void Signal() { m_Semaphore->Post(1, NULL); }
|
||||
Semaphore& Get() { return *m_Semaphore; }
|
||||
|
||||
private:
|
||||
Semaphore* m_Semaphore;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "il2cpp-config.h"
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/Atomic.h"
|
||||
#include "os/Mutex.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class SocketImpl;
|
||||
|
||||
enum AddressFamily
|
||||
{
|
||||
kAddressFamilyError = -1,
|
||||
kAddressFamilyUnspecified = 0,// AF_UNSPEC
|
||||
kAddressFamilyUnix = 1,// AF_UNIX
|
||||
kAddressFamilyInterNetwork = 2,// AF_INET
|
||||
kAddressFamilyIpx = 3,// AF_IPX
|
||||
kAddressFamilySna = 4,// AF_SNA
|
||||
kAddressFamilyDecNet = 5,// AF_DECnet
|
||||
kAddressFamilyAppleTalk = 6,// AF_APPLETALK
|
||||
kAddressFamilyInterNetworkV6 = 7,// AF_INET6
|
||||
kAddressFamilyIrda = 8,// AF_IRDA
|
||||
};
|
||||
|
||||
enum SocketType
|
||||
{
|
||||
kSocketTypeError = -1,
|
||||
kSocketTypeStream = 0,// SOCK_STREAM
|
||||
kSocketTypeDgram = 1,// SOCK_DGRAM
|
||||
kSocketTypeRaw = 2,// SOCK_RAW
|
||||
kSocketTypeRdm = 3,// SOCK_RDM
|
||||
kSocketTypeSeqpacket = 4,// SOCK_SEQPACKET
|
||||
};
|
||||
|
||||
enum ProtocolType
|
||||
{
|
||||
kProtocolTypeUnknown = -1,
|
||||
kProtocolTypeIP = 0,
|
||||
kProtocolTypeIcmp = 1,
|
||||
kProtocolTypeIgmp = 2,
|
||||
kProtocolTypeGgp = 3,
|
||||
kProtocolTypeTcp = 6,
|
||||
kProtocolTypePup = 12,
|
||||
kProtocolTypeUdp = 17,
|
||||
kProtocolTypeIdp = 22,
|
||||
kProtocolTypeND = 77,
|
||||
kProtocolTypeRaw = 255,
|
||||
kProtocolTypeUnspecified = 0,
|
||||
kProtocolTypeIpx = 1000,
|
||||
kProtocolTypeSpx = 1256,
|
||||
kProtocolTypeSpxII = 1257,
|
||||
|
||||
// #if NET_1_1
|
||||
kProtocolTypeIPv6 = 41,
|
||||
// #endif
|
||||
|
||||
// #if NET_2_0
|
||||
kProtocolTypeIPv4 = 4,
|
||||
kProtocolTypeIPv6RoutingHeader = 43,
|
||||
kProtocolTypeIPv6FragmentHeader = 44,
|
||||
kProtocolTypeIPSecEncapsulatingSecurityPayload = 50,
|
||||
kProtocolTypeIPSecAuthenticationHeader = 51,
|
||||
kProtocolTypeIcmpV6 = 58,
|
||||
kProtocolTypeIPv6NoNextHeader = 59,
|
||||
kProtocolTypeIPv6DestinationOptions = 60,
|
||||
kProtocolTypeIPv6HopByHopOptions = 0,
|
||||
// #endif
|
||||
};
|
||||
|
||||
enum SocketFlags
|
||||
{
|
||||
kSocketFlagsNone = 0x00000000,
|
||||
kSocketFlagsOutOfBand = 0x00000001,
|
||||
kSocketFlagsPeek = 0x00000002,
|
||||
kSocketFlagsDontRoute = 0x00000004,
|
||||
kSocketFlagsMaxIOVectorLength = 0x00000010,
|
||||
// #if NET_2_0
|
||||
kSocketFlagsTruncated = 0x00000100,
|
||||
kSocketFlagsControlDataTruncated = 0x00000200,
|
||||
kSocketFlagsBroadcast = 0x00000400,
|
||||
kSocketFlagsMulticast = 0x00000800,
|
||||
// #endif
|
||||
kSocketFlagsPartial = 0x00008000,
|
||||
};
|
||||
|
||||
enum SocketOptionLevel
|
||||
{
|
||||
kSocketOptionLevelSocket = 65535,
|
||||
kSocketOptionLevelIP = 0,
|
||||
kSocketOptionLevelTcp = 6,
|
||||
kSocketOptionLevelUdp = 17,
|
||||
|
||||
//#if NET_1_1
|
||||
kSocketOptionLevelIPv6 = 41,
|
||||
//#endif
|
||||
};
|
||||
|
||||
enum SocketOptionName
|
||||
{
|
||||
kSocketOptionNameDebug = 1,
|
||||
kSocketOptionNameAcceptConnection = 2,
|
||||
kSocketOptionNameReuseAddress = 4,
|
||||
kSocketOptionNameKeepAlive = 8,
|
||||
kSocketOptionNameDontRoute = 16,
|
||||
kSocketOptionNameBroadcast = 32,
|
||||
kSocketOptionNameUseLoopback = 64,
|
||||
kSocketOptionNameLinger = 128,
|
||||
kSocketOptionNameOutOfBandInline = 256,
|
||||
kSocketOptionNameDontLinger = -129,
|
||||
kSocketOptionNameExclusiveAddressUse = -5,
|
||||
kSocketOptionNameSendBuffer = 4097,
|
||||
kSocketOptionNameReceiveBuffer = 4098,
|
||||
kSocketOptionNameSendLowWater = 4099,
|
||||
kSocketOptionNameReceiveLowWater = 4100,
|
||||
kSocketOptionNameSendTimeout = 4101,
|
||||
kSocketOptionNameReceiveTimeout = 4102,
|
||||
kSocketOptionNameError = 4103,
|
||||
kSocketOptionNameType = 4104,
|
||||
kSocketOptionNameMaxConnections = 2147483647,
|
||||
kSocketOptionNameIPOptions = 1,
|
||||
kSocketOptionNameHeaderIncluded = 2,
|
||||
kSocketOptionNameTypeOfService = 3,
|
||||
kSocketOptionNameIpTimeToLive = 4,
|
||||
kSocketOptionNameMulticastInterface = 9,
|
||||
kSocketOptionNameMulticastTimeToLive = 10,
|
||||
kSocketOptionNameMulticastLoopback = 11,
|
||||
kSocketOptionNameAddMembership = 12,
|
||||
kSocketOptionNameDropMembership = 13,
|
||||
kSocketOptionNameDontFragment = 14,
|
||||
kSocketOptionNameAddSourceMembership = 15,
|
||||
kSocketOptionNameDropSourceMembership = 16,
|
||||
kSocketOptionNameBlockSource = 17,
|
||||
kSocketOptionNameUnblockSource = 18,
|
||||
kSocketOptionNamePacketInformation = 19,
|
||||
kSocketOptionNameNoDelay = 1,
|
||||
kSocketOptionNameBsdUrgent = 2,
|
||||
kSocketOptionNameExpedited = 2,
|
||||
kSocketOptionNameNoChecksum = 1,
|
||||
kSocketOptionNameChecksumCoverage = 20,
|
||||
kSocketOptionNameIPv6Only = 27,
|
||||
|
||||
// #if NET_2_0
|
||||
kSocketOptionNameHopLimit = 21,
|
||||
kSocketOptionNameUpdateAcceptContext = 28683,
|
||||
kSocketOptionNameUpdateConnectContext = 28688,
|
||||
// #endif
|
||||
};
|
||||
|
||||
enum PollFlags
|
||||
{
|
||||
kPollFlagsNone = 0,
|
||||
kPollFlagsIn = 1,
|
||||
kPollFlagsPri = 2,
|
||||
kPollFlagsOut = 4,
|
||||
kPollFlagsErr = 8,
|
||||
kPollFlagsHup = 0x10,
|
||||
kPollFlagsNVal = 0x20,
|
||||
kPollFlagsAny = 0xffffffff
|
||||
};
|
||||
|
||||
enum SocketError
|
||||
{
|
||||
kInterrupted = 4,// EINTR on POSIX and WSAEINTR on Windows
|
||||
kInvalidHandle = 9 // EBADF on POSIX and WSAEBADF on Windows
|
||||
};
|
||||
|
||||
inline void operator|=(PollFlags& left, PollFlags right)
|
||||
{
|
||||
left = static_cast<PollFlags>(static_cast<int>(left) | static_cast<int>(right));
|
||||
}
|
||||
|
||||
enum TransmitFileOptions
|
||||
{
|
||||
kTransmitFileOptionsUseDefaultWorkerThread = 0x00000000,
|
||||
kTransmitFileOptionsDisconnect = 0x00000001,
|
||||
kTransmitFileOptionsReuseSocket = 0x00000002,
|
||||
kTransmitFileOptionsWriteBehind = 0x00000004,
|
||||
kTransmitFileOptionsUseSystemThread = 0x00000010,
|
||||
kTransmitFileOptionsUseKernelApc = 0x00000020,
|
||||
};
|
||||
|
||||
class Socket;
|
||||
|
||||
struct PollRequest
|
||||
{
|
||||
int64_t fd;
|
||||
PollFlags events;
|
||||
PollFlags revents;
|
||||
};
|
||||
|
||||
#if IL2CPP_SUPPORT_IPV6
|
||||
struct IPv6Address
|
||||
{
|
||||
uint8_t addr[16];
|
||||
};
|
||||
#endif
|
||||
|
||||
// TODO: this should really be UNIX_PATH_MAX or SUN_LEN(n)
|
||||
#define END_POINT_MAX_PATH_LEN 255
|
||||
|
||||
#if IL2CPP_COMPILER_MSVC
|
||||
#pragma warning( push )
|
||||
#pragma warning( disable : 4200 )
|
||||
#endif
|
||||
|
||||
struct EndPointInfo
|
||||
{
|
||||
AddressFamily family;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint32_t port;
|
||||
uint32_t address;
|
||||
} inet;
|
||||
char path[END_POINT_MAX_PATH_LEN];
|
||||
uint8_t raw[IL2CPP_ZERO_LEN_ARRAY];
|
||||
} data;
|
||||
};
|
||||
|
||||
#if IL2CPP_COMPILER_MSVC
|
||||
#pragma warning( pop )
|
||||
#endif
|
||||
|
||||
// NOTE(gab): this must be binary compatible with Windows's WSABUF
|
||||
struct WSABuf
|
||||
{
|
||||
uint32_t length;
|
||||
void *buffer;
|
||||
};
|
||||
|
||||
// NOTE(gab): this must be binary compatible with Window's TRANSMIT_FILE_BUFFERS
|
||||
struct TransmitFileBuffers
|
||||
{
|
||||
void *head;
|
||||
uint32_t head_length;
|
||||
void *tail;
|
||||
uint32_t tail_length;
|
||||
};
|
||||
|
||||
// Note: this callback can be invoked by the os-specific implementation when an
|
||||
// interrupt is received or when the native code is looping in a potentially long
|
||||
// loop.
|
||||
// If the callback retun false, the executiong of the os-specific method is
|
||||
// gracefully interrupted, and an error is supposed to be returned by the
|
||||
// os-specific implementation.
|
||||
// The callback is allowed to throw exceptions (for example a ThreadAborted exception):
|
||||
// in this case, it is up to the os-specific implementation to properly deal with
|
||||
// cleaning up the temporarely allocated memory (if any).
|
||||
typedef bool (*ThreadStatusCallback)();
|
||||
|
||||
class Socket : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
|
||||
Socket(ThreadStatusCallback thread_status_callback);
|
||||
~Socket();
|
||||
|
||||
// Note: this Create is only used internally
|
||||
WaitStatus Create(int64_t fd, int32_t family, int32_t type, int32_t protocol);
|
||||
WaitStatus Create(AddressFamily family, SocketType type, ProtocolType protocol);
|
||||
|
||||
bool IsClosed();
|
||||
void Close();
|
||||
|
||||
int64_t GetDescriptor();
|
||||
|
||||
ErrorCode GetLastError() const;
|
||||
|
||||
WaitStatus SetBlocking(bool blocking);
|
||||
|
||||
WaitStatus Listen(int32_t blacklog);
|
||||
|
||||
WaitStatus Bind(const char *path);
|
||||
WaitStatus Bind(uint32_t address, uint16_t port);
|
||||
WaitStatus Bind(const char *address, uint16_t port);
|
||||
WaitStatus Bind(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port);
|
||||
|
||||
WaitStatus Connect(const char *path);
|
||||
WaitStatus Connect(uint32_t address, uint16_t port);
|
||||
WaitStatus Connect(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port);
|
||||
|
||||
WaitStatus Disconnect(bool reuse);
|
||||
WaitStatus Shutdown(int32_t how);
|
||||
|
||||
WaitStatus GetLocalEndPointInfo(EndPointInfo &info);
|
||||
WaitStatus GetRemoteEndPointInfo(EndPointInfo &info);
|
||||
|
||||
WaitStatus Receive(const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
WaitStatus Send(const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
|
||||
WaitStatus SendArray(WSABuf *wsabufs, int32_t count, int32_t *sent, SocketFlags c_flags);
|
||||
WaitStatus ReceiveArray(WSABuf *wsabufs, int32_t count, int32_t *len, SocketFlags c_flags);
|
||||
|
||||
WaitStatus SendTo(uint32_t address, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
WaitStatus SendTo(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
WaitStatus SendTo(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
|
||||
WaitStatus RecvFrom(uint32_t address, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
|
||||
WaitStatus RecvFrom(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
|
||||
WaitStatus RecvFrom(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
|
||||
|
||||
WaitStatus Available(int32_t *amount);
|
||||
|
||||
WaitStatus Accept(Socket **socket);
|
||||
|
||||
WaitStatus Ioctl(int32_t command, const uint8_t *in_data, int32_t in_len, uint8_t *out_data, int32_t out_len, int32_t *written);
|
||||
|
||||
WaitStatus GetSocketOption(SocketOptionLevel level, SocketOptionName name, uint8_t *buffer, int32_t *length);
|
||||
WaitStatus GetSocketOptionFull(SocketOptionLevel level, SocketOptionName name, int32_t *first, int32_t *second);
|
||||
|
||||
WaitStatus SetSocketOption(SocketOptionLevel level, SocketOptionName name, int32_t value);
|
||||
WaitStatus SetSocketOptionLinger(SocketOptionLevel level, SocketOptionName name, bool enabled, int32_t seconds);
|
||||
WaitStatus SetSocketOptionArray(SocketOptionLevel level, SocketOptionName name, const uint8_t *buffer, int32_t length);
|
||||
WaitStatus SetSocketOptionMembership(SocketOptionLevel level, SocketOptionName name, uint32_t group_address, uint32_t local_address);
|
||||
#if IL2CPP_SUPPORT_IPV6
|
||||
WaitStatus SetSocketOptionMembership(SocketOptionLevel level, SocketOptionName name, IPv6Address ipv6, uint64_t interfaceOffset);
|
||||
#endif
|
||||
|
||||
WaitStatus SendFile(const char *filename, TransmitFileBuffers *buffers, TransmitFileOptions options);
|
||||
|
||||
static WaitStatus Poll(std::vector<PollRequest> &requests, int32_t count, int32_t timeout, int32_t *result, int32_t *error);
|
||||
static WaitStatus Poll(std::vector<PollRequest> &requests, int32_t timeout, int32_t *result, int32_t *error);
|
||||
static WaitStatus Poll(PollRequest &request, int32_t timeout, int32_t *result, int32_t *error);
|
||||
|
||||
static WaitStatus GetHostName(std::string &name);
|
||||
static WaitStatus GetHostByName(const std::string &host, std::string &name, std::vector<std::string> &aliases, std::vector<std::string> &addresses);
|
||||
|
||||
// The pointers in addr_list are allocated with the il2cpp::utils::Memory::Malloc method. They should he freed by the caller using il2cpp::utils::Memory::Free.
|
||||
static WaitStatus GetHostByName(const std::string &host, std::string &name, int32_t &family, std::vector<std::string> &aliases, std::vector<void*> &addr_list, int32_t &addr_size);
|
||||
static WaitStatus GetHostByAddr(const std::string &address, std::string &name, std::vector<std::string> &aliases, std::vector<std::string> &addr_list);
|
||||
|
||||
static void Startup();
|
||||
static void Cleanup();
|
||||
|
||||
private:
|
||||
SocketImpl* m_Socket;
|
||||
};
|
||||
|
||||
/// Sockets should generally be referenced through SocketHandles for thread-safety.
|
||||
/// Handles are stored in a table and can be safely used even when the socket has already
|
||||
/// been deleted.
|
||||
typedef uint32_t SocketHandle;
|
||||
|
||||
enum
|
||||
{
|
||||
kInvalidSocketHandle = 0
|
||||
};
|
||||
|
||||
SocketHandle CreateSocketHandle(Socket* socket);
|
||||
Socket* AcquireSocketHandle(SocketHandle handle);
|
||||
void ReleaseSocketHandle(SocketHandle handle);
|
||||
|
||||
inline SocketHandle PointerToSocketHandle(void* ptr)
|
||||
{
|
||||
// Double cast to avoid warnings.
|
||||
return static_cast<SocketHandle>(reinterpret_cast<size_t>(ptr));
|
||||
}
|
||||
|
||||
/// Helper to automatically acquire and release a Socket within a scope.
|
||||
struct SocketHandleWrapper
|
||||
{
|
||||
SocketHandleWrapper()
|
||||
: m_Handle(kInvalidSocketHandle)
|
||||
, m_Socket(NULL) {}
|
||||
SocketHandleWrapper(SocketHandle handle)
|
||||
: m_Handle(handle)
|
||||
{
|
||||
m_Socket = AcquireSocketHandle(handle);
|
||||
}
|
||||
|
||||
SocketHandleWrapper(const SocketHandleWrapper& other)
|
||||
{
|
||||
m_Handle = other.m_Handle;
|
||||
if (m_Handle != kInvalidSocketHandle)
|
||||
m_Socket = AcquireSocketHandle(m_Handle);
|
||||
else
|
||||
m_Socket = NULL;
|
||||
}
|
||||
|
||||
~SocketHandleWrapper()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
void Acquire(SocketHandle handle)
|
||||
{
|
||||
Release();
|
||||
m_Handle = handle;
|
||||
m_Socket = AcquireSocketHandle(handle);
|
||||
}
|
||||
|
||||
void Release()
|
||||
{
|
||||
if (m_Socket)
|
||||
ReleaseSocketHandle(m_Handle);
|
||||
m_Socket = NULL;
|
||||
m_Handle = kInvalidSocketHandle;
|
||||
}
|
||||
|
||||
bool IsValid() const
|
||||
{
|
||||
return (m_Socket != NULL);
|
||||
}
|
||||
|
||||
SocketHandle GetHandle() const
|
||||
{
|
||||
return m_Handle;
|
||||
}
|
||||
|
||||
Socket* GetSocket() const
|
||||
{
|
||||
return m_Socket;
|
||||
}
|
||||
|
||||
Socket* operator->() const
|
||||
{
|
||||
return GetSocket();
|
||||
}
|
||||
|
||||
SocketHandleWrapper& operator=(const SocketHandleWrapper& other)
|
||||
{
|
||||
Acquire(other.GetHandle());
|
||||
return *this;
|
||||
}
|
||||
|
||||
private:
|
||||
SocketHandle m_Handle;
|
||||
Socket* m_Socket;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
typedef bool(*WalkStackCallback)(Il2CppMethodPointer frame, void* context);
|
||||
|
||||
class StackTrace
|
||||
{
|
||||
public:
|
||||
enum WalkOrder
|
||||
{
|
||||
kFirstCalledToLastCalled,
|
||||
kLastCalledToFirstCalled
|
||||
};
|
||||
|
||||
// Walks the stack calling callback for each frame in the stack
|
||||
// Stops when callback returns false
|
||||
static void WalkStack(WalkStackCallback callback, void* context, WalkOrder walkOrder);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_THREADS_STD
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/Thread.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
#include <thread>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ThreadImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
ThreadImpl();
|
||||
~ThreadImpl();
|
||||
uint64_t Id();
|
||||
ErrorCode Run(Thread::StartFunc func, void* arg);
|
||||
WaitStatus Join();
|
||||
WaitStatus Join(uint32_t ms);
|
||||
static WaitStatus Sleep(uint32_t milliseconds);
|
||||
static uint64_t CurrentThreadId();
|
||||
private:
|
||||
std::thread m_Thread;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
typedef enum
|
||||
{
|
||||
DATATYPE_STRING = 0,
|
||||
DATATYPE_INTPTR = 1,
|
||||
DATATYPE_FILE = 2
|
||||
} CertDataFormat;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void* certdata;
|
||||
int certsize;
|
||||
} CertObj;
|
||||
|
||||
class SystemCertificates
|
||||
{
|
||||
public:
|
||||
static void* OpenSystemRootStore();
|
||||
static int EnumSystemCertificates(void* certStore, void** iter, int *format, int* size, void** data);
|
||||
static void CloseSystemRootStore(void* cStore);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
#pragma once
|
||||
|
||||
#include "il2cpp-config.h"
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/Handle.h"
|
||||
#include "os/Event.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ThreadImpl;
|
||||
|
||||
enum ThreadPriority
|
||||
{
|
||||
kThreadPriorityLowest = 0,
|
||||
kThreadPriorityLow = 1,
|
||||
kThreadPriorityNormal = 2,
|
||||
kThreadPriorityHigh = 3,
|
||||
kThreadPriorityHighest = 4
|
||||
};
|
||||
|
||||
enum ApartmentState
|
||||
{
|
||||
kApartmentStateInSTA = 0,
|
||||
kApartmentStateInMTA = 1,
|
||||
kApartmentStateUnknown = 2,
|
||||
kApartmentStateCoInitialized = 4,
|
||||
};
|
||||
|
||||
class Thread : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
Thread();
|
||||
~Thread();
|
||||
|
||||
typedef void (*StartFunc) (void* arg);
|
||||
// Use STDCALL calling convention on Windows, as it will be called back directly from the OS. This is defined as nothing on other platforms.
|
||||
typedef void (STDCALL * APCFunc)(void* context);
|
||||
typedef uint64_t ThreadId;
|
||||
typedef void (*CleanupFunc) (void* arg);
|
||||
|
||||
/// Initialize/Shutdown thread subsystem. Must be called on main thread.
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
ErrorCode Run(StartFunc func, void* arg);
|
||||
ThreadId Id();
|
||||
|
||||
/// Set thread name for debugging purposes. Won't do anything if not supported
|
||||
/// by platform.
|
||||
void SetName(const std::string& name);
|
||||
|
||||
void SetPriority(ThreadPriority priority);
|
||||
ThreadPriority GetPriority();
|
||||
|
||||
void SetStackSize(size_t stackSize);
|
||||
static int GetMaxStackSize();
|
||||
|
||||
void SetCleanupFunction(CleanupFunc cleanupFunc, void* arg)
|
||||
{
|
||||
m_CleanupFunc = cleanupFunc;
|
||||
m_CleanupFuncArg = arg;
|
||||
}
|
||||
|
||||
/// Interruptible, infinite wait join.
|
||||
WaitStatus Join();
|
||||
|
||||
/// Interruptible, timed wait join.
|
||||
WaitStatus Join(uint32_t ms);
|
||||
|
||||
/// Execute the given function on the thread the next time the thread executes
|
||||
/// an interruptible blocking operation.
|
||||
/// NOTE: The APC is allowed to raise exceptions!
|
||||
void QueueUserAPC(APCFunc func, void* context);
|
||||
|
||||
// Explicit versions modify state without actually changing COM state.
|
||||
// Used to set thread state before it's started.
|
||||
ApartmentState GetApartment();
|
||||
ApartmentState GetExplicitApartment();
|
||||
ApartmentState SetApartment(ApartmentState state);
|
||||
void SetExplicitApartment(ApartmentState state);
|
||||
|
||||
/// Interruptible, timed sleep.
|
||||
static void Sleep(uint32_t ms, bool interruptible = false);
|
||||
|
||||
static ThreadId CurrentThreadId();
|
||||
static Thread* GetCurrentThread();
|
||||
static Thread* GetOrCreateCurrentThread();
|
||||
static void DetachCurrentThread();
|
||||
|
||||
#if NET_4_0
|
||||
static bool YieldInternal();
|
||||
#endif
|
||||
|
||||
#if IL2CPP_HAS_NATIVE_THREAD_CLEANUP
|
||||
typedef void (*ThreadCleanupFunc) (void* arg);
|
||||
static void SetNativeThreadCleanup(ThreadCleanupFunc cleanupFunction);
|
||||
static void RegisterCurrentThreadForCleanup(void* arg);
|
||||
static void UnregisterCurrentThreadForCleanup();
|
||||
void SignalExited();
|
||||
#endif
|
||||
|
||||
static const uint64_t kInvalidThreadId = 0;
|
||||
|
||||
private:
|
||||
|
||||
enum ThreadState
|
||||
{
|
||||
kThreadCreated,
|
||||
kThreadRunning,
|
||||
kThreadWaiting,
|
||||
kThreadExited
|
||||
};
|
||||
|
||||
ThreadState m_State;
|
||||
|
||||
friend class ThreadImpl; // m_Thread
|
||||
|
||||
ThreadImpl* m_Thread;
|
||||
|
||||
/// Event that the thread signals when it finishes execution. Used for joins.
|
||||
/// Supports interruption.
|
||||
Event m_ThreadExitedEvent;
|
||||
|
||||
CleanupFunc m_CleanupFunc;
|
||||
void* m_CleanupFuncArg;
|
||||
|
||||
Thread(ThreadImpl* thread);
|
||||
|
||||
static void RunWrapper(void* arg);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ThreadLocalValueImpl;
|
||||
|
||||
class ThreadLocalValue
|
||||
{
|
||||
public:
|
||||
ThreadLocalValue();
|
||||
~ThreadLocalValue();
|
||||
ErrorCode SetValue(void* value);
|
||||
ErrorCode GetValue(void** value);
|
||||
private:
|
||||
ThreadLocalValueImpl* m_ThreadLocalValue;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class Time
|
||||
{
|
||||
public:
|
||||
/* Returns the number of milliseconds from boot time: this should be monotonic */
|
||||
static uint32_t GetTicksMillisecondsMonotonic();
|
||||
|
||||
/* Returns the number of 100ns ticks from unspecified time: this should be monotonic */
|
||||
static int64_t GetTicks100NanosecondsMonotonic();
|
||||
|
||||
/* Returns the number of 100ns ticks since 1/1/1, UTC timezone */
|
||||
static int64_t GetTicks100NanosecondsDateTime();
|
||||
|
||||
// Retrieves the current system date and time. The information is in Coordinated Universal Time(UTC) format.
|
||||
static int64_t GetSystemTimeAsFileTime();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class TimeZone
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* This is heavily based on zdump.c from glibc 2.2.
|
||||
*
|
||||
* * data[0]: start of daylight saving time (in DateTime ticks).
|
||||
* * data[1]: end of daylight saving time (in DateTime ticks).
|
||||
* * data[2]: utcoffset (in TimeSpan ticks).
|
||||
* * data[3]: additional offset when daylight saving (in TimeSpan ticks).
|
||||
* * name[0]: name of this timezone when not daylight saving.
|
||||
* * name[1]: name of this timezone when daylight saving.
|
||||
*
|
||||
* FIXME: This only works with "standard" Unix dates (years between 1900 and 2100) while
|
||||
* the class library allows years between 1 and 9999.
|
||||
*
|
||||
* Returns true on success and zero on failure.
|
||||
*/
|
||||
#if NET_4_0
|
||||
static bool GetTimeZoneData(int32_t year, int64_t data[4], std::string names[2], bool* daylight_inverted);
|
||||
#else
|
||||
static bool GetTimeZoneData(int32_t year, int64_t data[4], std::string names[2]);
|
||||
#endif
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class TimeZoneInfo
|
||||
{
|
||||
public:
|
||||
static bool UsePalForTimeZoneInfo();
|
||||
static void* GetTimeZoneIDs();
|
||||
static bool GetLocalTimeZoneData(void** nativeRawData, char** nativeID, int* size);
|
||||
static bool GetTimeZoneDataForID(char* id, void** nativeRawData, int* size);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include "ExtendedAtomicTypes.h"
|
||||
|
||||
UNITY_PLATFORM_BEGIN_NAMESPACE;
|
||||
|
||||
class AtomicNode
|
||||
{
|
||||
friend class AtomicStack;
|
||||
friend class AtomicQueue;
|
||||
friend class MutexLockedStack;
|
||||
friend class MutexLockedQueue;
|
||||
|
||||
volatile atomic_word _next;
|
||||
|
||||
public:
|
||||
void* data[3];
|
||||
|
||||
AtomicNode *Next() const
|
||||
{
|
||||
return (AtomicNode*)_next;
|
||||
}
|
||||
|
||||
AtomicNode *Link(AtomicNode *next);
|
||||
};
|
||||
|
||||
UNITY_PLATFORM_END_NAMESPACE;
|
||||
@@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
|
||||
#include "UnityPlatformConfigure.h"
|
||||
#include "ExtendedAtomicTypes.h"
|
||||
#include "AtomicNode.h"
|
||||
|
||||
|
||||
UNITY_PLATFORM_BEGIN_NAMESPACE;
|
||||
|
||||
#if defined(ATOMIC_HAS_QUEUE)
|
||||
|
||||
|
||||
// A generic lockfree stack.
|
||||
// Any thread can Push / Pop nodes to the stack.
|
||||
|
||||
// The stack is lockfree and highly optimized. It has different implementations for different architectures.
|
||||
|
||||
// On intel / arm it is built with double CAS:
|
||||
// http://en.wikipedia.org/wiki/Double_compare-and-swap
|
||||
// On PPC it is built on LL/SC:
|
||||
// http://en.wikipedia.org/wiki/Load-link/store-conditional
|
||||
|
||||
class AtomicStack
|
||||
{
|
||||
#if defined(ATOMIC_HAS_DCAS)
|
||||
volatile atomic_word2 _top;
|
||||
#else
|
||||
volatile atomic_word _top;
|
||||
#endif
|
||||
|
||||
public:
|
||||
AtomicStack();
|
||||
~AtomicStack();
|
||||
|
||||
int IsEmpty() const;
|
||||
|
||||
void Push(AtomicNode *node);
|
||||
void PushAll(AtomicNode *first, AtomicNode *last);
|
||||
|
||||
AtomicNode *Pop();
|
||||
AtomicNode *PopAll();
|
||||
};
|
||||
|
||||
AtomicStack* CreateAtomicStack();
|
||||
void DestroyAtomicStack(AtomicStack* s);
|
||||
|
||||
|
||||
// A generic lockfree queue FIFO queue.
|
||||
// Any thread can Enqueue / Dequeue in parallel.
|
||||
// We do guarantee that all 3 data pointer are the same after dequeuing.
|
||||
//
|
||||
// But when pushing / popping a node there is no guarantee that the pointer to the AtomicNode is the same.
|
||||
// Enqueue adds node to the head, and Dequeue pops it from the tail.
|
||||
// Implementation relies on dummy head node which allow to modify next pointer atomically.
|
||||
// Thus Dequeue pops not the enqueued node, but the next one.
|
||||
// Empty: [ head ] [next] [ tail ]
|
||||
// dummy 0 dummy
|
||||
// Enqueue: [ head ] [next] [next] [ tail ]
|
||||
// node1 dummy 0 dummy
|
||||
// Dequeue: [ head ] [next] [ tail ] -> dummy dequeued, but with node1 data[3]
|
||||
// node1 0 node1
|
||||
// Make sure to destroy nodes consistently.
|
||||
|
||||
// The queue is lockfree and highly optimized. It has different implementations for different architectures.
|
||||
|
||||
// On intel / arm it is built with double CAS:
|
||||
// http://en.wikipedia.org/wiki/Double_compare-and-swap
|
||||
// On PPC it is built on LL/SC:
|
||||
// http://en.wikipedia.org/wiki/Load-link/store-conditional
|
||||
|
||||
class AtomicQueue
|
||||
{
|
||||
#if defined(ATOMIC_HAS_DCAS)
|
||||
volatile atomic_word2 _tail;
|
||||
#else
|
||||
volatile atomic_word _tail;
|
||||
#endif
|
||||
volatile atomic_word _head;
|
||||
|
||||
public:
|
||||
AtomicQueue();
|
||||
~AtomicQueue();
|
||||
|
||||
int IsEmpty() const;
|
||||
|
||||
void Enqueue(AtomicNode *node);
|
||||
void EnqueueAll(AtomicNode *first, AtomicNode *last);
|
||||
AtomicNode *Dequeue();
|
||||
};
|
||||
|
||||
AtomicQueue* CreateAtomicQueue();
|
||||
void DestroyAtomicQueue(AtomicQueue* s);
|
||||
|
||||
#elif IL2CPP_SUPPORT_THREADS
|
||||
#error Platform is missing atomic queue implementation
|
||||
#endif
|
||||
|
||||
//
|
||||
// Special concurrent list for JobQueue
|
||||
// This code is not meant to be general purpose and should not be used outside of the job queue.
|
||||
|
||||
class AtomicList
|
||||
{
|
||||
#if defined(ATOMIC_HAS_DCAS)
|
||||
|
||||
volatile atomic_word2 _top;
|
||||
|
||||
#else
|
||||
|
||||
volatile atomic_word _top;
|
||||
volatile atomic_word _ver;
|
||||
|
||||
#endif
|
||||
|
||||
public:
|
||||
void Init();
|
||||
|
||||
atomic_word Tag();
|
||||
AtomicNode *Peek();
|
||||
AtomicNode *Load(atomic_word &tag);
|
||||
|
||||
AtomicNode *Clear(AtomicNode *old, atomic_word tag);
|
||||
|
||||
bool Add(AtomicNode *first, AtomicNode *last, atomic_word tag);
|
||||
AtomicNode* Touch(atomic_word tag);
|
||||
void Reset(AtomicNode *node, atomic_word tag);
|
||||
};
|
||||
|
||||
UNITY_PLATFORM_END_NAMESPACE;
|
||||
@@ -0,0 +1,926 @@
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
# include "os/Win32/WindowsHeaders.h"
|
||||
# include <intrin.h>
|
||||
|
||||
#else
|
||||
|
||||
# define ASM_DMB_ISH "dmb ish\n\t"
|
||||
|
||||
# if defined(__ARM_ARCH_7S__)
|
||||
// this is sufficient for Swift processors
|
||||
# define ASM_REL "dmb ishst\n\t"
|
||||
# else
|
||||
# define ASM_REL "dmb ish\n\t"
|
||||
# endif
|
||||
|
||||
# define ASM_CLREX "clrex\n\t"
|
||||
|
||||
# define ASM_ISB "isb\n\t"
|
||||
# define ASM_LABEL(i) #i ":\n\t"
|
||||
|
||||
#endif
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_relaxed_t)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_release_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
#else
|
||||
__asm__ __volatile__ (ASM_REL : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_acquire_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
#else
|
||||
__asm__ __volatile__ (ASM_DMB_ISH : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_acq_rel_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
#else
|
||||
__asm__ __volatile__ (ASM_DMB_ISH : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
#else
|
||||
__asm__ __volatile__ (ASM_DMB_ISH : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ATOMIC_LOAD(PRE, POST) \
|
||||
atomic_word res; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
PRE \
|
||||
"ldr %0, %1\n\t" \
|
||||
POST \
|
||||
: "=r" (res) \
|
||||
: "m" (*p) \
|
||||
: "memory" \
|
||||
); \
|
||||
return res;
|
||||
|
||||
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return (atomic_word)__iso_volatile_load32((const volatile __int32*)p);
|
||||
#else
|
||||
ATOMIC_LOAD("", "")
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, memory_order_acquire_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
atomic_word res = (atomic_word)__iso_volatile_load32((const volatile __int32*)p);
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
return res;
|
||||
#else
|
||||
ATOMIC_LOAD("", ASM_DMB_ISH)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
atomic_word res = (atomic_word)__iso_volatile_load32((const volatile __int32*)p);
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
return res;
|
||||
#else
|
||||
ATOMIC_LOAD("", ASM_DMB_ISH)
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ATOMIC_STORE(PRE, POST) \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
PRE \
|
||||
"str %1, %0\n\t" \
|
||||
POST \
|
||||
: "=m" (*p) \
|
||||
: "r" (v) \
|
||||
: "memory" \
|
||||
);
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__iso_volatile_store32((volatile __int32*)p, (__int32)v);
|
||||
#else
|
||||
ATOMIC_STORE("", "")
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
__iso_volatile_store32((volatile __int32*)p, (__int32)v);
|
||||
#else
|
||||
ATOMIC_STORE(ASM_REL, "")
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
__iso_volatile_store32((volatile __int32*)p, (__int32)v);
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
#else
|
||||
ATOMIC_STORE(ASM_REL, ASM_DMB_ISH)
|
||||
#endif
|
||||
}
|
||||
|
||||
#define ATOMIC_XCHG(PRE, POST) \
|
||||
atomic_word res; \
|
||||
atomic_word success; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
PRE \
|
||||
ASM_LABEL (0) \
|
||||
"ldrex %2, [%4]\n\t" \
|
||||
"strex %0, %3, [%4]\n\t" \
|
||||
"teq %0, #0\n\t" \
|
||||
"bne 0b\n\t" \
|
||||
POST \
|
||||
: "=&r" (success), "+m" (*p), "=&r" (res) \
|
||||
: "r" (v), "r" (p) \
|
||||
: "cc", "memory" \
|
||||
); \
|
||||
return res;
|
||||
|
||||
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return (atomic_word)_InterlockedExchange_nf((long volatile*)p, (long)v);
|
||||
#else
|
||||
ATOMIC_XCHG("", "")
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
// _InterlockedExchange_rel is documented by Microsoft, but it doesn't seem to be defined
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
return (atomic_word)_InterlockedExchange_nf((long volatile*)p, (long)v);
|
||||
#else
|
||||
ATOMIC_XCHG(ASM_REL, "")
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, memory_order_acquire_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return (atomic_word)_InterlockedExchange_acq((long volatile*)p, (long)v);
|
||||
#else
|
||||
ATOMIC_XCHG("", ASM_ISB)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, memory_order_acq_rel_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
return (atomic_word)_InterlockedExchange_acq((long volatile*)p, (long)v);
|
||||
#else
|
||||
ATOMIC_XCHG(ASM_REL, ASM_ISB)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
// _InterlockedExchange_rel is documented by Microsoft, but it doesn't seem to be defined
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
atomic_word res = (atomic_word)_InterlockedExchange_nf((long volatile*)p, (long)v);
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
return res;
|
||||
#else
|
||||
ATOMIC_XCHG(ASM_REL, ASM_DMB_ISH)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !defined(_MSC_VER)
|
||||
|
||||
// atomic_compare_exchange_weak_explicit: can fail spuriously even if *p == *oldval
|
||||
|
||||
#define ATOMIC_CMP_XCHG(PRE, POST) \
|
||||
atomic_word res; \
|
||||
atomic_word success = 0; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
PRE \
|
||||
"ldrex %2, [%4]\n\t" \
|
||||
"teq %2, %5\n\t" \
|
||||
"it eq\n\t" \
|
||||
"strexeq %0, %3, [%4]\n\t" \
|
||||
POST \
|
||||
: "+r" (success), "+m" (*p), "=&r" (res) \
|
||||
: "r" (newval), "r" (p), "r" (*oldval) \
|
||||
: "cc", "memory" \
|
||||
); \
|
||||
*oldval = res; \
|
||||
return success;
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_relaxed_t, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("", "")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG(ASM_REL, "")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("", "teq %0, #0\n\tbne 1f\n\t" ASM_ISB ASM_LABEL(1))
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG(ASM_REL, "teq %0, #0\n\tbne 1f\n\t" ASM_ISB ASM_LABEL(1))
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG(ASM_REL, "teq %0, #0\n\tbne 1f\n\t" ASM_DMB_ISH ASM_LABEL(1))
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_release_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG(ASM_REL, "")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_acquire_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("", ASM_ISB)
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_acq_rel_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG(ASM_REL, ASM_ISB)
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
ATOMIC_CMP_XCHG(ASM_REL, ASM_DMB_ISH)
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// atomic_compare_exchange_strong_explicit: does loop and only returns false if *p != *oldval
|
||||
|
||||
#undef ATOMIC_CMP_XCHG
|
||||
#define ATOMIC_CMP_XCHG(PRE, POST) \
|
||||
atomic_word res; \
|
||||
atomic_word success = 0; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
PRE \
|
||||
ASM_LABEL (0) \
|
||||
"ldrex %2, [%4]\n\t" \
|
||||
"teq %2, %5\n\t" \
|
||||
"bne 1f\n\t" \
|
||||
"strex %0, %3, [%4]\n\t" \
|
||||
"teq %0, #0\n\t" \
|
||||
"bne 0b\n\t" \
|
||||
POST \
|
||||
: "=&r" (success), "+m" (*p), "=&r" (res) \
|
||||
: "r" (newval), "r" (p), "r" (*oldval) \
|
||||
: "cc", "memory" \
|
||||
); \
|
||||
*oldval = res; \
|
||||
return success;
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_relaxed_t, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
long tmp = _InterlockedCompareExchange_nf((long volatile*)p, (long)newval, (long)*oldval);
|
||||
return *oldval == tmp ? true : (*oldval = tmp, false);
|
||||
#else
|
||||
ATOMIC_CMP_XCHG("", ASM_LABEL(1) ASM_CLREX)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_release_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
long tmp = _InterlockedCompareExchange_rel((long volatile*)p, (long)newval, (long)*oldval);
|
||||
return *oldval == tmp ? true : (*oldval = tmp, false);
|
||||
#else
|
||||
ATOMIC_CMP_XCHG(ASM_REL, ASM_LABEL(1) ASM_CLREX)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_acquire_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
long tmp = _InterlockedCompareExchange_acq((long volatile*)p, (long)newval, (long)*oldval);
|
||||
return *oldval == tmp ? true : (*oldval = tmp, false);
|
||||
#else
|
||||
ATOMIC_CMP_XCHG("", ASM_LABEL(1) ASM_CLREX ASM_ISB)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_acq_rel_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
long tmp = _InterlockedCompareExchange_acq((long volatile*)p, (long)newval, (long)*oldval);
|
||||
return *oldval == tmp ? true : (*oldval = tmp, false);
|
||||
#else
|
||||
ATOMIC_CMP_XCHG(ASM_REL, ASM_LABEL(1) ASM_CLREX ASM_ISB)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
long tmp = _InterlockedCompareExchange_rel((long volatile*)p, (long)newval, (long)*oldval);
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
return *oldval == tmp ? true : (*oldval = tmp, false);
|
||||
#else
|
||||
ATOMIC_CMP_XCHG(ASM_REL, ASM_LABEL(1) ASM_CLREX ASM_DMB_ISH)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_release, memory_order_release);
|
||||
#else
|
||||
ATOMIC_CMP_XCHG(ASM_REL, ASM_LABEL(1) ASM_CLREX)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_acquire, memory_order_acquire);
|
||||
#else
|
||||
ATOMIC_CMP_XCHG("", ASM_ISB ASM_LABEL(1) ASM_CLREX)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_acq_rel, memory_order_acq_rel);
|
||||
#else
|
||||
ATOMIC_CMP_XCHG(ASM_REL, ASM_ISB ASM_LABEL(1) ASM_CLREX)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_seq_cst, memory_order_seq_cst);
|
||||
#else
|
||||
ATOMIC_CMP_XCHG(ASM_REL, ASM_DMB_ISH ASM_LABEL(1) ASM_CLREX)
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_relaxed_t, memory_order_relaxed_t)
|
||||
{
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_relaxed, memory_order_relaxed);
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_relaxed_t)
|
||||
{
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_release, memory_order_relaxed);
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_relaxed_t)
|
||||
{
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_acquire, memory_order_relaxed);
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_relaxed_t)
|
||||
{
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_acq_rel, memory_order_relaxed);
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, memory_order_relaxed_t)
|
||||
{
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_seq_cst, memory_order_relaxed);
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_release_t)
|
||||
{
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_release, memory_order_release);
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_acquire_t)
|
||||
{
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_acquire, memory_order_acquire);
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_acq_rel_t)
|
||||
{
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_acq_rel, memory_order_acq_rel);
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_seq_cst, memory_order_seq_cst);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#define ATOMIC_OP(PRE, OP, POST) \
|
||||
atomic_word res, tmp; \
|
||||
atomic_word success; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
PRE \
|
||||
ASM_LABEL (0) \
|
||||
"ldrex %2, [%5]\n\t" \
|
||||
OP " %3, %2, %4\n\t" \
|
||||
"strex %0, %3, [%5]\n\t" \
|
||||
"teq %0, #0\n\t" \
|
||||
"bne 0b\n\t" \
|
||||
POST \
|
||||
: "=&r" (success), "+m" (*p), "=&r" (res), "=&r" (tmp) \
|
||||
: "Ir" (v), "r" (p) \
|
||||
: "cc", "memory" \
|
||||
); \
|
||||
return res;
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return (atomic_word)_InterlockedExchangeAdd_nf((volatile long*)p, (long)v);
|
||||
#else
|
||||
ATOMIC_OP("", "add", "")
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return (atomic_word)_InterlockedExchangeAdd_rel((volatile long*)p, (long)v);
|
||||
#else
|
||||
ATOMIC_OP(ASM_REL, "add", "")
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, memory_order_acquire_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return (atomic_word)_InterlockedExchangeAdd_acq((volatile long*)p, (long)v);
|
||||
#else
|
||||
ATOMIC_OP("", "add", ASM_ISB)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, memory_order_acq_rel_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
return (atomic_word)_InterlockedExchangeAdd_acq((volatile long*)p, (long)v);
|
||||
#else
|
||||
ATOMIC_OP(ASM_REL, "add", ASM_ISB)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
long oldval = _InterlockedExchangeAdd_rel((volatile long*)p, (long)v);
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
return (atomic_word)oldval;
|
||||
#else
|
||||
ATOMIC_OP(ASM_REL, "add", ASM_DMB_ISH)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return atomic_fetch_add_explicit(p, -v, memory_order_relaxed);
|
||||
#else
|
||||
ATOMIC_OP("", "sub", "")
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return atomic_fetch_add_explicit(p, -v, memory_order_release);
|
||||
#else
|
||||
ATOMIC_OP(ASM_REL, "sub", "")
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, memory_order_acquire_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return atomic_fetch_add_explicit(p, -v, memory_order_acquire);
|
||||
#else
|
||||
ATOMIC_OP("", "sub", ASM_ISB)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, memory_order_acq_rel_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return atomic_fetch_add_explicit(p, -v, memory_order_acq_rel);
|
||||
#else
|
||||
ATOMIC_OP(ASM_REL, "sub", ASM_ISB)
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return atomic_fetch_add_explicit(p, -v, memory_order_seq_cst);
|
||||
#else
|
||||
ATOMIC_OP(ASM_REL, "sub", ASM_DMB_ISH)
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* extensions
|
||||
*/
|
||||
|
||||
static inline void atomic_retain(volatile int* p)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_InterlockedIncrement_nf((volatile long*)p);
|
||||
#else
|
||||
atomic_fetch_add_explicit(p, 1, memory_order_relaxed);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_release(volatile int* p)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
// _interlockedDecrement returns the resulting decremented value
|
||||
bool res = _InterlockedDecrement_rel((volatile long*)p) == 0;
|
||||
if (res)
|
||||
{
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
}
|
||||
#else
|
||||
bool res = atomic_fetch_sub_explicit(p, 1, memory_order_release) == 1;
|
||||
if (res)
|
||||
{
|
||||
atomic_thread_fence(memory_order_acquire);
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* double word
|
||||
*/
|
||||
|
||||
// Note: the only way to get atomic 64-bit memory accesses on ARM is to use ldrexd/strexd with a loop
|
||||
// (ldrd and strd instructions are not guaranteed to appear atomic)
|
||||
|
||||
static inline atomic_word2 atomic_load_explicit(const volatile atomic_word2* p, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
// atomic_word2 r; r.v = __iso_volatile_load64 ((volatile __int64*) p); return r;
|
||||
atomic_word2 r;
|
||||
r.v = _InterlockedCompareExchange64_nf((volatile __int64*)p, (__int64)0, (__int64)0);
|
||||
return r;
|
||||
#else
|
||||
register atomic_word lo __asm__ ("r2");
|
||||
register atomic_word hi __asm__ ("r3");
|
||||
atomic_word success;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
ASM_LABEL(0)
|
||||
"ldrexd\t%1, %2, [%3]\n\t"
|
||||
"strexd\t%0, %1, %2, [%3]\n\t"
|
||||
"teq\t%0, #0\n\t"
|
||||
"bne\t0b\n\t"
|
||||
|
||||
: "=&r" (success), "=&r" (lo), "=&r" (hi)
|
||||
: "r" (p)
|
||||
: "cc", "r2", "r3"
|
||||
);
|
||||
atomic_word2 w;
|
||||
w.lo = lo;
|
||||
w.hi = hi;
|
||||
return w;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word2 atomic_load_explicit(const volatile atomic_word2* p, memory_order_acquire_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
atomic_word2 r;
|
||||
r.v = _InterlockedCompareExchange64_acq((volatile __int64*)p, (__int64)0, (__int64)0);
|
||||
return r;
|
||||
#else
|
||||
register atomic_word lo __asm__ ("r2");
|
||||
register atomic_word hi __asm__ ("r3");
|
||||
atomic_word success;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
ASM_LABEL(0)
|
||||
"ldrexd\t%1, %2, [%3]\n\t"
|
||||
"strexd\t%0, %1, %2, [%3]\n\t"
|
||||
"teq\t%0, #0\n\t"
|
||||
"bne\t0b\n\t"
|
||||
ASM_ISB
|
||||
|
||||
: "=&r" (success), "=&r" (lo), "=&r" (hi)
|
||||
: "r" (p)
|
||||
: "cc", "memory", "r2", "r3"
|
||||
);
|
||||
atomic_word2 w;
|
||||
w.lo = lo;
|
||||
w.hi = hi;
|
||||
return w;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word2* p, atomic_word2 v, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
atomic_word2 w, x;
|
||||
w = v;
|
||||
x = v;
|
||||
do
|
||||
{
|
||||
w.v = _InterlockedCompareExchange64_nf((volatile __int64*)p, x.v, w.v);
|
||||
}
|
||||
while (w.v != x.v);
|
||||
#else
|
||||
register atomic_word l __asm__ ("r2");
|
||||
register atomic_word h __asm__ ("r3");
|
||||
register atomic_word lo __asm__ ("r0") = v.lo;
|
||||
register atomic_word hi __asm__ ("r1") = v.hi;
|
||||
atomic_word success;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
ASM_LABEL(0)
|
||||
"ldrexd\t%2, %3, [%6]\n\t"
|
||||
"strexd\t%0, %4, %5, [%6]\n\t"
|
||||
"teq\t%0, #0\n\t"
|
||||
"bne\t0b\n\t"
|
||||
|
||||
: "=&r" (success), "=m" (*p), "=&r" (l), "=&r" (h)
|
||||
: "r" (lo), "r" (hi), "r" (p)
|
||||
: "cc", "memory", "r2", "r3"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word2* p, atomic_word2 v, memory_order_release_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
atomic_word2 w, x;
|
||||
w = v;
|
||||
x = v;
|
||||
do
|
||||
{
|
||||
w.v = _InterlockedCompareExchange64_rel((volatile __int64*)p, x.v, w.v);
|
||||
}
|
||||
while (w.v != x.v);
|
||||
#else
|
||||
register atomic_word l __asm__ ("r2");
|
||||
register atomic_word h __asm__ ("r3");
|
||||
register atomic_word lo __asm__ ("r0") = v.lo;
|
||||
register atomic_word hi __asm__ ("r1") = v.hi;
|
||||
atomic_word success;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
ASM_REL
|
||||
ASM_LABEL(0)
|
||||
"ldrexd\t%2, %3, [%6]\n\t"
|
||||
"strexd\t%0, %4, %5, [%6]\n\t"
|
||||
"teq\t%0, #0\n\t"
|
||||
"bne\t0b\n\t"
|
||||
|
||||
: "=&r" (success), "=m" (*p), "=&r" (l), "=&r" (h)
|
||||
: "r" (lo), "r" (hi), "r" (p)
|
||||
: "cc", "memory", "r2", "r3"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word2 atomic_exchange_explicit(volatile atomic_word2* p, atomic_word2 val, memory_order_acq_rel_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
atomic_word2 w;
|
||||
w.v = _InterlockedExchange64_acq((__int64 volatile*)p, (__int64)val.v);
|
||||
return w;
|
||||
#else
|
||||
register atomic_word l __asm__ ("r0");
|
||||
register atomic_word h __asm__ ("r1");
|
||||
register atomic_word lo __asm__ ("r2") = val.lo;
|
||||
register atomic_word hi __asm__ ("r3") = val.hi;
|
||||
atomic_word success;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
ASM_REL
|
||||
ASM_LABEL(0)
|
||||
"ldrexd\t%2, %3, [%6]\n\t"
|
||||
"strexd\t%0, %5, %4, [%6]\n\t"
|
||||
"teq\t%0, #0\n\t"
|
||||
"bne\t0b\n\t"
|
||||
ASM_ISB
|
||||
|
||||
: "=&r" (success), "=m" (*p), "=&r" (l), "=&r" (h)
|
||||
: "r" (hi), "r" (lo), "r" (p)
|
||||
: "cc", "memory", "r0", "r1", "r3"
|
||||
);
|
||||
val.lo = l;
|
||||
val.hi = h;
|
||||
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, memory_order_acquire_t, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__int64 tmp = _InterlockedCompareExchange64_acq((volatile __int64*)p, newval.v, oldval->v);
|
||||
return oldval->v == tmp ? true : (oldval->v = tmp, false);
|
||||
#else
|
||||
register atomic_word l __asm__ ("r2");
|
||||
register atomic_word h __asm__ ("r3");
|
||||
register atomic_word lo __asm__ ("r0") = newval.lo;
|
||||
register atomic_word hi __asm__ ("r1") = newval.hi;
|
||||
atomic_word success;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
ASM_LABEL(0)
|
||||
"ldrexd\t%2, %3, [%8]\n\t"
|
||||
"teq\t%3, %5\n\t"
|
||||
"it\t\teq\n\t"
|
||||
"teqeq\t%2, %4\n\t"
|
||||
"bne\t1f\n\t"
|
||||
"strexd\t%0, %6, %7, [%8]\n\t"
|
||||
"teq\t%0, #0\n\t"
|
||||
"bne\t0b\n\t"
|
||||
ASM_ISB
|
||||
ASM_LABEL(1)
|
||||
"clrex\n\t"
|
||||
|
||||
: "=&r" (success), "+m" (*p), "=&r" (l), "=&r" (h)
|
||||
: "r" (oldval->lo), "r" (oldval->hi), "r" (lo), "r" (hi), "r" (p), "0" (1)
|
||||
: "cc", "memory", "r2", "r3"
|
||||
);
|
||||
if (success != 0)
|
||||
{
|
||||
oldval->lo = l;
|
||||
oldval->hi = h;
|
||||
}
|
||||
return success == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, memory_order_release_t, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__int64 tmp = _InterlockedCompareExchange64_rel((volatile __int64*)p, newval.v, oldval->v);
|
||||
return oldval->v == tmp ? true : (oldval->v = tmp, false);
|
||||
#else
|
||||
register atomic_word l __asm__ ("r2");
|
||||
register atomic_word h __asm__ ("r3");
|
||||
register atomic_word lo __asm__ ("r0") = newval.lo;
|
||||
register atomic_word hi __asm__ ("r1") = newval.hi;
|
||||
atomic_word success;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
ASM_REL
|
||||
ASM_LABEL(0)
|
||||
"ldrexd\t%2, %3, [%8]\n\t"
|
||||
"teq\t%3, %5\n\t"
|
||||
"it\t\teq\n\t"
|
||||
"teqeq\t%2, %4\n\t"
|
||||
"bne\t1f\n\t"
|
||||
"strexd\t%0, %6, %7, [%8]\n\t"
|
||||
"teq\t%0, #0\n\t"
|
||||
"bne\t0b\n\t"
|
||||
ASM_LABEL(1)
|
||||
"clrex\n\t"
|
||||
|
||||
: "=&r" (success), "+m" (*p), "=&r" (l), "=&r" (h)
|
||||
: "r" (oldval->lo), "r" (oldval->hi), "r" (lo), "r" (hi), "r" (p), "0" (1)
|
||||
: "cc", "memory", "r2", "r3"
|
||||
);
|
||||
if (success != 0)
|
||||
{
|
||||
oldval->lo = l;
|
||||
oldval->hi = h;
|
||||
}
|
||||
return success == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, memory_order_acq_rel_t, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
__int64 tmp = _InterlockedCompareExchange64_acq((volatile __int64*)p, newval.v, oldval->v);
|
||||
return oldval->v == tmp ? true : (oldval->v = tmp, false);
|
||||
#else
|
||||
register atomic_word l __asm__ ("r2");
|
||||
register atomic_word h __asm__ ("r3");
|
||||
register atomic_word lo __asm__ ("r0") = newval.lo;
|
||||
register atomic_word hi __asm__ ("r1") = newval.hi;
|
||||
atomic_word success;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
ASM_REL
|
||||
ASM_LABEL(0)
|
||||
"ldrexd\t%2, %3, [%8]\n\t"
|
||||
"teq\t%3, %5\n\t"
|
||||
"it\t\teq\n\t"
|
||||
"teqeq\t%2, %4\n\t"
|
||||
"bne\t1f\n\t"
|
||||
"strexd\t%0, %6, %7, [%8]\n\t"
|
||||
"teq\t%0, #0\n\t"
|
||||
"bne\t0b\n\t"
|
||||
ASM_ISB
|
||||
ASM_LABEL(1)
|
||||
"clrex\n\t"
|
||||
|
||||
: "=&r" (success), "+m" (*p), "=&r" (l), "=&r" (h)
|
||||
: "r" (oldval->lo), "r" (oldval->hi), "r" (lo), "r" (hi), "r" (p), "0" (1)
|
||||
: "cc", "memory", "r2", "r3"
|
||||
);
|
||||
if (success != 0)
|
||||
{
|
||||
oldval->lo = l;
|
||||
oldval->hi = h;
|
||||
}
|
||||
return success == 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, memory_order_seq_cst_t, memory_order_relaxed_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
__int64 tmp = _InterlockedCompareExchange64_rel((volatile __int64*)p, newval.v, oldval->v);
|
||||
__dmb(_ARM_BARRIER_ISH);
|
||||
return oldval->v == tmp ? true : (oldval->v = tmp, false);
|
||||
#else
|
||||
register atomic_word l __asm__ ("r2");
|
||||
register atomic_word h __asm__ ("r3");
|
||||
register atomic_word lo __asm__ ("r0") = newval.lo;
|
||||
register atomic_word hi __asm__ ("r1") = newval.hi;
|
||||
atomic_word success;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
ASM_REL
|
||||
ASM_LABEL(0)
|
||||
"ldrexd\t%2, %3, [%8]\n\t"
|
||||
"teq\t%3, %5\n\t"
|
||||
"it\t\teq\n\t"
|
||||
"teqeq\t%2, %4\n\t"
|
||||
"bne\t1f\n\t"
|
||||
"strexd\t%0, %6, %7, [%8]\n\t"
|
||||
"teq\t%0, #0\n\t"
|
||||
"bne\t0b\n\t"
|
||||
ASM_DMB_ISH
|
||||
ASM_LABEL(1)
|
||||
"clrex\n\t"
|
||||
|
||||
: "=&r" (success), "+m" (*p), "=&r" (l), "=&r" (h)
|
||||
: "r" (oldval->lo), "r" (oldval->hi), "r" (lo), "r" (hi), "r" (p), "0" (1)
|
||||
: "cc", "memory", "r2", "r3"
|
||||
);
|
||||
if (success != 0)
|
||||
{
|
||||
oldval->lo = l;
|
||||
oldval->hi = h;
|
||||
}
|
||||
return success == 0;
|
||||
#endif
|
||||
}
|
||||
+654
@@ -0,0 +1,654 @@
|
||||
#define ASM_DMB_ISH "dmb ish\n\t"
|
||||
|
||||
#if defined(__ARM_ARCH_7S__)
|
||||
// this is sufficient for Swift processors
|
||||
# define ASM_REL "dmb ishst\n\t"
|
||||
#else
|
||||
# define ASM_REL "dmb ish\n\t"
|
||||
#endif
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_relaxed_t)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_acquire_t)
|
||||
{
|
||||
__asm__ __volatile__ ("dmb ld\n\t" : : : "memory");
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_release_t)
|
||||
{
|
||||
__asm__ __volatile__ (ASM_REL : : : "memory");
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_acq_rel_t)
|
||||
{
|
||||
__asm__ __volatile__ (ASM_DMB_ISH : : : "memory");
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
__asm__ __volatile__ (ASM_DMB_ISH : : : "memory");
|
||||
}
|
||||
|
||||
#define ATOMIC_LOAD(opc) \
|
||||
atomic_word res; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
opc " %0, %1\n\t" \
|
||||
: "=r" (res) \
|
||||
: "m" (*p) \
|
||||
); \
|
||||
return res;
|
||||
|
||||
/*
|
||||
* int support
|
||||
*/
|
||||
|
||||
static inline int atomic_load_explicit(const volatile int* p, memory_order_relaxed_t)
|
||||
{
|
||||
int res;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"ldr %w0, %w1\n\t"
|
||||
: "=r" (res)
|
||||
: "m" (*p)
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int atomic_load_explicit(const volatile int* p, memory_order_acquire_t)
|
||||
{
|
||||
int res;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"ldar %w0, %w1\n\t"
|
||||
: "=r" (res)
|
||||
: "m" (*p)
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
static inline int atomic_load_explicit(const volatile int* p, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
int res;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"ldar %w0, %w1\n\t"
|
||||
: "=r" (res)
|
||||
: "m" (*p)
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* native word support
|
||||
*/
|
||||
|
||||
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_LOAD("ldr")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, memory_order_acquire_t)
|
||||
{
|
||||
ATOMIC_LOAD("ldar")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
ATOMIC_LOAD("ldar")
|
||||
}
|
||||
|
||||
#define ATOMIC_STORE(opc) \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
opc " %1, %0\n\t" \
|
||||
: "=m" (*p) \
|
||||
: "r" (v) \
|
||||
: "memory" \
|
||||
);
|
||||
|
||||
/*
|
||||
* int support
|
||||
*/
|
||||
|
||||
static inline void atomic_store_explicit(volatile int* p, int v, memory_order_relaxed_t)
|
||||
{
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"str %w1, %w0\n\t"
|
||||
: "=m" (*p)
|
||||
: "r" (v)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile int* p, int v, memory_order_release_t)
|
||||
{
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"stlr %w1, %w0\n\t"
|
||||
: "=m" (*p)
|
||||
: "r" (v)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile int* p, int v, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"stlr %w1, %w0\n\t"
|
||||
: "=m" (*p)
|
||||
: "r" (v)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* native word support
|
||||
*/
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_STORE("str")
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
|
||||
{
|
||||
ATOMIC_STORE("stlr")
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
ATOMIC_STORE("stlr")
|
||||
}
|
||||
|
||||
#define ATOMIC_XCHG(LD, ST) \
|
||||
atomic_word res; \
|
||||
atomic_word success; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"0:\n\t" \
|
||||
LD " %2, [%4]\n\t" \
|
||||
ST " %w0, %3, [%4]\n\t" \
|
||||
"cbnz %w0, 0b\n\t" \
|
||||
: "=&r" (success), "+m" (*p), "=&r" (res) \
|
||||
: "r" (v), "r" (p) \
|
||||
: "memory" \
|
||||
); \
|
||||
return res;
|
||||
|
||||
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_XCHG("ldxr", "stxr")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, memory_order_acquire_t)
|
||||
{
|
||||
ATOMIC_XCHG("ldaxr", "stxr")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
|
||||
{
|
||||
ATOMIC_XCHG("ldxr", "stlxr")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, memory_order_acq_rel_t)
|
||||
{
|
||||
ATOMIC_XCHG("ldaxr", "stlxr")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word v, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
ATOMIC_XCHG("ldaxr", "stlxr")
|
||||
}
|
||||
|
||||
// atomic_compare_exchange_weak_explicit: can fail spuriously even if *p == *oldval
|
||||
|
||||
#define ATOMIC_CMP_XCHG(LD, ST) \
|
||||
atomic_word res; \
|
||||
atomic_word success = 0; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
LD " %2, [%4]\n\t" \
|
||||
"cmp %2, %5\n\t" \
|
||||
"b.ne 1f\n\t" \
|
||||
ST " %w0, %3, [%4]\n" \
|
||||
"1:\n\t" \
|
||||
"clrex\n\t" \
|
||||
: "=&r" (success), "+m" (*p), "=&r" (res) \
|
||||
: "r" (newval), "r" (p), "r" (*oldval) \
|
||||
: "cc", "memory" \
|
||||
); \
|
||||
*oldval = res; \
|
||||
return success == 0;
|
||||
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_relaxed_t, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldxr", "stxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldaxr", "stxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldxr", "stlxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldaxr", "stlxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldaxr", "stlxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_acquire_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldaxr", "stxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_release_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldxr", "stlxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_acq_rel_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldaxr", "stlxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldaxr", "stlxr")
|
||||
}
|
||||
|
||||
// atomic_compare_exchange_strong_explicit: does loop and only returns false if *p != *oldval
|
||||
|
||||
#undef ATOMIC_CMP_XCHG
|
||||
|
||||
#define ATOMIC_CMP_XCHG(LD, ST) \
|
||||
atomic_word res; \
|
||||
atomic_word success = 0; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"0:\n\t" \
|
||||
LD " %2, [%4]\n\t" \
|
||||
"cmp %2, %5\n\t" \
|
||||
"b.ne 1f\n\t" \
|
||||
ST " %w0, %3, [%4]\n" \
|
||||
"cbnz %w0, 0b\n\t" \
|
||||
"1:\n\t" \
|
||||
"clrex\n\t" \
|
||||
: "=&r" (success), "+m" (*p), "=&r" (res) \
|
||||
: "r" (newval), "r" (p), "r" (*oldval) \
|
||||
: "cc", "memory" \
|
||||
); \
|
||||
*oldval = res; \
|
||||
return success == 0;
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_relaxed_t, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldxr", "stxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldaxr", "stxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldxr", "stlxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldaxr", "stlxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldaxr", "stlxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acquire_t, memory_order_acquire_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldaxr", "stxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_release_t, memory_order_release_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldxr", "stlxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_acq_rel_t, memory_order_acq_rel_t)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldaxr", "stlxr")
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word *oldval, atomic_word newval, int /* memory_order_seq_cst_t */, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
ATOMIC_CMP_XCHG("ldaxr", "stlxr")
|
||||
}
|
||||
|
||||
#define ATOMIC_PFIX_int "%w"
|
||||
#define ATOMIC_PFIX_atomic_word "%"
|
||||
#define ATOMIC_PFIX(WORD) ATOMIC_PFIX_##WORD
|
||||
|
||||
#define ATOMIC_OP(WORD, LD, ST, OP) \
|
||||
long long res, tmp; \
|
||||
int success; \
|
||||
__asm__ __volatile__ \
|
||||
( \
|
||||
"0:\n\t" \
|
||||
LD " " ATOMIC_PFIX(WORD) "2, [%5]\n\t" \
|
||||
OP " " ATOMIC_PFIX(WORD) "3, " ATOMIC_PFIX(WORD) "2, " ATOMIC_PFIX(WORD) "4\n\t"\
|
||||
ST " %w0, " ATOMIC_PFIX(WORD) "3, [%5]\n" \
|
||||
"cbnz %w0, 0b\n\t" \
|
||||
: "=&r" (success), "+m" (*p), "=&r" (res), "=&r" (tmp) \
|
||||
: "Ir" ((long long) v), "r" (p) \
|
||||
: "cc", "memory" \
|
||||
); \
|
||||
return (WORD) res;
|
||||
|
||||
static inline int atomic_fetch_add_explicit(volatile int* p, int v, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_OP(int, "ldxr", "stxr", "add")
|
||||
}
|
||||
|
||||
static inline int atomic_fetch_add_explicit(volatile int* p, int v, memory_order_acquire_t)
|
||||
{
|
||||
ATOMIC_OP(int, "ldaxr", "stxr", "add")
|
||||
}
|
||||
|
||||
static inline int atomic_fetch_add_explicit(volatile int* p, int v, memory_order_release_t)
|
||||
{
|
||||
ATOMIC_OP(int, "ldxr", "stlxr", "add")
|
||||
}
|
||||
|
||||
static inline int atomic_fetch_add_explicit(volatile int* p, int v, memory_order_acq_rel_t)
|
||||
{
|
||||
ATOMIC_OP(int, "ldaxr", "stlxr", "add")
|
||||
}
|
||||
|
||||
static inline int atomic_fetch_add_explicit(volatile int* p, int v, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
ATOMIC_OP(int, "ldaxr", "stlxr", "add")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_OP(atomic_word, "ldxr", "stxr", "add")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, memory_order_acquire_t)
|
||||
{
|
||||
ATOMIC_OP(atomic_word, "ldaxr", "stxr", "add")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
|
||||
{
|
||||
ATOMIC_OP(atomic_word, "ldxr", "stlxr", "add")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, memory_order_acq_rel_t)
|
||||
{
|
||||
ATOMIC_OP(atomic_word, "ldaxr", "stlxr", "add")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word* p, atomic_word v, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
ATOMIC_OP(atomic_word, "ldaxr", "stlxr", "add")
|
||||
}
|
||||
|
||||
static inline int atomic_fetch_sub_explicit(volatile int* p, int v, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_OP(int, "ldxr", "stxr", "sub")
|
||||
}
|
||||
|
||||
static inline int atomic_fetch_sub_explicit(volatile int* p, int v, memory_order_acquire_t)
|
||||
{
|
||||
ATOMIC_OP(int, "ldaxr", "stxr", "sub")
|
||||
}
|
||||
|
||||
static inline int atomic_fetch_sub_explicit(volatile int* p, int v, memory_order_release_t)
|
||||
{
|
||||
ATOMIC_OP(int, "ldxr", "stlxr", "sub")
|
||||
}
|
||||
|
||||
static inline int atomic_fetch_sub_explicit(volatile int* p, int v, memory_order_acq_rel_t)
|
||||
{
|
||||
ATOMIC_OP(int, "ldaxr", "stlxr", "sub")
|
||||
}
|
||||
|
||||
static inline int atomic_fetch_sub_explicit(volatile int* p, int v, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
ATOMIC_OP(int, "ldaxr", "stlxr", "sub")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
|
||||
{
|
||||
ATOMIC_OP(atomic_word, "ldxr", "stxr", "sub")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, memory_order_acquire_t)
|
||||
{
|
||||
ATOMIC_OP(atomic_word, "ldaxr", "stxr", "sub")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
|
||||
{
|
||||
ATOMIC_OP(atomic_word, "ldxr", "stlxr", "sub")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, memory_order_acq_rel_t)
|
||||
{
|
||||
ATOMIC_OP(atomic_word, "ldaxr", "stlxr", "sub")
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word* p, atomic_word v, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
ATOMIC_OP(atomic_word, "ldaxr", "stlxr", "sub")
|
||||
}
|
||||
|
||||
/*
|
||||
* extensions
|
||||
*/
|
||||
|
||||
static inline void atomic_retain(volatile int* p)
|
||||
{
|
||||
atomic_fetch_add_explicit(p, 1, memory_order_relaxed);
|
||||
}
|
||||
|
||||
static inline bool atomic_release(volatile int* p)
|
||||
{
|
||||
bool res = atomic_fetch_sub_explicit(p, 1, memory_order_release) == 1;
|
||||
if (res)
|
||||
{
|
||||
atomic_thread_fence(memory_order_acquire);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* double word
|
||||
*/
|
||||
|
||||
// Note: the only way to get atomic 128-bit memory accesses on ARM64 is to use ldxp/stxp with a loop
|
||||
// (ldxp and stxp instructions are not guaranteed to appear atomic)
|
||||
|
||||
static inline atomic_word2 atomic_load_explicit(const volatile atomic_word2* p, memory_order_relaxed_t)
|
||||
{
|
||||
atomic_word2 v;
|
||||
atomic_word success;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"0:\n\t"
|
||||
"ldxp\t%1, %2, [%3]\n\t"
|
||||
"stxp\t%w0, %1, %2, [%3]\n\t"
|
||||
"cbnz\t%w0, 0b\n\t"
|
||||
|
||||
: "=&r" (success), "=&r" (v.lo), "=&r" (v.hi)
|
||||
: "r" (p)
|
||||
);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline atomic_word2 atomic_load_explicit(const volatile atomic_word2* p, memory_order_acquire_t)
|
||||
{
|
||||
atomic_word2 v;
|
||||
atomic_word success;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"0:\n\t"
|
||||
"ldaxp\t%1, %2, [%3]\n\t"
|
||||
"stxp\t%w0, %1, %2, [%3]\n\t"
|
||||
"cbnz\t%w0, 0b\n\t"
|
||||
|
||||
: "=&r" (success), "=&r" (v.lo), "=&r" (v.hi)
|
||||
: "r" (p)
|
||||
);
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word2* p, atomic_word2 v, memory_order_relaxed_t)
|
||||
{
|
||||
atomic_word lo;
|
||||
atomic_word hi;
|
||||
atomic_word success;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"0:\n\t"
|
||||
"ldxp\t%2, %3, [%6]\n\t"
|
||||
"stxp\t%w0, %4, %5, [%6]\n\t"
|
||||
"cbnz\t%w0, 0b\n\t"
|
||||
|
||||
: "=&r" (success), "=m" (*p), "=&r" (lo), "=&r" (hi)
|
||||
: "r" (v.lo), "r" (v.hi), "r" (p)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word2* p, atomic_word2 v, memory_order_release_t)
|
||||
{
|
||||
atomic_word lo;
|
||||
atomic_word hi;
|
||||
atomic_word success;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"0:\n\t"
|
||||
"ldxp\t%2, %3, [%6]\n\t"
|
||||
"stlxp\t%w0, %4, %5, [%6]\n\t"
|
||||
"cbnz\t%w0, 0b\n\t"
|
||||
|
||||
: "=&r" (success), "=m" (*p), "=&r" (lo), "=&r" (hi)
|
||||
: "r" (v.lo), "r" (v.hi), "r" (p)
|
||||
: "memory"
|
||||
);
|
||||
}
|
||||
|
||||
static inline atomic_word2 atomic_exchange_explicit(volatile atomic_word2* p, atomic_word2 val, memory_order_acq_rel_t)
|
||||
{
|
||||
atomic_word2 oldval;
|
||||
atomic_word success;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"0:\n\t"
|
||||
"ldaxp\t%2, %3, [%6]\n\t"
|
||||
"stlxp\t%w0, %5, %4, [%6]\n\t"
|
||||
"cbnz\t%w0, 0b\n\t"
|
||||
|
||||
: "=&r" (success), "+m" (*p), "=&r" (oldval.lo), "=&r" (oldval.hi)
|
||||
: "r" (val.hi), "r" (val.lo), "r" (p)
|
||||
: "memory"
|
||||
);
|
||||
|
||||
return oldval;
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, memory_order_acquire_t, memory_order_relaxed_t)
|
||||
{
|
||||
atomic_word lo = oldval->lo;
|
||||
atomic_word hi = oldval->hi;
|
||||
atomic_word success;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"0:\n\t"
|
||||
"ldaxp\t%2, %3, [%8]\n\t"
|
||||
"cmp\t%3, %5\n\t"
|
||||
"b.ne\t1f\n\t"
|
||||
"cmp\t%2, %4\n\t"
|
||||
"b.ne\t1f\n\t"
|
||||
"stxp\t%w0, %6, %7, [%8]\n\t"
|
||||
"cbnz\t%w0, 0b\n\t"
|
||||
"1:\n\t"
|
||||
"clrex\n\t"
|
||||
|
||||
: "=&r" (success), "+m" (*p), "=&r" (oldval->lo), "=&r" (oldval->hi)
|
||||
: "r" (lo), "r" (hi), "r" (newval.lo), "r" (newval.hi), "r" (p), "0" (1)
|
||||
: "cc", "memory"
|
||||
);
|
||||
|
||||
return success == 0;
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, memory_order_release_t, memory_order_relaxed_t)
|
||||
{
|
||||
atomic_word lo = oldval->lo;
|
||||
atomic_word hi = oldval->hi;
|
||||
atomic_word success;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"0:\n\t"
|
||||
"ldxp\t%2, %3, [%8]\n\t"
|
||||
"cmp\t%3, %5\n\t"
|
||||
"b.ne\t1f\n\t"
|
||||
"cmp\t%2, %4\n\t"
|
||||
"b.ne\t1f\n\t"
|
||||
"stlxp\t%w0, %6, %7, [%8]\n\t"
|
||||
"cbnz\t%w0, 0b\n\t"
|
||||
"1:\n\t"
|
||||
"clrex\n\t"
|
||||
|
||||
: "=&r" (success), "+m" (*p), "=&r" (oldval->lo), "=&r" (oldval->hi)
|
||||
: "r" (lo), "r" (hi), "r" (newval.lo), "r" (newval.hi), "r" (p), "0" (1)
|
||||
: "cc", "memory"
|
||||
);
|
||||
|
||||
return success == 0;
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, int /*memory_order_acq_rel_t*/, memory_order_relaxed_t)
|
||||
{
|
||||
atomic_word lo = oldval->lo;
|
||||
atomic_word hi = oldval->hi;
|
||||
atomic_word success;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"0:\n\t"
|
||||
"ldaxp\t%2, %3, [%8]\n\t"
|
||||
"cmp\t%3, %5\n\t"
|
||||
"b.ne\t1f\n\t"
|
||||
"cmp\t%2, %4\n\t"
|
||||
"b.ne\t1f\n\t"
|
||||
"stlxp\t%w0, %6, %7, [%8]\n\t"
|
||||
"cbnz\t%w0, 0b\n\t"
|
||||
"1:\n\t"
|
||||
"clrex\n\t"
|
||||
|
||||
: "=&r" (success), "+m" (*p), "=&r" (oldval->lo), "=&r" (oldval->hi)
|
||||
: "r" (lo), "r" (hi), "r" (newval.lo), "r" (newval.hi), "r" (p), "0" (1)
|
||||
: "cc", "memory"
|
||||
);
|
||||
|
||||
return success == 0;
|
||||
}
|
||||
+217
@@ -0,0 +1,217 @@
|
||||
#if __cplusplus > 199711L
|
||||
#define CompileTimeAssert(condition, message) static_assert(condition, message)
|
||||
#else
|
||||
#define CompileTimeAssert(condition, message)
|
||||
#endif
|
||||
|
||||
static inline void atomic_pause()
|
||||
{
|
||||
#if defined(__i386__) || defined(__x86_64__)
|
||||
__asm__ __volatile__ ("pause");
|
||||
#elif defined(__arm__) || defined(__arm64__)
|
||||
#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__)
|
||||
// YIELD instruction is available only for ARMv6K and above.
|
||||
// http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0473j/dom1361289926796.html
|
||||
// Thus we do nothing here.
|
||||
#else
|
||||
__asm__ __volatile__("yield" : : : "memory");
|
||||
#endif
|
||||
#else
|
||||
#error untested architecture
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef UNITY_ATOMIC_FORCE_LOCKFREE_IMPLEMENTATION
|
||||
# define UNITY_ATOMIC_FORCE_LOCKFREE_IMPLEMENTATION 1
|
||||
#endif
|
||||
|
||||
namespace detail
|
||||
{
|
||||
#if UNITY_ATOMIC_USE_CLANG_ATOMICS && UNITY_ATOMIC_USE_GCC_ATOMICS
|
||||
# error Cannot use both Clang and GCC atomic built-ins
|
||||
#elif UNITY_ATOMIC_USE_CLANG_ATOMICS
|
||||
# if !__has_feature(c_atomic) && !__has_extension(c_atomic)
|
||||
# error "missing atomic built-in functions"
|
||||
# endif
|
||||
# define INTERNAL_UNITY_ATOMIC_THREAD_FENCE(memorder) __c11_atomic_thread_fence(memorder)
|
||||
# define INTERNAL_UNITY_ATOMIC_LOAD(ptr, memorder) __c11_atomic_load(ptr, memorder)
|
||||
# define INTERNAL_UNITY_ATOMIC_STORE(ptr, value, memorder) __c11_atomic_store(ptr, value, memorder)
|
||||
# define INTERNAL_UNITY_ATOMIC_EXCHANGE(ptr, value, memorder) __c11_atomic_exchange(ptr, value, memorder)
|
||||
# define INTERNAL_UNITY_ATOMIC_COMPARE_EXCHANGE_STRONG(ptr, oldval, newval, success, fail) __c11_atomic_compare_exchange_strong(ptr, oldval, newval, success, fail)
|
||||
# define INTERNAL_UNITY_ATOMIC_COMPARE_EXCHANGE_WEAK(ptr, oldval, newval, success, fail) __c11_atomic_compare_exchange_weak(ptr, oldval, newval, success, fail)
|
||||
# define INTERNAL_UNITY_ATOMIC_FETCH_ADD(ptr, value, memorder) __c11_atomic_fetch_add(ptr, value, memorder)
|
||||
# define INTERNAL_UNITY_ATOMIC_FETCH_SUB(ptr, value, memorder) __c11_atomic_fetch_sub(ptr, value, memorder)
|
||||
# define INTERNAL_UNITY_ATOMIC_TYPE(type) _Atomic(type)
|
||||
# define INTERNAL_UNITY_ATOMIC_IS_LOCK_FREE(type) __c11_atomic_is_lock_free(sizeof(type))
|
||||
#elif UNITY_ATOMIC_USE_GCC_ATOMICS
|
||||
# if (__GNUC__ < 4) || (__GNUC__ == 4 && __GNUC_MINOR__ < 7)
|
||||
# error "__atomic built-in functions not supported on GCC versions older than 4.7"
|
||||
# endif
|
||||
# if UNITY_ATOMIC_FORCE_LOCKFREE_IMPLEMENTATION
|
||||
# if __GCC_ATOMIC_INT_LOCK_FREE + 0 != 2 || __GCC_ATOMIC_LLONG_LOCK_FREE + 0 != 2
|
||||
# error "atomic ops are not lock-free for some required data types"
|
||||
# endif
|
||||
# endif
|
||||
# define INTERNAL_UNITY_ATOMIC_THREAD_FENCE(memorder) __atomic_thread_fence(memorder)
|
||||
# define INTERNAL_UNITY_ATOMIC_LOAD(ptr, memorder) __atomic_load_n(ptr, memorder)
|
||||
# define INTERNAL_UNITY_ATOMIC_STORE(ptr, value, memorder) __atomic_store_n(ptr, value, memorder)
|
||||
# define INTERNAL_UNITY_ATOMIC_EXCHANGE(ptr, value, memorder) __atomic_exchange_n(ptr, value, memorder)
|
||||
# define INTERNAL_UNITY_ATOMIC_COMPARE_EXCHANGE_STRONG(ptr, oldval, newval, success, fail) __atomic_compare_exchange_n(ptr, oldval, newval, false, success, fail)
|
||||
# define INTERNAL_UNITY_ATOMIC_COMPARE_EXCHANGE_WEAK(ptr, oldval, newval, success, fail) __atomic_compare_exchange_n(ptr, oldval, newval, true, success, fail)
|
||||
# define INTERNAL_UNITY_ATOMIC_FETCH_ADD(ptr, value, memorder) __atomic_fetch_add(ptr, value, memorder)
|
||||
# define INTERNAL_UNITY_ATOMIC_FETCH_SUB(ptr, value, memorder) __atomic_fetch_sub(ptr, value, memorder)
|
||||
# define INTERNAL_UNITY_ATOMIC_TYPE(type) type
|
||||
# if __GNUC__ >= 5
|
||||
// GCC pre-5 did not allow __atomic_always_lock_free in static expressions such as CompileTimeAssert
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=62024
|
||||
# define INTERNAL_UNITY_ATOMIC_IS_LOCK_FREE(type) __atomic_always_lock_free(sizeof(type), 0)
|
||||
# else
|
||||
# define INTERNAL_UNITY_ATOMIC_IS_LOCK_FREE(type) true
|
||||
# endif
|
||||
#else
|
||||
# error One of UNITY_ATOMIC_USE_CLANG_ATOMICS or UNITY_ATOMIC_USE_GCC_ATOMICS must be defined to 1
|
||||
#endif
|
||||
|
||||
inline int MemOrder(memory_order_relaxed_t) { return __ATOMIC_RELAXED; }
|
||||
inline int MemOrder(memory_order_release_t) { return __ATOMIC_RELEASE; }
|
||||
inline int MemOrder(memory_order_acquire_t) { return __ATOMIC_ACQUIRE; }
|
||||
inline int MemOrder(memory_order_acq_rel_t) { return __ATOMIC_ACQ_REL; }
|
||||
inline int MemOrder(memory_order_seq_cst_t) { return __ATOMIC_SEQ_CST; }
|
||||
int MemOrder(...); // generate link error on unsupported mem order types
|
||||
|
||||
#define INTERNAL_UNITY_ATOMIC_TYPEDEF(nonatomic, atomic) \
|
||||
typedef INTERNAL_UNITY_ATOMIC_TYPE(nonatomic) atomic; \
|
||||
CompileTimeAssert(!UNITY_ATOMIC_FORCE_LOCKFREE_IMPLEMENTATION || INTERNAL_UNITY_ATOMIC_IS_LOCK_FREE(atomic), #atomic " is not lock-free on this platform")
|
||||
|
||||
INTERNAL_UNITY_ATOMIC_TYPEDEF(non_atomic_word, native_atomic_word);
|
||||
INTERNAL_UNITY_ATOMIC_TYPEDEF(non_atomic_word2, native_atomic_word2);
|
||||
INTERNAL_UNITY_ATOMIC_TYPEDEF(int, native_atomic_int);
|
||||
|
||||
#if UNITY_ATOMIC_FORCE_LOCKFREE_IMPLEMENTATION
|
||||
CompileTimeAssert(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 + 0, "requires 32bit CAS");
|
||||
CompileTimeAssert(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 + 0, "requires 64bit CAS");
|
||||
# if __SIZEOF_POINTER__ == 8
|
||||
CompileTimeAssert(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 + 0, "requires 128bit CAS");
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#undef INTERNAL_UNITY_ATOMIC_TYPEDEF
|
||||
|
||||
inline native_atomic_word* AtomicPtr(atomic_word* p) { return reinterpret_cast<native_atomic_word*>(p); }
|
||||
inline volatile native_atomic_word* AtomicPtr(volatile atomic_word* p) { return reinterpret_cast<volatile native_atomic_word*>(p); }
|
||||
|
||||
inline native_atomic_word2* AtomicPtr(atomic_word2* p) { return reinterpret_cast<native_atomic_word2*>(&p->v); }
|
||||
inline volatile native_atomic_word2* AtomicPtr(volatile atomic_word2* p) { return reinterpret_cast<volatile native_atomic_word2*>(&p->v); }
|
||||
|
||||
inline non_atomic_word* NonAtomicPtr(atomic_word* v) { return v; }
|
||||
// same as above: inline non_atomic_word* NonAtomicPtr(non_atomic_word* v) { return v; }
|
||||
inline non_atomic_word2* NonAtomicPtr(atomic_word2* v) { return &v->v; }
|
||||
inline non_atomic_word2* NonAtomicPtr(non_atomic_word2* v) { return v; }
|
||||
|
||||
inline non_atomic_word NonAtomicValue(atomic_word v) { return v; }
|
||||
// same as above: inline non_atomic_word NonAtomicValue(non_atomic_word v) { return v; }
|
||||
inline non_atomic_word2 NonAtomicValue(atomic_word2 v) { return v.v; }
|
||||
inline non_atomic_word2 NonAtomicValue(non_atomic_word2 v) { return v; }
|
||||
|
||||
inline atomic_word UnityAtomicValue(non_atomic_word v) { return v; }
|
||||
inline atomic_word2 UnityAtomicValue(non_atomic_word2 v) { atomic_word2 r; r.v = v; return r; }
|
||||
|
||||
#ifdef UNITY_ATOMIC_INT_OVERLOAD
|
||||
inline native_atomic_int* AtomicPtr(int* p) { return reinterpret_cast<native_atomic_int*>(p); }
|
||||
inline volatile native_atomic_int* AtomicPtr(volatile int* p) { return reinterpret_cast<volatile native_atomic_int*>(p); }
|
||||
inline int* NonAtomicPtr(int* v) { return v; }
|
||||
inline int NonAtomicValue(int v) { return v; }
|
||||
inline int UnityAtomicValue(int v) { return v; }
|
||||
#endif
|
||||
|
||||
template<typename T> struct Identity { typedef T type; };
|
||||
} // namespace detail
|
||||
|
||||
template<typename MemOrder>
|
||||
static inline void atomic_thread_fence(MemOrder memOrder)
|
||||
{
|
||||
INTERNAL_UNITY_ATOMIC_THREAD_FENCE(detail::MemOrder(memOrder));
|
||||
}
|
||||
|
||||
template<typename T, typename MemOrder>
|
||||
static inline T atomic_load_explicit(const volatile T* p, MemOrder memOrder)
|
||||
{
|
||||
return detail::UnityAtomicValue(INTERNAL_UNITY_ATOMIC_LOAD(detail::AtomicPtr(const_cast<T*>(p)), detail::MemOrder(memOrder)));
|
||||
}
|
||||
|
||||
template<typename T, typename MemOrder>
|
||||
static inline void atomic_store_explicit(volatile T* p, typename detail::Identity<T>::type v, MemOrder memOrder)
|
||||
{
|
||||
INTERNAL_UNITY_ATOMIC_STORE(detail::AtomicPtr(p), detail::NonAtomicValue(v), detail::MemOrder(memOrder));
|
||||
}
|
||||
|
||||
template<typename T, typename MemOrder>
|
||||
static inline T atomic_exchange_explicit(volatile T* p, typename detail::Identity<T>::type v, MemOrder memOrder)
|
||||
{
|
||||
return detail::UnityAtomicValue(INTERNAL_UNITY_ATOMIC_EXCHANGE(detail::AtomicPtr(p), detail::NonAtomicValue(v), detail::MemOrder(memOrder)));
|
||||
}
|
||||
|
||||
template<typename T, typename MemOrderSuccess, typename MemOrderFail>
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile T* p, T* oldval, typename detail::Identity<T>::type newval,
|
||||
MemOrderSuccess memOrderSuccess, MemOrderFail memOrderFail)
|
||||
{
|
||||
return INTERNAL_UNITY_ATOMIC_COMPARE_EXCHANGE_WEAK(detail::AtomicPtr(p), detail::NonAtomicPtr(oldval), detail::NonAtomicValue(newval),
|
||||
detail::MemOrder(memOrderSuccess), detail::MemOrder(memOrderFail));
|
||||
}
|
||||
|
||||
template<typename T, typename MemOrderSuccess, typename MemOrderFail>
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile T* p, T* oldval, typename detail::Identity<T>::type newval,
|
||||
MemOrderSuccess memOrderSuccess, MemOrderFail memOrderFail)
|
||||
{
|
||||
return INTERNAL_UNITY_ATOMIC_COMPARE_EXCHANGE_STRONG(detail::AtomicPtr(p), detail::NonAtomicPtr(oldval), detail::NonAtomicValue(newval),
|
||||
detail::MemOrder(memOrderSuccess), detail::MemOrder(memOrderFail));
|
||||
}
|
||||
|
||||
template<typename T, typename MemOrder>
|
||||
static inline T atomic_fetch_add_explicit(volatile T* p, typename detail::Identity<T>::type v, MemOrder memOrder)
|
||||
{
|
||||
return detail::UnityAtomicValue(INTERNAL_UNITY_ATOMIC_FETCH_ADD(detail::AtomicPtr(p), detail::NonAtomicValue(v), detail::MemOrder(memOrder)));
|
||||
}
|
||||
|
||||
template<typename T, typename MemOrder>
|
||||
static inline T atomic_fetch_sub_explicit(volatile T* p, typename detail::Identity<T>::type v, MemOrder memOrder)
|
||||
{
|
||||
return detail::UnityAtomicValue(INTERNAL_UNITY_ATOMIC_FETCH_SUB(detail::AtomicPtr(p), detail::NonAtomicValue(v), detail::MemOrder(memOrder)));
|
||||
}
|
||||
|
||||
/*
|
||||
* extensions
|
||||
*/
|
||||
static inline void atomic_retain(volatile int* p)
|
||||
{
|
||||
atomic_fetch_add_explicit(p, 1, memory_order_relaxed);
|
||||
}
|
||||
|
||||
static inline bool atomic_release(volatile int* p)
|
||||
{
|
||||
// Both paths here should be correct on any platform
|
||||
// On architectures where read-modify-write with memory_order_acq_rel is more expensive than memory_order_release
|
||||
// the idea is to use a global memory_order_acquire fence instead, but only when the reference count drops to 0.
|
||||
// Only then the acquire/release synchronization is needed to make sure everything prior to atomic_release happens before running a d'tor.
|
||||
#if defined(__arm__) || defined(__arm64__)
|
||||
bool res = atomic_fetch_sub_explicit(p, 1, memory_order_release) == 1;
|
||||
if (res)
|
||||
{
|
||||
atomic_thread_fence(memory_order_acquire);
|
||||
}
|
||||
return res;
|
||||
#else
|
||||
return atomic_fetch_sub_explicit(p, 1, memory_order_acq_rel) == 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef INTERNAL_UNITY_ATOMIC_THREAD_FENCE
|
||||
#undef INTERNAL_UNITY_ATOMIC_LOAD
|
||||
#undef INTERNAL_UNITY_ATOMIC_STORE
|
||||
#undef INTERNAL_UNITY_ATOMIC_EXCHANGE
|
||||
#undef INTERNAL_UNITY_ATOMIC_COMPARE_EXCHANGE_STRONG
|
||||
#undef INTERNAL_UNITY_ATOMIC_COMPARE_EXCHANGE_WEAK
|
||||
#undef INTERNAL_UNITY_ATOMIC_FETCH_ADD
|
||||
#undef INTERNAL_UNITY_ATOMIC_FETCH_SUB
|
||||
#undef INTERNAL_UNITY_ATOMIC_TYPE
|
||||
#undef INTERNAL_UNITY_ATOMIC_IS_LOCK_FREE
|
||||
+329
@@ -0,0 +1,329 @@
|
||||
#if defined(_MSC_VER)
|
||||
# include "os/Win32/WindowsHeaders.h"
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(__SSE2__)
|
||||
# include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_relaxed_t)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_release_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
__asm__ __volatile__ ("" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_acquire_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
__asm__ __volatile__ ("" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_acq_rel_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
__asm__ __volatile__ ("" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
#if defined(__SSE2__)
|
||||
_mm_mfence();
|
||||
#elif defined(_MSC_VER)
|
||||
volatile LONGLONG tmp;
|
||||
_InterlockedOr64(&tmp, 0);
|
||||
#else
|
||||
__asm__ __volatile__ ("lock orl #0, 0(%%esp)" ::: "cc", "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* int support
|
||||
*/
|
||||
|
||||
static inline atomic_word atomic_load_explicit(const volatile int* p, memory_order_relaxed_t)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
static inline int atomic_load_explicit(const volatile int* p, int)
|
||||
{
|
||||
int v;
|
||||
#if defined(_MSC_VER)
|
||||
v = *p;
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
__asm__ __volatile__ ("movl %1, %0" : "=r" (v) : "m" (*p) : "memory");
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile int* p, int v, memory_order_relaxed_t)
|
||||
{
|
||||
*p = v;
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile int* p, int v, memory_order_release_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_ReadWriteBarrier();
|
||||
*p = v;
|
||||
#else
|
||||
__asm__ __volatile__ ("movl %1, %0" : "=m" (*p) : "r" (v) : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile int* p, int val, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_InterlockedExchange((volatile LONG*)p, (LONG)val);
|
||||
#else
|
||||
// lock prefix is implicit
|
||||
__asm__ __volatile__
|
||||
(
|
||||
/*lock*/ "xchgl %1, %0"
|
||||
|
||||
: "+m" (*p), "+r" (val)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* native word support
|
||||
*/
|
||||
|
||||
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, memory_order_relaxed_t)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, int)
|
||||
{
|
||||
atomic_word v;
|
||||
#if defined(_MSC_VER)
|
||||
v = *p;
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
__asm__ __volatile__ ("movq %1, %0" : "=r" (v) : "m" (*p) : "memory");
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
|
||||
{
|
||||
*p = v;
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_ReadWriteBarrier();
|
||||
*p = v;
|
||||
#else
|
||||
__asm__ __volatile__ ("movq %1, %0" : "=m" (*p) : "r" (v) : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word val, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_InterlockedExchange64((volatile LONGLONG*)p, (LONGLONG)val);
|
||||
#else
|
||||
// lock prefix is implicit
|
||||
__asm__ __volatile__
|
||||
(
|
||||
/*lock*/ "xchgq %1, %0"
|
||||
: "+m" (*p), "+r" (val)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word val, int)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return (atomic_word)_InterlockedExchange64((volatile LONGLONG*)p, (LONGLONG)val);
|
||||
#else
|
||||
// lock prefix is implicit
|
||||
__asm__ __volatile__
|
||||
(
|
||||
/*lock*/ "xchgq %1, %0"
|
||||
: "+m" (*p), "+r" (val)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word* oldval, atomic_word newval, int, int)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
atomic_word tmp = (atomic_word)_InterlockedCompareExchange64((volatile LONGLONG*)p, (LONGLONG)newval, (LONGLONG)*oldval);
|
||||
return *oldval == tmp ? true : (*oldval = tmp, false);
|
||||
#else
|
||||
char res;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"lock cmpxchgq %3, %0\n\t"
|
||||
"setz %b1"
|
||||
: "+m" (*p), "=q" (res), "+a" (*oldval)
|
||||
: "r" (newval)
|
||||
: "cc", "memory"
|
||||
);
|
||||
return res != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word* oldval, atomic_word newval, int, int)
|
||||
{
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_seq_cst, memory_order_seq_cst);
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile int *p, int val, int)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return _InterlockedExchangeAdd((LONG volatile*)p, (LONG)val);
|
||||
#else
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"lock xaddl\t%1, %0"
|
||||
: "+m" (*p), "+r" (val)
|
||||
:
|
||||
: "cc", "memory"
|
||||
);
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word *p, atomic_word val, int)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return _InterlockedExchangeAdd64((LONGLONG volatile*)p, (LONGLONG)val);
|
||||
#else
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"lock xaddq %1, %0"
|
||||
: "+m" (*p), "+r" (val)
|
||||
:
|
||||
: "cc", "memory"
|
||||
);
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile int *p, int val, int mo)
|
||||
{
|
||||
return atomic_fetch_add_explicit(p, -val, mo);
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word *p, atomic_word val, int mo)
|
||||
{
|
||||
return atomic_fetch_add_explicit(p, -val, mo);
|
||||
}
|
||||
|
||||
/*
|
||||
* extensions
|
||||
*/
|
||||
|
||||
static inline void atomic_retain(volatile int *p)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_InterlockedIncrement((LONG volatile*)p);
|
||||
#else
|
||||
__asm__ (
|
||||
"lock incl %0\n\t"
|
||||
: "+m" (*p)
|
||||
:
|
||||
: "cc", "memory"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_release(volatile int *p)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return _InterlockedDecrement((LONG volatile*)p) == 0;
|
||||
#else
|
||||
bool res;
|
||||
__asm__ (
|
||||
"lock decl %0\n\t"
|
||||
"setz %b1"
|
||||
: "+m" (*p), "=q" (res)
|
||||
:
|
||||
: "cc", "memory"
|
||||
);
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* double word
|
||||
*/
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, int, int)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return _InterlockedCompareExchange128((volatile LONGLONG*)p, (LONGLONG)newval.hi, (LONGLONG)newval.lo, (LONGLONG*)oldval) != 0;
|
||||
#else
|
||||
char res;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"lock cmpxchg16b %0\n\t"
|
||||
"setz %b1\n\t"
|
||||
|
||||
: "+m" (*p), "=q" (res), "+a" (oldval->lo), "+d" (oldval->hi)
|
||||
: "b" (newval.lo), "c" (newval.hi)
|
||||
: "cc", "memory"
|
||||
);
|
||||
return res != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word2 atomic_load_explicit(const volatile atomic_word2* p, int o)
|
||||
{
|
||||
/*
|
||||
atomic_word2 r = { 0, 0 };
|
||||
atomic_word2 c = { 0, 0 };
|
||||
atomic_compare_exchange_strong_explicit((volatile atomic_word2*) p, &r, c, o, o);
|
||||
return r;
|
||||
*/
|
||||
atomic_word2 r;
|
||||
r.v = ::_mm_load_si128((const __m128i*)p);
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word2* p, atomic_word2 v, int o)
|
||||
{
|
||||
/*
|
||||
atomic_word2 c = v;
|
||||
while(!atomic_compare_exchange_strong_explicit(p, &c, v, o, o)) {};
|
||||
*/
|
||||
::_mm_store_si128((__m128i*)&p->v, v.v);
|
||||
}
|
||||
|
||||
static inline atomic_word2 atomic_exchange_explicit(volatile atomic_word2* p, atomic_word2 newval, int)
|
||||
{
|
||||
atomic_word2 oldval;
|
||||
oldval.lo = 0;
|
||||
oldval.hi = newval.hi - 1;
|
||||
while (!atomic_compare_exchange_strong_explicit(p, &oldval, newval, memory_order_seq_cst, memory_order_seq_cst))
|
||||
;
|
||||
return oldval;
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
#if defined(_MSC_VER)
|
||||
# include "os/Win32/WindowsHeaders.h"
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(__SSE2__)
|
||||
# include <emmintrin.h>
|
||||
#endif
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_relaxed_t)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_release_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
__asm__ __volatile__ ("" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_acquire_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
__asm__ __volatile__ ("" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(memory_order_acq_rel_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
__asm__ __volatile__ ("" : : : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_thread_fence(int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
#if defined(__SSE2__)
|
||||
_mm_mfence();
|
||||
#elif defined(_MSC_VER)
|
||||
volatile LONG tmp;
|
||||
_InterlockedOr(&tmp, 0);
|
||||
#else
|
||||
__asm__ __volatile__ ("lock orl #0, 0(%%esp)" ::: "cc", "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, memory_order_relaxed_t)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, int)
|
||||
{
|
||||
atomic_word v;
|
||||
#if defined(_MSC_VER)
|
||||
v = *p;
|
||||
_ReadWriteBarrier();
|
||||
#else
|
||||
__asm__ __volatile__ ("movl %1, %0" : "=r" (v) : "m" (*p) : "memory");
|
||||
#endif
|
||||
return v;
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
|
||||
{
|
||||
*p = v;
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, memory_order_release_t)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_ReadWriteBarrier();
|
||||
*p = v;
|
||||
#else
|
||||
__asm__ __volatile__ ("movl %1, %0" : "=m" (*p) : "r" (v) : "memory");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word val, int /* memory_order_seq_cst_t */)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_InterlockedExchange((volatile LONG*)p, (LONG)val);
|
||||
#else
|
||||
// lock prefix is implicit
|
||||
__asm__ __volatile__
|
||||
(
|
||||
/*lock*/ "xchgl %1, %0"
|
||||
|
||||
: "+m" (*p), "+r" (val)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_exchange_explicit(volatile atomic_word* p, atomic_word val, int)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return (atomic_word)_InterlockedExchange((volatile LONG*)p, (LONG)val);
|
||||
#else
|
||||
// lock prefix is implicit
|
||||
__asm__ __volatile__
|
||||
(
|
||||
/*lock*/ "xchgl %1, %0"
|
||||
|
||||
: "+m" (*p), "+r" (val)
|
||||
:
|
||||
: "memory"
|
||||
);
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word* p, atomic_word* oldval, atomic_word newval, int, int)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
atomic_word tmp = (atomic_word)_InterlockedCompareExchange((volatile LONG*)p, (LONG)newval, (LONG)*oldval);
|
||||
return *oldval == tmp ? true : (*oldval = tmp, false);
|
||||
#else
|
||||
char res;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"lock cmpxchgl %3, %0\n\t"
|
||||
"setz %b1"
|
||||
|
||||
: "+m" (*p), "=q" (res), "+a" (*oldval)
|
||||
: "r" (newval)
|
||||
: "cc", "memory"
|
||||
);
|
||||
return res != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_weak_explicit(volatile atomic_word* p, atomic_word* oldval, atomic_word newval, int, int)
|
||||
{
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_seq_cst, memory_order_seq_cst);
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add_explicit(volatile atomic_word *p, atomic_word val, int)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return _InterlockedExchangeAdd((LONG volatile*)p, (LONG)val);
|
||||
#else
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"lock xaddl %1, %0"
|
||||
: "+m" (*p), "+r" (val)
|
||||
:
|
||||
: "cc", "memory"
|
||||
);
|
||||
return val;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub_explicit(volatile atomic_word *p, atomic_word val, int mo)
|
||||
{
|
||||
return atomic_fetch_add_explicit(p, -val, mo);
|
||||
}
|
||||
|
||||
/*
|
||||
* extensions
|
||||
*/
|
||||
|
||||
static inline void atomic_retain(volatile int *p)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
_InterlockedIncrement((LONG volatile*)p);
|
||||
#else
|
||||
__asm__ (
|
||||
"lock incl %0\n\t"
|
||||
: "+m" (*p)
|
||||
:
|
||||
: "cc", "memory"
|
||||
);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_release(volatile int *p)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
return _InterlockedDecrement((LONG volatile*)p) == 0;
|
||||
#else
|
||||
bool res;
|
||||
__asm__ (
|
||||
"lock decl %0\n\t"
|
||||
"setz %b1"
|
||||
: "+m" (*p), "=q" (res)
|
||||
:
|
||||
: "cc", "memory"
|
||||
);
|
||||
return res;
|
||||
#endif
|
||||
}
|
||||
|
||||
// double word
|
||||
|
||||
static inline atomic_word2 atomic_load_explicit(const volatile atomic_word2* p, int)
|
||||
{
|
||||
atomic_word2 r;
|
||||
#if defined(__SSE2__)
|
||||
_mm_store_sd((double*)&r, _mm_load_sd((const double*)p));
|
||||
#else
|
||||
// using the FPU is the only way to do a 64 bit atomic load if SSE is not available
|
||||
r.d = p->d;
|
||||
#endif
|
||||
return r;
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word2* p, atomic_word2 v, int)
|
||||
{
|
||||
#if defined(__SSE2__)
|
||||
_mm_store_sd((double*)p, _mm_load_sd((const double*)&v));
|
||||
#else
|
||||
// using the FPU is the only way to do a 64 bit atomic store if SSE is not available
|
||||
p->d = v.d;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange_strong_explicit(volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, int, int)
|
||||
{
|
||||
#if defined(_MSC_VER)
|
||||
LONGLONG tmp = _InterlockedCompareExchange64((volatile LONGLONG*)p, newval.v, oldval->v);
|
||||
return oldval->v == tmp ? true : (oldval->v = tmp, false);
|
||||
#else
|
||||
char res;
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"lock cmpxchg8b %0\n\t"
|
||||
"setz %b1\n\t"
|
||||
|
||||
: "+m" (*p), "=q" (res), "+a" (oldval->lo), "+d" (oldval->hi)
|
||||
: "b" (newval.lo), "c" (newval.hi)
|
||||
: "cc", "memory"
|
||||
);
|
||||
return res != 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline atomic_word2 atomic_exchange_explicit(volatile atomic_word2* p, atomic_word2 newval, int)
|
||||
{
|
||||
atomic_word2 oldval;
|
||||
oldval.lo = 0;
|
||||
oldval.hi = newval.hi - 1;
|
||||
while (!atomic_compare_exchange_strong_explicit(p, &oldval, newval, memory_order_seq_cst, memory_order_seq_cst))
|
||||
;
|
||||
return oldval;
|
||||
}
|
||||
@@ -0,0 +1,215 @@
|
||||
#pragma once
|
||||
|
||||
#include "ExtendedAtomicTypes.h"
|
||||
|
||||
UNITY_PLATFORM_BEGIN_NAMESPACE;
|
||||
|
||||
enum memory_order_relaxed_t { memory_order_relaxed = 0 };
|
||||
enum memory_order_acquire_t { memory_order_acquire = 2, memory_order_consume = memory_order_acquire };
|
||||
enum memory_order_release_t { memory_order_release = 3 };
|
||||
enum memory_order_acq_rel_t { memory_order_acq_rel = 4 };
|
||||
enum memory_order_seq_cst_t { memory_order_seq_cst = 5 };
|
||||
|
||||
/*
|
||||
Available atomic functions:
|
||||
|
||||
// non-explicit versions, use sequential consistency semantic by default
|
||||
|
||||
// atomic load
|
||||
atomic_word atomic_load (const volatile atomic_word* p);
|
||||
|
||||
// atomic store
|
||||
void atomic_store (volatile atomic_word* p, atomic_word val);
|
||||
|
||||
// atomic exchange, returns previous value
|
||||
atomic_word atomic_exchange (volatile atomic_word* p, atomic_word val);
|
||||
|
||||
// atomic compare exchange (strong), returns if the operation succeeded and update *oldval with the previous value
|
||||
bool atomic_compare_exchange (volatile atomic_word* p, atomic_word* oldval, atomic_word newval);
|
||||
|
||||
// atomic fetch then add, returns previous value
|
||||
atomic_word atomic_fetch_add (volatile atomic_word *p, atomic_word val);
|
||||
|
||||
// atomic fetch then sub, returns previous value
|
||||
atomic_word atomic_fetch_sub (volatile atomic_word *p, atomic_word val);
|
||||
|
||||
// explicit versions
|
||||
|
||||
// memory fence with <mo> semantic
|
||||
void atomic_thread_fence (memory_order_t mo);
|
||||
|
||||
// atomic load with <mo> semantic
|
||||
atomic_word atomic_load_explicit (const volatile atomic_word* p, memory_order_t mo);
|
||||
|
||||
// atomic store with <mo> semantic
|
||||
void atomic_store_explicit (volatile atomic_word* p, atomic_word v, memory_order_t mo);
|
||||
|
||||
// atomic exchange with <mo> semantic, returns previous value
|
||||
atomic_word atomic_exchange_explicit (volatile atomic_word* p, atomic_word v, memory_order_t mo);
|
||||
|
||||
// on RISC platforms with LoadLinked-StoreConditional available:
|
||||
// atomic_compare_exchange_weak_explicit: can fail spuriously even if *p == *oldval
|
||||
// uses <success> memory barrier when it succeeds, <failure> otherwize
|
||||
// returns the state of the operation and updates *oldval with the previous value
|
||||
bool atomic_compare_exchange_weak_explicit (volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_t success, memory_order_t failure);
|
||||
|
||||
// atomic_compare_exchange_strong_explicit: can loop and only returns false if *p != *oldval
|
||||
// uses <success> memory barrier when it succeeds, <failure> otherwise
|
||||
// returns the state of the operation and updates *oldval with the previous value
|
||||
bool atomic_compare_exchange_strong_explicit (volatile atomic_word* p, atomic_word *oldval, atomic_word newval, memory_order_t success, memory_order_t failure);
|
||||
|
||||
// atomic fetch then add with <mo> semantic, returns previous value
|
||||
int atomic_fetch_add_explicit (volatile int* p, int val, memory_order_t mo);
|
||||
atomic_word atomic_fetch_add_explicit (volatile atomic_word* p, atomic_word val, memory_order_t mo);
|
||||
|
||||
// atomic fetch then sub with <mo> semantic, returns previous value
|
||||
int atomic_fetch_sub_explicit (volatile int* p, int val, memory_order_t mo);
|
||||
atomic_word atomic_fetch_sub_explicit (volatile atomic_word* p, atomic_word val, memory_order_t mo);
|
||||
|
||||
// extensions to the C++0x11 standard:
|
||||
|
||||
// atomic increment with relaxed semantic
|
||||
void atomic_retain (volatile int *p);
|
||||
|
||||
// atomic decrement with acquire/release semantic, returns true if resulting value is zero, false otherwize
|
||||
bool atomic_release (volatile int *p);
|
||||
|
||||
// on platforms with double word compare exchange (ABA safe atomic pointers):
|
||||
|
||||
// atomic load
|
||||
atomic_word2 atomic_load_explicit (const volatile atomic_word2* p, memory_order_t mo);
|
||||
|
||||
// atomic store
|
||||
void atomic_store_explicit (volatile atomic_word2* p, atomic_word2 v, memory_order_t mo);
|
||||
|
||||
// atomic exchange
|
||||
atomic_word atomic_exchange_explicit (volatile atomic_word2* p, atomic_word2 newval, memory_order_t mo);
|
||||
|
||||
// atomic compare exchange
|
||||
bool atomic_compare_exchange_strong_explicit (volatile atomic_word2* p, atomic_word2* oldval, atomic_word2 newval, memory_order_t success, memory_order_t failure);
|
||||
*/
|
||||
|
||||
#if IL2CPP_TARGET_HAS_EXTENDED_ATOMICS
|
||||
|
||||
# include "os/ExtendedAtomicOps.h"
|
||||
|
||||
#elif UNITY_ATOMIC_USE_GCC_ATOMICS || UNITY_ATOMIC_USE_CLANG_ATOMICS
|
||||
|
||||
# include "ExtendedAtomicOps-clang-gcc.h"
|
||||
|
||||
#elif defined(__x86_64__) || defined(_M_X64)
|
||||
|
||||
# include "ExtendedAtomicOps-x86-64.h"
|
||||
# define UNITY_ATOMIC_INT_OVERLOAD
|
||||
|
||||
#elif defined(__x86__) || defined(__i386__) || defined(_M_IX86)
|
||||
|
||||
# include "ExtendedAtomicOps-x86.h"
|
||||
|
||||
#elif (defined(__arm64__) || defined(__aarch64__)) && (defined(__clang__) || defined(__GNUC__))
|
||||
|
||||
# include "ExtendedAtomicOps-arm64.h"
|
||||
# define UNITY_ATOMIC_INT_OVERLOAD
|
||||
|
||||
#elif defined(_M_ARM) || (defined(__arm__) && (defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)) && (!UNITY_STV_API) && (defined(__clang__) || defined(__GNUC__)))
|
||||
|
||||
# include "ExtendedAtomicOps-arm.h"
|
||||
|
||||
#elif PLATFORM_WIIU
|
||||
|
||||
# include "ExtendedAtomicOps-ppc.h"
|
||||
|
||||
#elif PLATFORM_PSVITA
|
||||
|
||||
# include "PlatformExtendedAtomicOps.h"
|
||||
|
||||
#elif (defined(__ppc64__) || defined(_ARCH_PPC64)) && (defined(__clang__) || defined(__GNUC__))
|
||||
|
||||
# include "ExtendedAtomicOps-ppc64.h"
|
||||
# define UNITY_ATOMIC_INT_OVERLOAD
|
||||
|
||||
//#elif defined (__ppc__) && (defined (__clang__) || defined (__GNUC__))
|
||||
|
||||
//# include "Runtime/Threads/ExtendedAtomicOps-ppc.h"
|
||||
#else
|
||||
|
||||
#define UNITY_NO_ATOMIC_OPS
|
||||
|
||||
static inline atomic_word atomic_load_explicit(const volatile atomic_word* p, memory_order_relaxed_t)
|
||||
{
|
||||
return *p;
|
||||
}
|
||||
|
||||
static inline void atomic_store_explicit(volatile atomic_word* p, atomic_word v, memory_order_relaxed_t)
|
||||
{
|
||||
*p = v;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef UNITY_NO_ATOMIC_OPS
|
||||
|
||||
// non-explicit versions, use sequential consistency semantic
|
||||
|
||||
static inline void atomic_thread_fence()
|
||||
{
|
||||
atomic_thread_fence(memory_order_seq_cst);
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_load(const volatile atomic_word* p)
|
||||
{
|
||||
return atomic_load_explicit(p, memory_order_seq_cst);
|
||||
}
|
||||
|
||||
static inline void atomic_store(volatile atomic_word* p, atomic_word val)
|
||||
{
|
||||
atomic_store_explicit(p, val, memory_order_seq_cst);
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_exchange(volatile atomic_word* p, atomic_word val)
|
||||
{
|
||||
return atomic_exchange_explicit(p, val, memory_order_seq_cst);
|
||||
}
|
||||
|
||||
static inline bool atomic_compare_exchange(volatile atomic_word* p, atomic_word* oldval, atomic_word newval)
|
||||
{
|
||||
return atomic_compare_exchange_strong_explicit(p, oldval, newval, memory_order_seq_cst, memory_order_seq_cst);
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_add(volatile atomic_word *p, atomic_word val)
|
||||
{
|
||||
return atomic_fetch_add_explicit(p, val, memory_order_seq_cst);
|
||||
}
|
||||
|
||||
static inline atomic_word atomic_fetch_sub(volatile atomic_word *p, atomic_word val)
|
||||
{
|
||||
return atomic_fetch_sub_explicit(p, val, memory_order_seq_cst);
|
||||
}
|
||||
|
||||
#if defined(UNITY_ATOMIC_INT_OVERLOAD)
|
||||
|
||||
static inline int atomic_load(const volatile int* p)
|
||||
{
|
||||
return atomic_load_explicit(p, memory_order_seq_cst);
|
||||
}
|
||||
|
||||
static inline void atomic_store(volatile int* p, int val)
|
||||
{
|
||||
atomic_store_explicit(p, val, memory_order_seq_cst);
|
||||
}
|
||||
|
||||
static inline int atomic_fetch_add(volatile int *p, int val)
|
||||
{
|
||||
return static_cast<int>(atomic_fetch_add_explicit(p, val, memory_order_seq_cst));
|
||||
}
|
||||
|
||||
static inline int atomic_fetch_sub(volatile int *p, int val)
|
||||
{
|
||||
return static_cast<int>(atomic_fetch_sub_explicit(p, val, memory_order_seq_cst));
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
UNITY_PLATFORM_END_NAMESPACE;
|
||||
@@ -0,0 +1,193 @@
|
||||
#pragma once
|
||||
|
||||
// Off by default, can be enabled in platform specific configuration
|
||||
#ifndef UNITY_ATOMIC_USE_CLANG_ATOMICS
|
||||
# define UNITY_ATOMIC_USE_CLANG_ATOMICS 0
|
||||
#endif
|
||||
#ifndef UNITY_ATOMIC_USE_GCC_ATOMICS
|
||||
# define UNITY_ATOMIC_USE_GCC_ATOMICS 0
|
||||
#endif
|
||||
|
||||
#if UNITY_ATOMIC_USE_GCC_ATOMICS || UNITY_ATOMIC_USE_CLANG_ATOMICS
|
||||
# if __SIZEOF_POINTER__ == 8
|
||||
typedef long long non_atomic_word;
|
||||
typedef __int128 non_atomic_word2;
|
||||
# define UNITY_ATOMIC_INT_OVERLOAD
|
||||
# elif __SIZEOF_POINTER__ == 4
|
||||
typedef int non_atomic_word;
|
||||
typedef long long non_atomic_word2;
|
||||
# else
|
||||
# error unsupported __SIZEOF_POINTER__
|
||||
# endif
|
||||
|
||||
# define ATOMIC_HAS_DCAS
|
||||
|
||||
typedef non_atomic_word atomic_word;
|
||||
|
||||
union atomic_word2
|
||||
{
|
||||
non_atomic_word2 v;
|
||||
struct
|
||||
{
|
||||
atomic_word lo;
|
||||
atomic_word hi;
|
||||
};
|
||||
};
|
||||
|
||||
#elif defined(__x86_64__) || defined(_M_X64)
|
||||
|
||||
# include <emmintrin.h>
|
||||
|
||||
/// atomic_word must be 8 bytes aligned if you want to use it with atomic_* ops.
|
||||
# if defined(_MSC_VER)
|
||||
typedef __int64 atomic_word;
|
||||
# else
|
||||
typedef long long atomic_word;
|
||||
# endif
|
||||
|
||||
/// atomic_word2 must be 16 bytes aligned if you want to use it with atomic_* ops.
|
||||
union atomic_word2
|
||||
{
|
||||
__m128i v;
|
||||
struct
|
||||
{
|
||||
atomic_word lo, hi;
|
||||
};
|
||||
};
|
||||
#define ATOMIC_HAS_DCAS
|
||||
#define UNITY_ATOMIC_INT_OVERLOAD
|
||||
|
||||
#elif defined(__x86__) || defined(__i386__) || defined(_M_IX86)
|
||||
|
||||
/// atomic_word must be 4 bytes aligned if you want to use it with atomic_* ops.
|
||||
typedef int atomic_word;
|
||||
|
||||
/// atomic_word2 must be 8 bytes aligned if you want to use it with atomic_* ops.
|
||||
union atomic_word2
|
||||
{
|
||||
# if defined(_MSC_VER)
|
||||
__int64 v;
|
||||
# else
|
||||
long long v;
|
||||
# endif
|
||||
# if !defined(__SSE2__)
|
||||
double d;
|
||||
# endif
|
||||
struct
|
||||
{
|
||||
atomic_word lo, hi;
|
||||
};
|
||||
};
|
||||
#define ATOMIC_HAS_DCAS
|
||||
|
||||
#elif __ARMCC_VERSION // 3DS
|
||||
|
||||
typedef int atomic_word;
|
||||
typedef int memory_order_t;
|
||||
|
||||
# include "os/ExtendedAtomicTypes.h"
|
||||
|
||||
#elif (defined(__arm64__) || defined(__aarch64__)) && (defined(__clang__) || defined(__GNUC__))
|
||||
|
||||
typedef long long atomic_word;
|
||||
struct atomic_word2
|
||||
{
|
||||
atomic_word lo;
|
||||
atomic_word hi;
|
||||
};
|
||||
# define ATOMIC_HAS_DCAS
|
||||
# define ATOMIC_HAS_LDR
|
||||
# define UNITY_ATOMIC_INT_OVERLOAD
|
||||
|
||||
#elif defined(_M_ARM) || (defined(__arm__) && (defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)) && (defined(__clang__) || defined(__GNUC__)))
|
||||
|
||||
typedef int atomic_word;
|
||||
union atomic_word2
|
||||
{
|
||||
# if defined(_MSC_VER)
|
||||
__int64 v;
|
||||
# else
|
||||
long long v;
|
||||
# endif
|
||||
struct
|
||||
{
|
||||
atomic_word lo;
|
||||
atomic_word hi;
|
||||
};
|
||||
};
|
||||
# define ATOMIC_HAS_DCAS
|
||||
# if !defined(_MSC_VER)
|
||||
# define ATOMIC_HAS_LDR
|
||||
# endif
|
||||
|
||||
#elif PLATFORM_WINRT && defined(__arm__)
|
||||
|
||||
typedef __int32 atomic_word;
|
||||
union atomic_word2
|
||||
{
|
||||
__int64 v;
|
||||
struct
|
||||
{
|
||||
atomic_word lo;
|
||||
atomic_word hi;
|
||||
};
|
||||
};
|
||||
# define ATOMIC_HAS_DCAS
|
||||
|
||||
#elif PLATFORM_PSVITA || (PLATFORM_WEBGL && SUPPORT_THREADS)
|
||||
|
||||
#include <stdint.h>
|
||||
typedef int32_t atomic_word;
|
||||
union atomic_word2
|
||||
{
|
||||
int64_t v;
|
||||
struct
|
||||
{
|
||||
atomic_word lo;
|
||||
atomic_word hi;
|
||||
};
|
||||
};
|
||||
# define ATOMIC_HAS_DCAS
|
||||
# define ATOMIC_HAS_LDR
|
||||
|
||||
#elif defined(__ppc64__) || defined(_ARCH_PPC64)
|
||||
|
||||
typedef long atomic_word;
|
||||
# define ATOMIC_HAS_LDR
|
||||
# define UNITY_ATOMIC_INT_OVERLOAD
|
||||
|
||||
#elif defined(__ppc__)
|
||||
|
||||
typedef int atomic_word;
|
||||
# define ATOMIC_HAS_LDR
|
||||
|
||||
#else
|
||||
|
||||
# if defined(__LP64__)
|
||||
typedef long long atomic_word;
|
||||
# define UNITY_ATOMIC_INT_OVERLOAD
|
||||
# else
|
||||
typedef int atomic_word;
|
||||
# endif
|
||||
|
||||
struct atomic_word2
|
||||
{
|
||||
atomic_word lo;
|
||||
atomic_word hi;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(ATOMIC_HAS_DCAS)
|
||||
|
||||
#define ATOMIC_HAS_QUEUE 2
|
||||
|
||||
#elif (defined(__arm64__) || defined(__aarch64__)) && (defined(__clang__) || defined(__GNUC__))
|
||||
|
||||
#define ATOMIC_HAS_QUEUE 1
|
||||
|
||||
#elif defined(__arm__) && (defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)) && (defined(__clang__) || defined(__GNUC__) || defined(SN_TARGET_PSP2))
|
||||
|
||||
#define ATOMIC_HAS_QUEUE 1
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
// Stopgap measure to allow using some code from the Unity's own platform layer without having to adapt it exclusively
|
||||
// for il2cpp.
|
||||
|
||||
#include "il2cpp-config.h"
|
||||
|
||||
#if IL2CPP_TARGET_WINDOWS || IL2CPP_TARGET_XBOXONE
|
||||
#include <malloc.h>
|
||||
#else
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
#include <new>
|
||||
|
||||
#define UNITY_PLATFORM_BEGIN_NAMESPACE namespace il2cpp { namespace os {
|
||||
#define UNITY_PLATFORM_END_NAMESPACE }}
|
||||
|
||||
#define UNITY_PLATFORM_NEW(type, label) new type
|
||||
#define UNITY_PLATFORM_NEW_ALIGNED(type, label, alignment) new (alignment) type
|
||||
#define UNITY_PLATFORM_DELETE(ptr, label) delete ptr
|
||||
|
||||
inline void* operator new(size_t size, int alignment)
|
||||
{
|
||||
void* result = NULL;
|
||||
#if IL2CPP_TARGET_WINDOWS || IL2CPP_TARGET_XBOXONE
|
||||
result = _aligned_malloc(size, alignment);
|
||||
#elif IL2CPP_TARGET_ANDROID || IL2CPP_TARGET_PSP2
|
||||
result = memalign(alignment, size);
|
||||
#else
|
||||
if (posix_memalign(&result, size, alignment))
|
||||
result = NULL;
|
||||
#endif
|
||||
if (!result)
|
||||
throw std::bad_alloc();
|
||||
return result;
|
||||
}
|
||||
|
||||
#if IL2CPP_TARGET_WINDOWS || IL2CPP_TARGET_XBOXONE // Visual C++ warns if new is overridden but delete is not.
|
||||
inline void operator delete(void* ptr, int alignment) throw ()
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#include "os/c-api/WaitStatus-c-api.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
typedef UnityPalWaitStatus WaitStatus;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_TARGET_WINDOWS
|
||||
|
||||
#include "os/Win32/WindowsHeaders.h"
|
||||
#include "c-api/Atomic-c-api.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
inline void Atomic::FullMemoryBarrier()
|
||||
{
|
||||
#if defined(_AMD64_)
|
||||
::__faststorefence();
|
||||
#elif defined(_M_IX86)
|
||||
::MemoryBarrier();
|
||||
#elif defined(_M_ARM)
|
||||
__dmb(_ARM_BARRIER_SY);
|
||||
#else
|
||||
#error Not implemented;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
#if NET_4_0
|
||||
#if IL2CPP_THREADS_WIN32
|
||||
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
#include "WindowsHeaders.h"
|
||||
|
||||
class FastMutexImpl;
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ConditionVariableImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
ConditionVariableImpl();
|
||||
~ConditionVariableImpl();
|
||||
|
||||
int Wait(FastMutexImpl* lock);
|
||||
int TimedWait(FastMutexImpl* lock, uint32_t timeout_ms);
|
||||
void Broadcast();
|
||||
void Signal();
|
||||
|
||||
private:
|
||||
CONDITION_VARIABLE m_ConditionVariable;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
void InitializeDllMain();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_THREADS_WIN32
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
#include "WindowsHeaders.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class EventImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
EventImpl(bool manualReset = false, bool signaled = false);
|
||||
~EventImpl();
|
||||
|
||||
ErrorCode Set();
|
||||
ErrorCode Reset();
|
||||
WaitStatus Wait(bool interruptible);
|
||||
WaitStatus Wait(uint32_t ms, bool interruptible);
|
||||
|
||||
private:
|
||||
HANDLE m_Event;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,63 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_THREADS_WIN32
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
#include "WindowsHeaders.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class MutexImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
MutexImpl();
|
||||
~MutexImpl();
|
||||
|
||||
void Lock(bool interruptible);
|
||||
bool TryLock(uint32_t milliseconds, bool interruptible);
|
||||
void Unlock();
|
||||
|
||||
private:
|
||||
HANDLE m_MutexHandle;
|
||||
};
|
||||
|
||||
class FastMutexImpl
|
||||
{
|
||||
public:
|
||||
FastMutexImpl()
|
||||
{
|
||||
InitializeCriticalSection(&m_CritialSection);
|
||||
}
|
||||
|
||||
~FastMutexImpl()
|
||||
{
|
||||
DeleteCriticalSection(&m_CritialSection);
|
||||
}
|
||||
|
||||
void Lock()
|
||||
{
|
||||
EnterCriticalSection(&m_CritialSection);
|
||||
}
|
||||
|
||||
void Unlock()
|
||||
{
|
||||
LeaveCriticalSection(&m_CritialSection);
|
||||
}
|
||||
|
||||
CRITICAL_SECTION* GetOSHandle()
|
||||
{
|
||||
return &m_CritialSection;
|
||||
}
|
||||
|
||||
private:
|
||||
CRITICAL_SECTION m_CritialSection;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_THREADS_WIN32
|
||||
|
||||
#include "WindowsHeaders.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ReaderWriterLockImpl
|
||||
{
|
||||
public:
|
||||
|
||||
ReaderWriterLockImpl()
|
||||
{
|
||||
InitializeSRWLock(&m_Lock);
|
||||
}
|
||||
|
||||
void LockExclusive()
|
||||
{
|
||||
AcquireSRWLockExclusive(&m_Lock);
|
||||
}
|
||||
|
||||
void LockShared()
|
||||
{
|
||||
AcquireSRWLockShared(&m_Lock);
|
||||
}
|
||||
|
||||
void ReleaseExclusive()
|
||||
{
|
||||
ReleaseSRWLockExclusive(&m_Lock);
|
||||
}
|
||||
|
||||
void ReleaseShared()
|
||||
{
|
||||
ReleaseSRWLockShared(&m_Lock);
|
||||
}
|
||||
|
||||
PSRWLOCK GetOSHandle()
|
||||
{
|
||||
return &m_Lock;
|
||||
}
|
||||
|
||||
private:
|
||||
SRWLOCK m_Lock;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_THREADS_WIN32
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
#include "WindowsHeaders.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class SemaphoreImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
SemaphoreImpl(int32_t initialValue, int32_t maximumValue);
|
||||
~SemaphoreImpl();
|
||||
bool Post(int32_t releaseCount, int32_t* previousCount = NULL);
|
||||
WaitStatus Wait(bool interruptible);
|
||||
WaitStatus Wait(uint32_t ms, bool interruptible);
|
||||
private:
|
||||
HANDLE m_Handle;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,129 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_TARGET_WINDOWS
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "os/Socket.h"
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
struct sockaddr;
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class SocketImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
|
||||
/// Handle for socket. Must be large enough to hold a pointer.
|
||||
typedef uint64_t SocketDescriptor;
|
||||
|
||||
SocketImpl(ThreadStatusCallback thread_status_callback);
|
||||
~SocketImpl();
|
||||
|
||||
inline SocketDescriptor GetDescriptor()
|
||||
{
|
||||
return _fd;
|
||||
}
|
||||
|
||||
ErrorCode GetLastError() const;
|
||||
|
||||
WaitStatus Create(SocketDescriptor fd, int32_t family, int32_t type, int32_t protocol);
|
||||
WaitStatus Create(AddressFamily family, SocketType type, ProtocolType protocol);
|
||||
|
||||
WaitStatus Close();
|
||||
bool IsClosed() { return (_fd == -1); }
|
||||
|
||||
WaitStatus SetBlocking(bool blocking);
|
||||
|
||||
WaitStatus Listen(int32_t blacklog);
|
||||
|
||||
WaitStatus Bind(const char *path);
|
||||
WaitStatus Bind(const char *address, uint16_t port);
|
||||
WaitStatus Bind(uint32_t address, uint16_t port);
|
||||
WaitStatus Bind(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port);
|
||||
|
||||
WaitStatus Connect(const char *path);
|
||||
WaitStatus Connect(uint32_t address, uint16_t port);
|
||||
WaitStatus Connect(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port);
|
||||
|
||||
WaitStatus Disconnect(bool reuse);
|
||||
WaitStatus Shutdown(int32_t how);
|
||||
|
||||
WaitStatus GetLocalEndPointInfo(EndPointInfo &info);
|
||||
WaitStatus GetRemoteEndPointInfo(EndPointInfo &info);
|
||||
|
||||
WaitStatus Receive(const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
WaitStatus ReceiveFromInternal(const uint8_t *data, size_t count, int32_t flags, int32_t *len, struct sockaddr *from, int32_t *fromlen);
|
||||
|
||||
WaitStatus Send(const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
|
||||
WaitStatus SendArray(WSABuf *wsabufs, int32_t count, int32_t *sent, SocketFlags c_flags);
|
||||
WaitStatus ReceiveArray(WSABuf *wsabufs, int32_t count, int32_t *len, SocketFlags c_flags);
|
||||
|
||||
WaitStatus SendTo(uint32_t address, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
WaitStatus SendTo(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
WaitStatus SendTo(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len);
|
||||
|
||||
WaitStatus RecvFrom(uint32_t address, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
|
||||
WaitStatus RecvFrom(const char *path, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
|
||||
WaitStatus RecvFrom(uint8_t address[ipv6AddressSize], uint32_t scope, uint16_t port, const uint8_t *data, int32_t count, os::SocketFlags flags, int32_t *len, os::EndPointInfo &ep);
|
||||
|
||||
WaitStatus Available(int32_t *amount);
|
||||
|
||||
WaitStatus Accept(os::Socket **socket);
|
||||
|
||||
WaitStatus Ioctl(int32_t command, const uint8_t *in_data, int32_t in_len, uint8_t *out_data, int32_t out_len, int32_t *written);
|
||||
|
||||
WaitStatus GetSocketOption(SocketOptionLevel level, SocketOptionName name, uint8_t *buffer, int32_t *length);
|
||||
WaitStatus GetSocketOptionFull(SocketOptionLevel level, SocketOptionName name, int32_t *first, int32_t *second);
|
||||
|
||||
WaitStatus SetSocketOption(SocketOptionLevel level, SocketOptionName name, int32_t value);
|
||||
WaitStatus SetSocketOptionLinger(SocketOptionLevel level, SocketOptionName name, bool enabled, int32_t seconds);
|
||||
WaitStatus SetSocketOptionArray(SocketOptionLevel level, SocketOptionName name, const uint8_t *buffer, int32_t length);
|
||||
WaitStatus SetSocketOptionMembership(SocketOptionLevel level, SocketOptionName name, uint32_t group_address, uint32_t local_address);
|
||||
#if IL2CPP_SUPPORT_IPV6
|
||||
WaitStatus SetSocketOptionMembership(SocketOptionLevel level, SocketOptionName name, IPv6Address ipv6, uint64_t interfaceOffset);
|
||||
#endif
|
||||
|
||||
WaitStatus SendFile(const char *filename, TransmitFileBuffers *buffers, TransmitFileOptions options);
|
||||
|
||||
static WaitStatus Poll(std::vector<PollRequest> &requests, int32_t count, int32_t timeout, int32_t *result, int32_t *error);
|
||||
static WaitStatus Poll(std::vector<PollRequest> &requests, int32_t timeout, int32_t *result, int32_t *error);
|
||||
static WaitStatus Poll(PollRequest& request, int32_t timeout, int32_t *result, int32_t *error);
|
||||
|
||||
static WaitStatus GetHostName(std::string &name);
|
||||
static WaitStatus GetHostByName(const std::string &host, std::string &name, std::vector<std::string> &aliases, std::vector<std::string> &addresses);
|
||||
static WaitStatus GetHostByName(const std::string &host, std::string &name, int32_t &family, std::vector<std::string> &aliases, std::vector<void*> &addr_list, int32_t &addr_size);
|
||||
static WaitStatus GetHostByAddr(const std::string &address, std::string &name, std::vector<std::string> &aliases, std::vector<std::string> &addr_list);
|
||||
|
||||
static void Startup();
|
||||
static void Cleanup();
|
||||
|
||||
private:
|
||||
|
||||
bool _is_valid;
|
||||
SocketDescriptor _fd;
|
||||
int32_t _domain;
|
||||
int32_t _type;
|
||||
int32_t _protocol;
|
||||
ErrorCode _saved_error;
|
||||
int32_t _still_readable;
|
||||
ThreadStatusCallback _thread_status_callback;
|
||||
|
||||
void StoreLastError();
|
||||
void StoreLastError(int32_t error_no);
|
||||
|
||||
WaitStatus ConnectInternal(struct sockaddr *sa, int32_t sa_size);
|
||||
WaitStatus SetSocketOptionInternal(int32_t level, int32_t name, const void *value, int32_t len);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#if !IL2CPP_THREADS_STD && IL2CPP_THREADS_WIN32
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/Thread.h"
|
||||
#include "os/WaitStatus.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
#include "WindowsHeaders.h"
|
||||
|
||||
#define IL2CPP_DEFAULT_STACK_SIZE ( 1 * 1024 * 1024) // default .NET stacksize is 1mb
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ThreadImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
ThreadImpl();
|
||||
~ThreadImpl();
|
||||
|
||||
uint64_t Id();
|
||||
ErrorCode Run(Thread::StartFunc func, void* arg);
|
||||
void SetName(const std::string& name);
|
||||
void SetPriority(ThreadPriority priority);
|
||||
ThreadPriority GetPriority();
|
||||
|
||||
void SetStackSize(size_t newsize)
|
||||
{
|
||||
// only makes sense if it's called BEFORE the thread has been created
|
||||
IL2CPP_ASSERT(m_ThreadHandle == NULL);
|
||||
// if newsize is zero we use the per-platform default value for size of stack
|
||||
if (newsize == 0)
|
||||
{
|
||||
newsize = IL2CPP_DEFAULT_STACK_SIZE;
|
||||
}
|
||||
m_StackSize = newsize;
|
||||
}
|
||||
|
||||
static int GetMaxStackSize();
|
||||
|
||||
void QueueUserAPC(Thread::APCFunc func, void* context);
|
||||
|
||||
ApartmentState GetApartment();
|
||||
ApartmentState GetExplicitApartment();
|
||||
ApartmentState SetApartment(ApartmentState state);
|
||||
void SetExplicitApartment(ApartmentState state);
|
||||
|
||||
static void Sleep(uint32_t ms, bool interruptible);
|
||||
static uint64_t CurrentThreadId();
|
||||
static ThreadImpl* CreateForCurrentThread();
|
||||
|
||||
#if NET_4_0
|
||||
static bool YieldInternal();
|
||||
#endif
|
||||
|
||||
#if IL2CPP_HAS_NATIVE_THREAD_CLEANUP
|
||||
static void SetNativeThreadCleanup(Thread::ThreadCleanupFunc cleanupFunction);
|
||||
static void RegisterCurrentThreadForCleanup(void* arg);
|
||||
static void UnregisterCurrentThreadForCleanup();
|
||||
static void OnCurrentThreadExiting();
|
||||
#endif
|
||||
|
||||
private:
|
||||
HANDLE m_ThreadHandle;
|
||||
volatile DWORD m_ThreadId;
|
||||
SIZE_T m_StackSize;
|
||||
ApartmentState m_ApartmentState;
|
||||
ThreadPriority m_Priority;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_THREADS_WIN32
|
||||
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "utils/NonCopyable.h"
|
||||
|
||||
#include "WindowsHelpers.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class ThreadLocalValueImpl : public il2cpp::utils::NonCopyable
|
||||
{
|
||||
public:
|
||||
ThreadLocalValueImpl();
|
||||
~ThreadLocalValueImpl();
|
||||
ErrorCode SetValue(void* value);
|
||||
ErrorCode GetValue(void** value);
|
||||
private:
|
||||
DWORD m_Index;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_TARGET_WINDOWS
|
||||
|
||||
#include "../c-api/Win32/WindowsHeaders.h"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_TARGET_WINDOWS
|
||||
|
||||
#include "WindowsHeaders.h"
|
||||
#include "os/WaitStatus.h"
|
||||
|
||||
#if IL2CPP_TARGET_WINRT
|
||||
#include "os/WinRT/Win32ApiWinRTEmulation.h"
|
||||
#endif
|
||||
|
||||
#if IL2CPP_TARGET_XBOXONE
|
||||
#include "os/XboxOne/Win32ApiXboxEmulation.h"
|
||||
#endif
|
||||
|
||||
#if IL2CPP_TARGET_WINRT || IL2CPP_TARGET_XBOXONE
|
||||
#include "os/WinRT/Win32ApiSharedEmulation.h"
|
||||
#endif
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
namespace win
|
||||
{
|
||||
// Wait for a release of the given handle in way that can be interrupted by APCs.
|
||||
WaitStatus WaitForSingleObjectAndAccountForAPCs(HANDLE handle, uint32_t ms, bool interruptible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // IL2CPP_TARGET_WINDOWS
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include "os/Win32/WindowsHeaders.h"
|
||||
#include <windows.foundation.collections.h>
|
||||
#include <wrl.h>
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace winrt
|
||||
{
|
||||
template<typename T>
|
||||
class SynchronousOperation : Microsoft::WRL::RuntimeClass<Microsoft::WRL::RuntimeClassFlags<Microsoft::WRL::WinRtClassicComMix>, ABI::Windows::Foundation::IAsyncOperationCompletedHandler<T> >
|
||||
{
|
||||
private:
|
||||
HANDLE m_Event;
|
||||
HRESULT m_HR;
|
||||
T m_Result;
|
||||
|
||||
public:
|
||||
inline SynchronousOperation(ABI::Windows::Foundation::IAsyncOperation<T>* op)
|
||||
{
|
||||
m_Event = CreateEventExW(nullptr, nullptr, CREATE_EVENT_MANUAL_RESET, EVENT_ALL_ACCESS);
|
||||
Assert(m_Event);
|
||||
|
||||
auto hr = op->put_Completed(this);
|
||||
Assert(SUCCEEDED(hr));
|
||||
}
|
||||
|
||||
inline ~SynchronousOperation()
|
||||
{
|
||||
CloseHandle(m_Event);
|
||||
}
|
||||
|
||||
HRESULT GetResults(T* result)
|
||||
{
|
||||
auto waitResult = WaitForSingleObjectEx(m_Event, INFINITE, FALSE);
|
||||
|
||||
if (waitResult != WAIT_OBJECT_0)
|
||||
return E_FAIL;
|
||||
|
||||
if (FAILED(m_HR))
|
||||
return m_HR;
|
||||
|
||||
*result = m_Result;
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual HRESULT STDMETHODCALLTYPE Invoke(ABI::Windows::Foundation::IAsyncOperation<T>* asyncInfo, ABI::Windows::Foundation::AsyncStatus status) override
|
||||
{
|
||||
m_HR = asyncInfo->GetResults(&m_Result);
|
||||
SetEvent(m_Event);
|
||||
return S_OK;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
+125
@@ -0,0 +1,125 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_TARGET_WINRT || IL2CPP_TARGET_XBOXONE
|
||||
|
||||
#include "os/Win32/WindowsHeaders.h"
|
||||
#include <wrl.h>
|
||||
|
||||
#if WINDOWS_SDK_BUILD_VERSION < 16299 // This got readded on Windows 10 Fall Creators Update
|
||||
#define MAX_COMPUTERNAME_LENGTH 31
|
||||
#define GetComputerName GetComputerNameW
|
||||
#endif
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace winrt
|
||||
{
|
||||
inline DWORD WIN32_FROM_HRESULT(HRESULT hr)
|
||||
{
|
||||
if ((hr & 0xFFFF0000) == MAKE_HRESULT(SEVERITY_ERROR, FACILITY_WIN32, 0))
|
||||
return HRESULT_CODE(hr);
|
||||
if (hr == S_OK)
|
||||
return HRESULT_CODE(hr);
|
||||
return ERROR_SUCCESS;
|
||||
}
|
||||
|
||||
inline static BOOL CopyHStringToBuffer(Microsoft::WRL::Wrappers::HString& source, LPWSTR target, LPDWORD targetSize)
|
||||
{
|
||||
unsigned int sourceLength;
|
||||
auto sourceBuffer = source.GetRawBuffer(&sourceLength);
|
||||
|
||||
if (sourceLength + 1 > *targetSize)
|
||||
{
|
||||
SetLastError(ERROR_BUFFER_OVERFLOW);
|
||||
*targetSize = sourceLength + 1;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*targetSize = sourceLength;
|
||||
|
||||
if (target != nullptr)
|
||||
{
|
||||
memcpy(target, sourceBuffer, sourceLength * sizeof(wchar_t));
|
||||
target[sourceLength] = L'\0';
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if WINDOWS_SDK_BUILD_VERSION < 16299 // These APIs got readded on Windows 10 Fall Creators Update
|
||||
|
||||
extern "C"
|
||||
{
|
||||
inline BOOL WINAPI CopyFileW(LPCWSTR lpExistingFileName, LPCWSTR lpNewFileName, BOOL bFailIfExists)
|
||||
{
|
||||
COPYFILE2_EXTENDED_PARAMETERS params;
|
||||
|
||||
params.dwSize = sizeof(params);
|
||||
params.dwCopyFlags = bFailIfExists ? COPY_FILE_FAIL_IF_EXISTS : 0;
|
||||
params.pfCancel = FALSE;
|
||||
params.pProgressRoutine = nullptr;
|
||||
params.pvCallbackContext = nullptr;
|
||||
|
||||
auto hr = CopyFile2(lpExistingFileName, lpNewFileName, ¶ms);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
SetLastError(il2cpp::winrt::WIN32_FROM_HRESULT(hr));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
inline UINT WINAPI GetACP()
|
||||
{
|
||||
return CP_ACP;
|
||||
}
|
||||
|
||||
BOOL WINAPI GetComputerNameW(LPWSTR lpBuffer, LPDWORD nSize);
|
||||
} // extern "C"
|
||||
|
||||
#endif
|
||||
|
||||
#if WINDOWS_SDK_BUILD_VERSION < 15063
|
||||
|
||||
extern "C"
|
||||
{
|
||||
typedef struct
|
||||
{
|
||||
char String[4 * 4];
|
||||
} IP_ADDRESS_STRING, *PIP_ADDRESS_STRING, IP_MASK_STRING, *PIP_MASK_STRING;
|
||||
|
||||
typedef struct _IP_ADDR_STRING
|
||||
{
|
||||
struct _IP_ADDR_STRING* Next;
|
||||
IP_ADDRESS_STRING IpAddress;
|
||||
IP_MASK_STRING IpMask;
|
||||
DWORD Context;
|
||||
} IP_ADDR_STRING, *PIP_ADDR_STRING;
|
||||
|
||||
#define MAX_HOSTNAME_LEN 128
|
||||
#define MAX_DOMAIN_NAME_LEN 128
|
||||
#define MAX_SCOPE_ID_LEN 256
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char HostName[MAX_HOSTNAME_LEN + 4];
|
||||
char DomainName[MAX_DOMAIN_NAME_LEN + 4];
|
||||
PIP_ADDR_STRING CurrentDnsServer;
|
||||
IP_ADDR_STRING DnsServerList;
|
||||
UINT NodeType;
|
||||
char ScopeId[MAX_SCOPE_ID_LEN + 4];
|
||||
UINT EnableRouting;
|
||||
UINT EnableProxy;
|
||||
UINT EnableDns;
|
||||
} FIXED_INFO, *PFIXED_INFO;
|
||||
|
||||
DWORD WINAPI GetNetworkParams(PFIXED_INFO pFixedInfo, PULONG pOutBufLen);
|
||||
} // extern "C"
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_TARGET_WINRT
|
||||
|
||||
extern "C"
|
||||
{
|
||||
#if WINDOWS_SDK_BUILD_VERSION < 16299 // These APIs got readded on Windows 10 Fall Creators Update
|
||||
|
||||
#define CreateEvent CreateEventW
|
||||
#define FreeEnvironmentStrings FreeEnvironmentStringsW
|
||||
#define GetEnvironmentStrings GetEnvironmentStringsW
|
||||
#define GetEnvironmentVariable GetEnvironmentVariableW
|
||||
#define GetVersionEx GetVersionExW
|
||||
#define SetEnvironmentVariable SetEnvironmentVariableW
|
||||
|
||||
#endif
|
||||
|
||||
#define GetUserName GetUserNameW
|
||||
|
||||
#if WINDOWS_SDK_BUILD_VERSION < 16299
|
||||
|
||||
inline HANDLE WINAPI CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState, LPCWSTR lpName)
|
||||
{
|
||||
DWORD flags = 0;
|
||||
if (bManualReset)
|
||||
flags |= CREATE_EVENT_MANUAL_RESET;
|
||||
if (bInitialState)
|
||||
flags |= CREATE_EVENT_INITIAL_SET;
|
||||
return CreateEventExW(lpEventAttributes, lpName, flags, EVENT_ALL_ACCESS);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline HANDLE WINAPI CreateFileW(LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile)
|
||||
{
|
||||
const DWORD kFileAttributeMask = 0x0000FFFF;
|
||||
const DWORD kFileFlagMask = 0xFFFF0000;
|
||||
|
||||
CREATEFILE2_EXTENDED_PARAMETERS extendedParameters;
|
||||
extendedParameters.dwSize = sizeof(CREATEFILE2_EXTENDED_PARAMETERS);
|
||||
extendedParameters.dwFileAttributes = dwFlagsAndAttributes & kFileAttributeMask;
|
||||
extendedParameters.dwFileFlags = dwFlagsAndAttributes & kFileFlagMask;
|
||||
extendedParameters.dwSecurityQosFlags = SECURITY_ANONYMOUS;
|
||||
extendedParameters.lpSecurityAttributes = lpSecurityAttributes;
|
||||
extendedParameters.hTemplateFile = hTemplateFile;
|
||||
|
||||
return CreateFile2(lpFileName, dwDesiredAccess, dwShareMode, dwCreationDisposition, &extendedParameters);
|
||||
}
|
||||
|
||||
#if WINDOWS_SDK_BUILD_VERSION < 16299
|
||||
|
||||
BOOL WINAPI FreeEnvironmentStringsW(LPWCH strings);
|
||||
|
||||
LPWCH WINAPI GetEnvironmentStringsW();
|
||||
|
||||
DWORD WINAPI GetEnvironmentVariableW(LPCWSTR lpName, LPWSTR lpBuffer, DWORD nSize);
|
||||
|
||||
BOOL WINAPI GetVersionExW(LPOSVERSIONINFOW lpVersionInformation);
|
||||
|
||||
#endif
|
||||
|
||||
BOOL WINAPI GetUserNameW(LPWSTR lpBuffer, LPDWORD pcbBuffer);
|
||||
|
||||
inline HMODULE WINAPI LoadLibraryW(LPCWSTR lpLibFileName)
|
||||
{
|
||||
return LoadPackagedLibrary(lpLibFileName, 0);
|
||||
}
|
||||
|
||||
#if WINDOWS_SDK_BUILD_VERSION < 16299
|
||||
|
||||
BOOL WINAPI SetEnvironmentVariableW(LPCWSTR lpName, LPCWSTR lpValue);
|
||||
|
||||
#endif
|
||||
|
||||
#define CreateFileMappingW(hFile, lpFileMappingAttributes, flProtect, dwMaximumSizeHigh, dwMaximumSizeLow, lpName) \
|
||||
CreateFileMappingFromApp(hFile, lpFileMappingAttributes, flProtect, (static_cast<ULONG64>(dwMaximumSizeHigh) << 32) | dwMaximumSizeLow, lpName);
|
||||
|
||||
#define MapViewOfFile(hFileMappingObject, dwDesiredAccess, dwFileOffsetHigh, dwFileOffsetLow, dwNumberOfBytesToMap) \
|
||||
MapViewOfFileFromApp(hFileMappingObject, dwDesiredAccess, (static_cast<ULONG64>(dwFileOffsetHigh) << 32) | dwFileOffsetLow, dwNumberOfBytesToMap);
|
||||
|
||||
#if WINDOWS_SDK_BUILD_VERSION < 14393
|
||||
#define TlsAlloc() FlsAlloc(NULL)
|
||||
#define TlsGetValue FlsGetValue
|
||||
#define TlsSetValue FlsSetValue
|
||||
#define TlsFree FlsFree
|
||||
#endif
|
||||
} // extern "C"
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include "il2cpp-object-internals.h"
|
||||
#include "utils/StringView.h"
|
||||
|
||||
namespace il2cpp
|
||||
{
|
||||
namespace os
|
||||
{
|
||||
class LIBIL2CPP_CODEGEN_API WindowsRuntime
|
||||
{
|
||||
public:
|
||||
static il2cpp_hresult_t GetActivationFactory(Il2CppHString className, Il2CppIActivationFactory** activationFactory);
|
||||
|
||||
static il2cpp_hresult_t CreateHStringReference(const utils::StringView<Il2CppNativeChar>& str, Il2CppHStringHeader* header, Il2CppHString* hstring);
|
||||
static il2cpp_hresult_t CreateHString(const utils::StringView<Il2CppChar>& str, Il2CppHString* hstring);
|
||||
#if !IL2CPP_TARGET_WINDOWS // Il2CppChar and Il2CppNativeChar are the same on Windows
|
||||
static il2cpp_hresult_t CreateHString(const utils::StringView<Il2CppNativeChar>& str, Il2CppHString* hstring);
|
||||
#endif
|
||||
static il2cpp_hresult_t DeleteHString(Il2CppHString hstring);
|
||||
|
||||
static const Il2CppChar* GetHStringBuffer(Il2CppHString hstring, uint32_t* length);
|
||||
static const Il2CppNativeChar* GetNativeHStringBuffer(Il2CppHString hstring, uint32_t* length);
|
||||
static Il2CppString* HStringToManagedString(Il2CppHString hstring);
|
||||
|
||||
static il2cpp_hresult_t PreallocateHStringBuffer(uint32_t length, Il2CppNativeChar** mutableBuffer, void** bufferHandle);
|
||||
static il2cpp_hresult_t PromoteHStringBuffer(void* bufferHandle, Il2CppHString* hstring);
|
||||
static il2cpp_hresult_t DeleteHStringBuffer(void* bufferHandle);
|
||||
|
||||
static Il2CppIRestrictedErrorInfo* GetRestrictedErrorInfo();
|
||||
static void OriginateLanguageException(Il2CppException* ex, Il2CppString* exceptionString);
|
||||
|
||||
static void EnableErrorReporting();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void* (*allocate_func)(size_t size);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void register_allocator(allocate_func allocator);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class Allocator
|
||||
{
|
||||
public:
|
||||
static void* Allocate(size_t size);
|
||||
static char* CopyToAllocatedStringBuffer(const std::string& input);
|
||||
static char* CopyToAllocatedStringBuffer(const char* input);
|
||||
static void CopyStringVectorToNullTerminatedArray(const std::vector<std::string>& input, void*** output);
|
||||
static void CopyDataVectorToNullTerminatedArray(const std::vector<void*>& input, void*** output, int32_t elementSize);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,123 @@
|
||||
#pragma once
|
||||
|
||||
#include "il2cpp-config-platforms.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline int32_t UnityPalCompareExchange(volatile int32_t* dest, int32_t exchange, int32_t comparand);
|
||||
static inline int64_t UnityPalCompareExchange64(volatile int64_t* dest, int64_t exchange, int64_t comparand);
|
||||
static inline void* UnityPalCompareExchangePointer(void* volatile* dest, void* exchange, void* comparand);
|
||||
static inline int32_t UnityPalAdd(volatile int32_t* location1, int32_t value);
|
||||
static inline int64_t UnityPalAdd64(volatile int64_t* location1, int64_t value);
|
||||
static inline int32_t UnityPalIncrement(volatile int32_t* value);
|
||||
static inline int64_t UnityPalIncrement64(volatile int64_t* value);
|
||||
static inline int32_t UnityPalDecrement(volatile int32_t* value);
|
||||
static inline int64_t UnityPalDecrement64(volatile int64_t* value);
|
||||
static inline int32_t UnityPalExchange(volatile int32_t* dest, int32_t exchange);
|
||||
static inline int64_t UnityPalExchange64(volatile int64_t* dest, int64_t exchange);
|
||||
static inline void* UnityPalExchangePointer(void* volatile* dest, void* exchange);
|
||||
static inline int64_t UnityPalRead64(volatile int64_t* addr);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !IL2CPP_SUPPORT_THREADS
|
||||
|
||||
inline int32_t UnityPalAdd(volatile int32_t* location1, int32_t value)
|
||||
{
|
||||
return *location1 += value;
|
||||
}
|
||||
|
||||
inline int64_t UnityPalAdd64(volatile int64_t* location1, int64_t value)
|
||||
{
|
||||
return *location1 += value;
|
||||
}
|
||||
|
||||
inline int32_t UnityPalIncrement(volatile int32_t* value)
|
||||
{
|
||||
return ++(*value);
|
||||
}
|
||||
|
||||
inline int64_t UnityPalIncrement64(volatile int64_t* value)
|
||||
{
|
||||
return ++(*value);
|
||||
}
|
||||
|
||||
inline int32_t UnityPalDecrement(volatile int32_t* value)
|
||||
{
|
||||
return --(*value);
|
||||
}
|
||||
|
||||
inline int64_t UnityPalDecrement64(volatile int64_t* value)
|
||||
{
|
||||
return --(*value);
|
||||
}
|
||||
|
||||
inline int32_t UnityPalCompareExchange(volatile int32_t* dest, int32_t exchange, int32_t comparand)
|
||||
{
|
||||
int32_t orig = *dest;
|
||||
if (*dest == comparand)
|
||||
*dest = exchange;
|
||||
|
||||
return orig;
|
||||
}
|
||||
|
||||
inline int64_t UnityPalCompareExchange64(volatile int64_t* dest, int64_t exchange, int64_t comparand)
|
||||
{
|
||||
int64_t orig = *dest;
|
||||
if (*dest == comparand)
|
||||
*dest = exchange;
|
||||
|
||||
return orig;
|
||||
}
|
||||
|
||||
inline void* UnityPalCompareExchangePointer(void* volatile* dest, void* exchange, void* comparand)
|
||||
{
|
||||
void* orig = *dest;
|
||||
if (*dest == comparand)
|
||||
*dest = exchange;
|
||||
|
||||
return orig;
|
||||
}
|
||||
|
||||
inline int64_t UnityPalExchange64(volatile int64_t* dest, int64_t exchange)
|
||||
{
|
||||
int64_t orig = *dest;
|
||||
*dest = exchange;
|
||||
return orig;
|
||||
}
|
||||
|
||||
inline int32_t UnityPalExchange(volatile int32_t* dest, int32_t exchange)
|
||||
{
|
||||
int32_t orig = *dest;
|
||||
*dest = exchange;
|
||||
return orig;
|
||||
}
|
||||
|
||||
inline void* UnityPalExchangePointer(void* volatile* dest, void* exchange)
|
||||
{
|
||||
void* orig = *dest;
|
||||
*dest = exchange;
|
||||
return orig;
|
||||
}
|
||||
|
||||
int64_t UnityPalRead64(volatile int64_t* addr)
|
||||
{
|
||||
return *addr;
|
||||
}
|
||||
|
||||
#elif IL2CPP_TARGET_WINDOWS
|
||||
#include "Win32/AtomicImpl-c-api.h"
|
||||
#elif IL2CPP_TARGET_PS4
|
||||
#include "PS4/AtomicImpl-c-api.h" // has to come earlier than posix
|
||||
#elif IL2CPP_TARGET_PSP2
|
||||
#include "PSP2/AtomicImpl-c-api.h"
|
||||
#elif IL2CPP_TARGET_POSIX
|
||||
#include "Posix/AtomicImpl-c-api.h"
|
||||
#else
|
||||
#include "AtomicImpl-c-api.h"
|
||||
#endif
|
||||
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
#include "os/COM.h"
|
||||
|
||||
typedef Il2CppGuid UnityPalIl2CppGuid;
|
||||
typedef Il2CppIUnknown UnityPalIl2CppIUnknown;
|
||||
typedef Il2CppVariant UnityPalIl2CppVariant;
|
||||
typedef Il2CppSafeArray UnityPalIl2CppSafeArray;
|
||||
typedef Il2CppSafeArrayBound UnityPalIl2CppSafeArrayBound;
|
||||
|
||||
#else
|
||||
|
||||
typedef struct UnityPalIl2CppGuid UnityPalIl2CppGuid;
|
||||
typedef struct UnityPalIl2CppIUnknown UnityPalIl2CppIUnknown;
|
||||
typedef struct UnityPalIl2CppVariant UnityPalIl2CppVariant;
|
||||
typedef struct UnityPalIl2CppSafeArray UnityPalIl2CppSafeArray;
|
||||
typedef struct UnityPalIl2CppSafeArrayBound UnityPalIl2CppSafeArrayBound;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
il2cpp_hresult_t UnityPalCOMCreateInstance(const UnityPalIl2CppGuid& clsid, UnityPalIl2CppIUnknown** object);
|
||||
il2cpp_hresult_t UnityPalCOMCreateFreeThreadedMarshaler(UnityPalIl2CppIUnknown* outer, UnityPalIl2CppIUnknown** marshal);
|
||||
|
||||
void UnityPalCOMVariantInit(UnityPalIl2CppVariant* variant);
|
||||
il2cpp_hresult_t UnityPalCOMVariantClear(UnityPalIl2CppVariant* variant);
|
||||
|
||||
UnityPalIl2CppSafeArray* UnityPalCOMSafeArrayCreate(uint16_t type, uint32_t dimension_count, UnityPalIl2CppSafeArrayBound* bounds);
|
||||
il2cpp_hresult_t UnityPalCOMSafeArrayDestroy(UnityPalIl2CppSafeArray* safeArray);
|
||||
il2cpp_hresult_t UnityPalCOMSafeArrayAccessData(UnityPalIl2CppSafeArray* safeArray, void** data);
|
||||
il2cpp_hresult_t UnityPalCOMSafeArrayUnaccessData(UnityPalIl2CppSafeArray* safeArray);
|
||||
il2cpp_hresult_t UnityPalCOMSafeArrayGetVartype(UnityPalIl2CppSafeArray* safeArray, uint16_t* type);
|
||||
uint32_t UnityPalCOMSafeArrayGetDim(UnityPalIl2CppSafeArray* safeArray);
|
||||
il2cpp_hresult_t UnityPalCOMSafeArrayGetLBound(UnityPalIl2CppSafeArray* safeArray, uint32_t dimention, int32_t* bound);
|
||||
il2cpp_hresult_t UnityPalCOMSafeArrayGetUBound(UnityPalIl2CppSafeArray* safeArray, uint32_t dimention, int32_t* bound);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "Mutex-c-api.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#if NET_4_0
|
||||
#include "os/ConditionVariable.h"
|
||||
typedef il2cpp::os::ConditionVariable UnityPalConditionVariable;
|
||||
#endif
|
||||
#else
|
||||
typedef struct UnityPalConditionVariable UnityPalConditionVariable;
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
UnityPalConditionVariable* UnityPalConditionVariableNew();
|
||||
void UnityPalConditionVariableDelete(UnityPalConditionVariable* object);
|
||||
|
||||
int UnityPalConditionVariableWait(UnityPalConditionVariable* object, UnityPalFastMutex* lock);
|
||||
int UnityPalConditionVariableTimedWait(UnityPalConditionVariable* object, UnityPalFastMutex* lock, uint32_t timeout_ms);
|
||||
void UnityPalConditionVariableBroadcast(UnityPalConditionVariable* object);
|
||||
void UnityPalConditionVariableSignal(UnityPalConditionVariable* object);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int32_t UnityPalConsoleInternalKeyAvailable(int32_t ms_timeout);
|
||||
int32_t UnityPalConsoleSetBreak(int32_t wantBreak);
|
||||
int32_t UnityPalConsoleSetEcho(int32_t wantEcho);
|
||||
int32_t UnityPalConsoleTtySetup(const char* keypadXmit, const char* teardown, uint8_t* control_characters, int32_t** size);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void* UnityPalCpuInfoCreate();
|
||||
int32_t UnityPalCpuInfoUsage(void* previous);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void* UnityPalGetCryptographyProvider();
|
||||
|
||||
int32_t UnityPalOpenCryptographyProvider();
|
||||
|
||||
void UnityPalReleaseCryptographyProvider(void* provider);
|
||||
|
||||
int32_t UnityPalCryptographyFillBufferWithRandomBytes(void* provider, uint32_t length, unsigned char* data);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int32_t UnityPalIsDebuggerPresent();
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,40 @@
|
||||
#pragma once
|
||||
|
||||
#include "Error-c-api.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include "os/Directory.h"
|
||||
typedef il2cpp::os::Directory::FindHandle UnityPalFindHandle;
|
||||
|
||||
#else
|
||||
|
||||
typedef struct UnityPalFindHandle UnityPalFindHandle;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
const char* UnityPalDirectoryGetCurrent(int* error);
|
||||
int32_t UnityPalDirectorySetCurrent(const char* path, int* error);
|
||||
int32_t UnityPalDirectoryCreate(const char* path, int *error);
|
||||
int32_t UnityPalDirectoryRemove(const char* path, int *error);
|
||||
|
||||
void UnityPalDirectoryGetFileSystemEntries(const char* path, const char* pathWithPattern, int32_t attrs, int32_t mask, int* error, char*** entries, int32_t* numEntries);
|
||||
|
||||
|
||||
UnityPalFindHandle* UnityPalDirectoryFindHandleNew(const char* searchPathWithPattern);
|
||||
void UnityPalDirectoryFindHandleDelete(UnityPalFindHandle* object);
|
||||
|
||||
int32_t UnityPalDirectoryCloseOSHandle(UnityPalFindHandle* object);
|
||||
void* UnityPalDirectoryGetOSHandle(UnityPalFindHandle* object);
|
||||
|
||||
UnityPalErrorCode UnityPalDirectoryFindFirstFile(UnityPalFindHandle* findHandle, const char* searchPathWithPattern, char** resultFileName, int32_t* resultAttributes);
|
||||
UnityPalErrorCode UnityPalDirectoryFindNextFile(UnityPalFindHandle* findHandle, char** resultFileName, int32_t* resultAttributes);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
char* UnityPalGetOsUserName();
|
||||
char* UnityPalGetMachineName();
|
||||
char* UnityPalGetEnvironmentVariable(const char* name);
|
||||
void UnityPalSetEnvironmentVariable(const char* name, const char* value);
|
||||
char* UnityPalGetHomeDirectory();
|
||||
int32_t UnityPalGetProcessorCount();
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include "os/Error.h"
|
||||
typedef il2cpp::os::ErrorCode UnityPalErrorCode;
|
||||
|
||||
#else
|
||||
|
||||
typedef int32_t UnityPalErrorCode;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
UnityPalErrorCode UnityPalGetLastError();
|
||||
void UnityPalSetLastError(UnityPalErrorCode code);
|
||||
int32_t UnityPalSuccess(UnityPalErrorCode code);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
#pragma once
|
||||
|
||||
#include "Error-c-api.h"
|
||||
#include "WaitStatus-c-api.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include "os/Event.h"
|
||||
typedef il2cpp::os::Event UnityPalEvent;
|
||||
typedef il2cpp::os::EventHandle UnityPalEventHandle;
|
||||
#else
|
||||
typedef struct UnityPalEvent UnityPalEvent;
|
||||
typedef struct UnityPalEventHandle UnityPalEventHandle;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
UnityPalEvent* UnityPalEventNew(int32_t manualReset, int32_t signaled);
|
||||
void UnityPalEventDelete(UnityPalEvent* event);
|
||||
UnityPalErrorCode UnityPalEventSet(UnityPalEvent* event);
|
||||
UnityPalErrorCode UnityPalEventReset(UnityPalEvent* event);
|
||||
UnityPalWaitStatus UnityPalEventWait(UnityPalEvent* event, int32_t interruptible);
|
||||
UnityPalWaitStatus UnityPalEventWaitMs(UnityPalEvent* event, uint32_t ms, int32_t interruptible);
|
||||
|
||||
UnityPalEventHandle* UnityPalEventHandleNew(UnityPalEvent* Event);
|
||||
void UnityPalEventHandleDelete(UnityPalEventHandle* Event);
|
||||
int32_t UnityPalEventHandleWait(UnityPalEventHandle* handle);
|
||||
int32_t UnityPalEventHandleWaitMs(UnityPalEventHandle* handle, uint32_t ms);
|
||||
void UnityPalEventHandleSignal(UnityPalEventHandle* handle);
|
||||
UnityPalEvent* UnityPalEventHandleGet(UnityPalEventHandle* handle);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,64 @@
|
||||
#pragma once
|
||||
|
||||
#include "OSGlobalEnums.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include "os/ErrorCodes.h"
|
||||
#include "os/File.h"
|
||||
|
||||
typedef il2cpp::os::FileHandle UnityPalFileHandle;
|
||||
|
||||
#else
|
||||
|
||||
typedef struct UnityPalFileHandle UnityPalFileHandle;
|
||||
|
||||
#endif //__cplusplus
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char* name;
|
||||
int32_t attributes;
|
||||
int64_t length;
|
||||
int64_t creation_time;
|
||||
int64_t last_access_time;
|
||||
int64_t last_write_time;
|
||||
} UnityPalFileStat;
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int32_t UnityPalIsatty(UnityPalFileHandle* fileHandle);
|
||||
UnityPalFileHandle* UnityPalGetStdInput();
|
||||
UnityPalFileHandle* UnityPalGetStdOutput();
|
||||
UnityPalFileHandle* UnityPalGetStdError();
|
||||
int32_t UnityPalCreatePipe(UnityPalFileHandle** read_handle, UnityPalFileHandle** write_handle);
|
||||
int32_t UnityPalCreatePipe_with_error(UnityPalFileHandle** read_handle, UnityPalFileHandle** write_handle, int* error);
|
||||
FileType UnityPalGetFileType(UnityPalFileHandle* handle);
|
||||
UnityPalFileAttributes UnityPalGetFileAttributes(const char* path, int* error);
|
||||
int32_t UnityPalSetFileAttributes(const char* path, UnityPalFileAttributes attributes, int* error);
|
||||
int32_t UnityPalGetFileStat(const char* path, UnityPalFileStat * stat, int* error);
|
||||
int32_t UnityPalCopyFile(const char* src, const char* dest, int32_t overwrite, int* error);
|
||||
int32_t UnityPalMoveFile(const char* src, const char* dest, int* error);
|
||||
int32_t UnityPalDeleteFile(const char* path, int *error);
|
||||
int32_t UnityPalReplaceFile(const char* sourceFileName, const char* destinationFileName, const char* destinationBackupFileName, int32_t ignoreMetadataErrors, int* error);
|
||||
UnityPalFileHandle* UnityPalOpen(const char* path, int openMode, int accessMode, int shareMode, int options, int *error);
|
||||
int32_t UnityPalClose(UnityPalFileHandle* handle, int *error);
|
||||
int32_t UnityPalSetFileTime(UnityPalFileHandle* handle, int64_t creation_time, int64_t last_access_time, int64_t last_write_time, int* error);
|
||||
int64_t UnityPalGetLength(UnityPalFileHandle* handle, int *error);
|
||||
int32_t UnityPalSetLength(UnityPalFileHandle* handle, int64_t length, int *error);
|
||||
int32_t UnityPalTruncate(UnityPalFileHandle* handle, int *error);
|
||||
int64_t UnityPalSeek(UnityPalFileHandle* handle, int64_t offset, int origin, int *error);
|
||||
int UnityPalRead(UnityPalFileHandle* handle, char *dest, int count, int *error);
|
||||
int32_t UnityPalWrite(UnityPalFileHandle* handle, const char* buffer, int count, int *error);
|
||||
int32_t UnityPalFlush(UnityPalFileHandle* handle, int* error);
|
||||
void UnityPalLock(UnityPalFileHandle* handle, int64_t position, int64_t length, int* error);
|
||||
void UnityPalUnlock(UnityPalFileHandle* handle, int64_t position, int64_t length, int* error);
|
||||
int32_t UnityPalDuplicateHandle(UnityPalFileHandle* source_process_handle, UnityPalFileHandle* source_handle, UnityPalFileHandle* target_process_handle,
|
||||
UnityPalFileHandle** target_handle, int access, int inherit, int options, int* error);
|
||||
int32_t UnityPalIsExecutable(const char* filename);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "WaitStatus-c-api.h"
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include "os/Handle.h"
|
||||
typedef il2cpp::os::Handle UnityPalHandle;
|
||||
#else
|
||||
typedef struct UnityPalHandle UnityPalHandle;
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void UnityPalHandleDestroy(UnityPalHandle* handle);
|
||||
UnityPalWaitStatus UnityPalHandleWait(UnityPalHandle* handle, int32_t interruptible);
|
||||
UnityPalWaitStatus UnityPalHandleWaitMs(UnityPalHandle* handle, uint32_t ms, int32_t interruptible);
|
||||
UnityPalWaitStatus UnityPalHandleSignalAndWait(UnityPalHandle* toSignal, UnityPalHandle* toWait, uint32_t ms, int32_t interruptible);
|
||||
UnityPalWaitStatus UnityPalWaitForMultipleHandles(UnityPalHandle** handles, size_t numberOfHandlers, int32_t waitAll, uint32_t ms, int32_t interruptible);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include "os/LibraryLoader.h"
|
||||
typedef Il2CppMethodPointer UnityPalMethodPointer;
|
||||
#else
|
||||
typedef void (*UnityPalMethodPointer)();
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void* UnityPalLibraryLoaderLoadDynamicLibrary(const char* nativeDynamicLibrary, int flags);
|
||||
void UnityPalLibraryLoaderCleanupLoadedLibraries();
|
||||
UnityPalMethodPointer UnityPalLibraryLoaderGetFunctionPointer(void* dynamicLibrary, const char* functionName);
|
||||
int32_t UnityPalLibraryLoaderCloseLoadedLibrary(void** dynamicLibrary);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void UnityPalLocaleInitialize();
|
||||
void UnityPalLocaleUnInitialize();
|
||||
char* UnityPalGetLocale();
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void* UnityPalAlignedAlloc(size_t size, size_t alignment);
|
||||
void* UnityPalAlignedReAlloc(void* memory, size_t newSize, size_t alignment);
|
||||
void UnityPalAlignedFree(void* memory);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "File-c-api.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void* UnityPalMemoryMappedFileMap(UnityPalFileHandle* file);
|
||||
void UnityPalMemoryMappedFileUnmap(void* address);
|
||||
|
||||
void* UnityPalMemoryMappedFileMapWithParams(UnityPalFileHandle* file, int64_t length, int64_t offset);
|
||||
void UnityPalMemoryMappedFileUnmapWithParams(void* address, int64_t length);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
#include "os/c-api/Error-c-api.h"
|
||||
#include "os/c-api/Messages-c-api.h"
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
char* UnityPalMessagesFromCode(UnityPalErrorCode code);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,44 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include "os/Mutex.h"
|
||||
#include "os/WaitStatus.h"
|
||||
typedef il2cpp::os::Mutex UnityPalMutex;
|
||||
typedef il2cpp::os::MutexHandle UnityPalMutexHandle;
|
||||
typedef il2cpp::os::FastMutex UnityPalFastMutex;
|
||||
typedef il2cpp::os::FastMutexImpl UnityPalFastMutexImpl;
|
||||
#else
|
||||
typedef struct UnityPalMutex UnityPalMutex;
|
||||
typedef struct UnityPalMutexHandle UnityPalMutexHandle;
|
||||
typedef struct UnityPalFastMutex UnityPalFastMutex;
|
||||
typedef struct UnityPalFastMutexImpl UnityPalFastMutexImpl;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
UnityPalMutex* UnityPalMutexNew(int32_t initiallyOwned);
|
||||
void UnityPalMutexDelete(UnityPalMutex* mutex);
|
||||
void UnityPalMutexLock(UnityPalMutex* mutex, int32_t interruptible);
|
||||
int32_t UnityPalMutexTryLock(UnityPalMutex* mutex, uint32_t milliseconds, int32_t interruptible);
|
||||
void UnityPalMutexUnlock(UnityPalMutex* mutex);
|
||||
|
||||
UnityPalMutexHandle* UnityPalMutexHandleNew(UnityPalMutex* mutex);
|
||||
void UnityPalMutexHandleDelete(UnityPalMutexHandle* mutex);
|
||||
int32_t UnityPalMutexHandleWait(UnityPalMutexHandle* handle);
|
||||
int32_t UnityPalMutexHandleWaitMs(UnityPalMutexHandle* handle, uint32_t ms);
|
||||
void UnityPalMutexHandleSignal(UnityPalMutexHandle* handle);
|
||||
UnityPalMutex* UnityPalMutexHandleGet(UnityPalMutexHandle* handle);
|
||||
|
||||
UnityPalFastMutex* UnityPalFastMutexNew();
|
||||
void UnityPalFastMutexDelete(UnityPalFastMutex* fastMutex);
|
||||
void UnityPalFastMutexLock(UnityPalFastMutex* fastMutex);
|
||||
void UnityPalFastMutexUnlock(UnityPalFastMutex* fastMutex);
|
||||
UnityPalFastMutexImpl* UnityPalFastMutexGetImpl(UnityPalFastMutex* fastMutex);
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "os/c-api/Process_c_api.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int32_t UnityPalNativeCloseProcess(UnityPalProcessHandle* handle);
|
||||
int32_t UnityPalNativeGetExitCodeProcess(UnityPalProcessHandle* handle, int32_t* exitCode);
|
||||
int32_t UnityPalNativeGetCurrentProcessId();
|
||||
UnityPalProcessHandle* UnityPalNativeGetCurrentProcess();
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,77 @@
|
||||
#pragma once
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kFileTypeUnknown = 0x0000,
|
||||
kFileTypeDisk = 0x0001,
|
||||
kFileTypeChar = 0x0002,
|
||||
kFileTypePipe = 0x0003,
|
||||
kFileTypeRemote = 0x8000
|
||||
} FileType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kFileAttributeReadOnly = 0x00000001,
|
||||
kFileAttributeHidden = 0x00000002,
|
||||
kFileAttributeSystem = 0x00000004,
|
||||
kFileAttributeDirectory = 0x00000010,
|
||||
kFileAttributeArchive = 0x00000020,
|
||||
kFileAttributeDevice = 0x00000040,
|
||||
kFileAttributeNormal = 0x00000080,
|
||||
kFileAttributeTemporary = 0x00000100,
|
||||
kFileAttributeSparse_file = 0x00000200,
|
||||
kFileAttributeReparse_point = 0x00000400,
|
||||
kFileAttributeCompressed = 0x00000800,
|
||||
kFileAttributeOffline = 0x00001000,
|
||||
kFileAttributeNot_content_indexed = 0x00002000,
|
||||
kFileAttributeEncrypted = 0x00004000,
|
||||
kFileAttributeVirtual = 0x00010000,
|
||||
kFileAttributeInternalMonoExecutable = 0x80000000 // Only used internally by Mono
|
||||
} UnityPalFileAttributes;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kFileAccessRead = 0x01,
|
||||
kFileAccessWrite = 0x02,
|
||||
kFileAccessExecute = 0x04,
|
||||
kFileAccessReadWrite = kFileAccessRead | kFileAccessWrite,
|
||||
kFileAccessReadWriteExecute = kFileAccessRead | kFileAccessWrite | kFileAccessExecute
|
||||
} FileAccess;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kFileModeCreateNew = 1,
|
||||
kFileModeCreate = 2,
|
||||
kFileModeOpen = 3,
|
||||
kFileModeOpenOrCreate = 4,
|
||||
kFileModeTruncate = 5,
|
||||
kFileModeAppend = 6
|
||||
} FileMode;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kFileShareNone = 0x0,
|
||||
kFileShareRead = 0x01,
|
||||
kFileShareWrite = 0x02,
|
||||
kFileShareReadWrite = kFileShareRead | kFileShareWrite,
|
||||
kFileShareDelete = 0x04
|
||||
} FileShare;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kFileOptionsNone = 0,
|
||||
kFileOptionsTemporary = 1, // Internal. See note in System.IO.FileOptions
|
||||
kFileOptionsEncrypted = 0x4000,
|
||||
kFileOptionsDeleteOnClose = 0x4000000,
|
||||
kFileOptionsSequentialScan = 0x8000000,
|
||||
kFileOptionsRandomAccess = 0x10000000,
|
||||
kFileOptionsAsynchronous = 0x40000000,
|
||||
kFileOptionsWriteThrough = 0x80000000
|
||||
} FileOptions;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kFileSeekOriginBegin = 0,
|
||||
kFileSeekOriginCurrent = 1,
|
||||
kFileSeekOriginEnd = 2
|
||||
} SeekOrigin;
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
char* UnityPalGetExecutablePath();
|
||||
char* UnityPalGetTempPath();
|
||||
int32_t UnityPalIsAbsolutePath(const char* path);
|
||||
char* UnityPalBasename(const char* path);
|
||||
char* UnityPalDirectoryName(const char* path);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,119 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
#include <emscripten/threading.h>
|
||||
#endif
|
||||
|
||||
inline int32_t UnityPalAdd(volatile int32_t* location1, int32_t value)
|
||||
{
|
||||
ASSERT_ALIGNMENT(location1, 4);
|
||||
return __sync_add_and_fetch(location1, value);
|
||||
}
|
||||
|
||||
inline int64_t UnityPalAdd64(volatile int64_t* location1, int64_t value)
|
||||
{
|
||||
ASSERT_ALIGNMENT(location1, 8);
|
||||
return __sync_add_and_fetch(location1, value);
|
||||
}
|
||||
|
||||
inline int32_t UnityPalIncrement(volatile int32_t* value)
|
||||
{
|
||||
ASSERT_ALIGNMENT(value, 4);
|
||||
return __sync_add_and_fetch(value, 1);
|
||||
}
|
||||
|
||||
inline int64_t UnityPalIncrement64(volatile int64_t* value)
|
||||
{
|
||||
ASSERT_ALIGNMENT(value, 8);
|
||||
return __sync_add_and_fetch(value, 1);
|
||||
}
|
||||
|
||||
inline int32_t UnityPalDecrement(volatile int32_t* value)
|
||||
{
|
||||
ASSERT_ALIGNMENT(value, 4);
|
||||
return __sync_add_and_fetch(value, -1);
|
||||
}
|
||||
|
||||
inline int64_t UnityPalDecrement64(volatile int64_t* value)
|
||||
{
|
||||
ASSERT_ALIGNMENT(value, 8);
|
||||
return __sync_add_and_fetch(value, -1);
|
||||
}
|
||||
|
||||
inline int32_t UnityPalCompareExchange(volatile int32_t* dest, int32_t exchange, int32_t comparand)
|
||||
{
|
||||
ASSERT_ALIGNMENT(dest, 4);
|
||||
return __sync_val_compare_and_swap(dest, comparand, exchange);
|
||||
}
|
||||
|
||||
inline int64_t UnityPalCompareExchange64(volatile int64_t* dest, int64_t exchange, int64_t comparand)
|
||||
{
|
||||
ASSERT_ALIGNMENT(dest, 8);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return emscripten_atomic_cas_u64((void*)dest, comparand, exchange) == comparand ? comparand : *dest;
|
||||
#else
|
||||
return __sync_val_compare_and_swap(dest, comparand, exchange);
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void* UnityPalCompareExchangePointer(void* volatile* dest, void* exchange, void* comparand)
|
||||
{
|
||||
ASSERT_ALIGNMENT(dest, IL2CPP_SIZEOF_VOID_P);
|
||||
return __sync_val_compare_and_swap(dest, comparand, exchange);
|
||||
}
|
||||
|
||||
inline int32_t UnityPalExchange(volatile int32_t* dest, int32_t exchange)
|
||||
{
|
||||
ASSERT_ALIGNMENT(dest, 4);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return emscripten_atomic_exchange_u32((void*)dest, exchange);
|
||||
#else
|
||||
int32_t prev;
|
||||
do
|
||||
{
|
||||
prev = *dest;
|
||||
}
|
||||
while (!__sync_bool_compare_and_swap(dest, prev, exchange));
|
||||
return prev;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int64_t UnityPalExchange64(volatile int64_t* dest, int64_t exchange)
|
||||
{
|
||||
ASSERT_ALIGNMENT(dest, 8);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return emscripten_atomic_exchange_u64((void*)dest, exchange);
|
||||
#else
|
||||
int64_t prev;
|
||||
do
|
||||
{
|
||||
prev = *dest;
|
||||
}
|
||||
while (!__sync_bool_compare_and_swap(dest, prev, exchange));
|
||||
return prev;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline void* UnityPalExchangePointer(void* volatile* dest, void* exchange)
|
||||
{
|
||||
ASSERT_ALIGNMENT(dest, IL2CPP_SIZEOF_VOID_P);
|
||||
#ifdef __EMSCRIPTEN__
|
||||
return (void*)emscripten_atomic_exchange_u32((void*)dest, (uint32_t)exchange);
|
||||
#else
|
||||
void* prev;
|
||||
do
|
||||
{
|
||||
prev = *dest;
|
||||
}
|
||||
while (!__sync_bool_compare_and_swap(dest, prev, exchange));
|
||||
return prev;
|
||||
#endif
|
||||
}
|
||||
|
||||
inline int64_t UnityPalRead64(volatile int64_t* addr)
|
||||
{
|
||||
ASSERT_ALIGNMENT(addr, 8);
|
||||
return __sync_fetch_and_add(addr, 0);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#if defined(__cplusplus)
|
||||
|
||||
typedef il2cpp::os::ProcessHandle UnityPalProcessHandle;
|
||||
|
||||
#else
|
||||
|
||||
typedef struct UnityPalProcessHandle UnityPalProcessHandle;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int UnityPalGetCurrentProcessId();
|
||||
UnityPalProcessHandle* UnityPalGetProcess(int processId);
|
||||
void UnityPalFreeProcess(UnityPalProcessHandle* handle);
|
||||
const char* UnityPalGetProcessName(UnityPalProcessHandle* handle);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
|
||||
#include "WaitStatus-c-api.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include "os/Semaphore.h"
|
||||
typedef il2cpp::os::Semaphore UnityPalSemaphore;
|
||||
typedef il2cpp::os::SemaphoreHandle UnityPalSemaphoreHandle;
|
||||
#else
|
||||
typedef struct UnityPalSemaphore UnityPalSemaphore;
|
||||
typedef struct UnityPalSemaphoreHandle UnityPalSemaphoreHandle;
|
||||
#endif
|
||||
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
UnityPalSemaphore* UnityPalSemaphoreNew(int32_t initialValue, int32_t maximumValue);
|
||||
void UnityPalSemaphoreDelete(UnityPalSemaphore* semaphore);
|
||||
int32_t UnityPalSemaphorePost(UnityPalSemaphore* semaphore, int32_t releaseCount, int32_t* previousCount);
|
||||
UnityPalWaitStatus UnityPalSemaphoreWait(UnityPalSemaphore* semaphore, int32_t interruptible);
|
||||
UnityPalWaitStatus UnityPalSemaphoreWaitMs(UnityPalSemaphore* semaphore, uint32_t ms, int32_t interruptible);
|
||||
|
||||
UnityPalSemaphoreHandle* UnityPalSemaphoreHandleNew(UnityPalSemaphore* semaphore);
|
||||
void UnityPalSemaphoreHandleDelete(UnityPalSemaphoreHandle* handle);
|
||||
int32_t UnityPalSemaphoreHandleWait(UnityPalSemaphoreHandle* handle);
|
||||
int32_t UnityPalSemaphoreHandleWaitMs(UnityPalSemaphoreHandle* handle, uint32_t ms);
|
||||
void UnityPalSemaphoreHandleSignal(UnityPalSemaphoreHandle* handle);
|
||||
UnityPalSemaphore* UnityPalSemaphoreHandleGet(UnityPalSemaphoreHandle* handle);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "WaitStatus-c-api.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include "os/Socket.h"
|
||||
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#endif //__cplusplus
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
UnityPalWaitStatus UnityPalGetHostByName(const char* host, char** name, int32_t* family, char*** aliases, void*** address_list, int32_t* address_size);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void* UnityPalSystemCertificatesOpenSystemRootStore();
|
||||
int UnityPalSystemCertificatesEnumSystemCertificates(void* certStore, void** iter, int *format, int* size, void** data);
|
||||
void UnityPalSystemCertificatesCloseSystemRootStore(void* cStore);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include "os/Thread.h"
|
||||
|
||||
typedef il2cpp::os::Thread::ThreadId UnityPalThreadId;
|
||||
|
||||
#else
|
||||
|
||||
typedef uint64_t UnityPalThreadId;
|
||||
|
||||
#endif //__cplusplus
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
void UnityPalThreadInitialize();
|
||||
void UnityPalSleep(uint32_t milliseconds);
|
||||
UnityPalThreadId UnityPalGetCurrentThreadId();
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include "os/c-api/Error-c-api.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
#include "os/ThreadLocalValue.h"
|
||||
typedef il2cpp::os::ThreadLocalValue UnityPalThreadLocalValue;
|
||||
|
||||
#else
|
||||
|
||||
typedef struct UnityPalThreadLocalValue UnityPalThreadLocalValue;
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
UnityPalThreadLocalValue* UnityPalThreadLocalValueNew();
|
||||
void UnityPalThreadLocalValueDelete(UnityPalThreadLocalValue* object);
|
||||
|
||||
UnityPalErrorCode UnityPalThreadLocalValueSetValue(UnityPalThreadLocalValue* object, void* value);
|
||||
UnityPalErrorCode UnityPalThreadLocalValueGetValue(UnityPalThreadLocalValue* object, void** value);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
uint32_t UnityPalGetTicksMillisecondsMonotonic();
|
||||
int64_t UnityPalGetTicks100NanosecondsMonotonic();
|
||||
int64_t UnityPalGetTicks100NanosecondsDateTime();
|
||||
int64_t UnityPalGetSystemTimeAsFileTime();
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
int32_t UnityPalGetTimeZoneData(int32_t year, int64_t data[4], const char* names[2]);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#include "il2cpp-config-platforms.h"
|
||||
#include "il2cpp-config-api-platforms.h"
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
IL2CPP_EXPORT int UseUnityPalForTimeZoneInformation();
|
||||
IL2CPP_EXPORT void* UnityPalTimeZoneInfoGetTimeZoneIDs();
|
||||
IL2CPP_EXPORT int UnityPalGetLocalTimeZoneData(void** nativeRawData, char** nativeID, int* size);
|
||||
IL2CPP_EXPORT int UnityPalGetTimeZoneDataForID(char* id, void** nativeRawData, int* size);
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
// This should match MonoW32HandleWaitRet in the Mono code.
|
||||
|
||||
#define MAXIMUM_WAIT_OBJECTS 64
|
||||
|
||||
typedef enum
|
||||
{
|
||||
kWaitStatusSuccess = 0,
|
||||
kWaitStatusAbandoned = kWaitStatusSuccess + MAXIMUM_WAIT_OBJECTS,
|
||||
kWaitStatusAlerted = -1,
|
||||
kWaitStatusTimeout = -2,
|
||||
kWaitStatusFailure = -3,
|
||||
} UnityPalWaitStatus;
|
||||
@@ -0,0 +1,82 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#define INC_OLE2 1
|
||||
#include <Windows.h>
|
||||
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
static inline int32_t UnityPalCompareExchange(volatile int32_t* dest, int32_t exchange, int32_t comparand)
|
||||
{
|
||||
return InterlockedCompareExchange((long volatile*)dest, exchange, comparand);
|
||||
}
|
||||
|
||||
static inline int64_t UnityPalCompareExchange64(volatile int64_t* dest, int64_t exchange, int64_t comparand)
|
||||
{
|
||||
return InterlockedCompareExchange64((long long volatile*)dest, exchange, comparand);
|
||||
}
|
||||
|
||||
static inline void* UnityPalCompareExchangePointer(void* volatile* dest, void* exchange, void* comparand)
|
||||
{
|
||||
return InterlockedCompareExchangePointer(dest, exchange, comparand);
|
||||
}
|
||||
|
||||
static inline int32_t UnityPalAdd(volatile int32_t* location1, int32_t value)
|
||||
{
|
||||
return (InterlockedExchangeAdd((long volatile*)location1, value) + value);
|
||||
}
|
||||
|
||||
static inline int64_t UnityPalAdd64(volatile int64_t* location1, int64_t value)
|
||||
{
|
||||
return (InterlockedExchangeAdd64((long long volatile*)location1, value) + value);
|
||||
}
|
||||
|
||||
static inline int32_t UnityPalIncrement(volatile int32_t* value)
|
||||
{
|
||||
return InterlockedIncrement((long volatile*)value);
|
||||
}
|
||||
|
||||
static inline int64_t UnityPalIncrement64(volatile int64_t* value)
|
||||
{
|
||||
return InterlockedIncrement64(value);
|
||||
}
|
||||
|
||||
static inline int32_t UnityPalDecrement(volatile int32_t* value)
|
||||
{
|
||||
return InterlockedDecrement((long volatile*)value);
|
||||
}
|
||||
|
||||
static inline int64_t UnityPalDecrement64(volatile int64_t* value)
|
||||
{
|
||||
return InterlockedDecrement64((long long volatile*)value);
|
||||
}
|
||||
|
||||
static inline int64_t UnityPalExchange64(volatile int64_t* dest, int64_t exchange)
|
||||
{
|
||||
return InterlockedExchange64(dest, exchange);
|
||||
}
|
||||
|
||||
static inline int32_t UnityPalExchange(volatile int32_t* dest, int32_t exchange)
|
||||
{
|
||||
return InterlockedExchange((long volatile*)dest, exchange);
|
||||
}
|
||||
|
||||
static inline void* UnityPalExchangePointer(void* volatile* dest, void* exchange)
|
||||
{
|
||||
return InterlockedExchangePointer(dest, exchange);
|
||||
}
|
||||
|
||||
static inline int64_t UnityPalRead64(volatile int64_t* addr)
|
||||
{
|
||||
return InterlockedCompareExchange64((long long volatile*)addr, 0, 0);
|
||||
}
|
||||
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef NOMINMAX
|
||||
#define NOMINMAX
|
||||
#endif
|
||||
#define WIN32_LEAN_AND_MEAN 1
|
||||
#define INC_OLE2 1
|
||||
#include <Windows.h>
|
||||
#include <Objidl.h>
|
||||
|
||||
#if IL2CPP_TARGET_WINDOWS_DESKTOP || IL2CPP_TARGET_WINRT
|
||||
#include <wincrypt.h>
|
||||
#include <Iphlpapi.h>
|
||||
#endif
|
||||
|
||||
#if !IL2CPP_TARGET_WINDOWS_DESKTOP
|
||||
#include <bcrypt.h>
|
||||
#include <roapi.h>
|
||||
#include <robuffer.h>
|
||||
#include <winstring.h>
|
||||
#endif
|
||||
|
||||
#define LINK_TO_WINDOWSRUNTIME_LIBS (!IL2CPP_TARGET_WINDOWS_DESKTOP)
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include "os/c-api/il2cpp-config-platforms.h"
|
||||
|
||||
#ifdef _MSC_VER
|
||||
# include <malloc.h>
|
||||
# define IL2CPP_EXPORT __declspec(dllexport)
|
||||
# define IL2CPP_IMPORT __declspec(dllimport)
|
||||
#elif IL2CPP_TARGET_PSP2 || IL2CPP_TARGET_PS4
|
||||
# define IL2CPP_EXPORT __declspec(dllexport)
|
||||
# define IL2CPP_IMPORT __declspec(dllimport)
|
||||
#else
|
||||
# define IL2CPP_EXPORT __attribute__ ((visibility ("default")))
|
||||
# define IL2CPP_IMPORT
|
||||
#endif
|
||||
+221
@@ -0,0 +1,221 @@
|
||||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#if defined(__aarch64__) && defined(__arm__)
|
||||
#error We assume both __aarch64__ and __arm__ cannot be defined at tha same time.
|
||||
#endif
|
||||
|
||||
#if defined(__aarch64__)
|
||||
#define IL2CPP_TARGET_ARM64 1
|
||||
#define IL2CPP_TARGET_ARMV7 0
|
||||
#elif defined(__arm__)
|
||||
#define IL2CPP_TARGET_ARM64 0
|
||||
#define IL2CPP_TARGET_ARMV7 1
|
||||
#else
|
||||
#define IL2CPP_TARGET_ARM64 0
|
||||
#define IL2CPP_TARGET_ARMV7 0
|
||||
#endif
|
||||
|
||||
#define IL2CPP_BINARY_SECTION_NAME ".il2cpp"
|
||||
|
||||
#if defined(SN_TARGET_PSP2)
|
||||
#define IL2CPP_TARGET_PSP2 1
|
||||
#define _UNICODE 1
|
||||
#define UNICODE 1
|
||||
#include "il2cpp-config-psp2.h"
|
||||
#elif defined(SN_TARGET_ORBIS)
|
||||
#define IL2CPP_TARGET_PS4 1
|
||||
#define _UNICODE 1
|
||||
#define UNICODE 1
|
||||
#elif defined(_MSC_VER)
|
||||
#define IL2CPP_TARGET_WINDOWS 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_CUSTOM_SECTIONS 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_DEBUGGER_PRESENT 1
|
||||
#define IL2CPP_METHOD_ATTR __declspec(code_seg (".il2cpp"))
|
||||
#if defined(_XBOX_ONE)
|
||||
#define IL2CPP_TARGET_XBOXONE 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_DEBUGGER_PRESENT 1
|
||||
#elif defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP)
|
||||
#define IL2CPP_TARGET_WINRT 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_SYSTEM_CERTIFICATES 1
|
||||
#else
|
||||
#define IL2CPP_TARGET_WINDOWS_DESKTOP 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_SYSTEM_CERTIFICATES 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_CPU_INFO 1
|
||||
#endif
|
||||
#define _UNICODE 1
|
||||
#define UNICODE 1
|
||||
#define STRICT 1
|
||||
#elif defined(__APPLE__)
|
||||
#define IL2CPP_TARGET_DARWIN 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_CPU_INFO 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_TIMEZONEINFO 1
|
||||
|
||||
#include "TargetConditionals.h"
|
||||
#if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR || TARGET_OS_TV || TARGET_TVOS_SIMULATOR
|
||||
#define IL2CPP_TARGET_IOS 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_CPU_INFO 1
|
||||
#else
|
||||
#define IL2CPP_TARGET_OSX 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_SYSTEM_CERTIFICATES 1
|
||||
#endif
|
||||
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_CUSTOM_SECTIONS !(IL2CPP_TARGET_IOS && IL2CPP_TARGET_ARMV7)
|
||||
#if IL2CPP_PLATFORM_SUPPORTS_CUSTOM_SECTIONS
|
||||
// The following gives managed stack traces (even with bitcode App Store submission), but may cause linker
|
||||
// errors on ARMv7 builds.
|
||||
#define IL2CPP_METHOD_ATTR __attribute__((section ("__TEXT," IL2CPP_BINARY_SECTION_NAME ",regular,pure_instructions")))
|
||||
#endif
|
||||
|
||||
#elif defined(__ANDROID__)
|
||||
#define IL2CPP_TARGET_ANDROID 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_TIMEZONEINFO 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_CUSTOM_SECTIONS 1
|
||||
#define IL2CPP_METHOD_ATTR __attribute__((section ("__TEXT," IL2CPP_BINARY_SECTION_NAME ",regular,pure_instructions")))
|
||||
#elif defined(EMSCRIPTEN)
|
||||
#define IL2CPP_TARGET_JAVASCRIPT 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_CPU_INFO 1
|
||||
#elif defined(NOVA)
|
||||
#define IL2CPP_TARGET_NOVA 1
|
||||
#elif defined(__linux__)
|
||||
#define IL2CPP_TARGET_LINUX 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_CPU_INFO 1
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_SYSTEM_CERTIFICATES 1
|
||||
#elif defined(NN_PLATFORM_CTR)
|
||||
#define IL2CPP_TARGET_N3DS 1
|
||||
#elif defined(NN_BUILD_TARGET_PLATFORM_NX)
|
||||
#define IL2CPP_TARGET_SWITCH 1
|
||||
#include "il2cpp-config-switch.h"
|
||||
#else
|
||||
#error please define your target platform
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_WINDOWS
|
||||
#define IL2CPP_TARGET_WINDOWS 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_WINDOWS_DESKTOP
|
||||
#define IL2CPP_TARGET_WINDOWS_DESKTOP 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_WINRT
|
||||
#define IL2CPP_TARGET_WINRT 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_XBOXONE
|
||||
#define IL2CPP_TARGET_XBOXONE 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_DARWIN
|
||||
#define IL2CPP_TARGET_DARWIN 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_IOS
|
||||
#define IL2CPP_TARGET_IOS 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_OSX
|
||||
#define IL2CPP_TARGET_OSX 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_ANDROID
|
||||
#define IL2CPP_TARGET_ANDROID 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_JAVASCRIPT
|
||||
#define IL2CPP_TARGET_JAVASCRIPT 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_LINUX
|
||||
#define IL2CPP_TARGET_LINUX 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_N3DS
|
||||
#define IL2CPP_TARGET_N3DS 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_PS4
|
||||
#define IL2CPP_TARGET_PS4 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_PSP2
|
||||
#define IL2CPP_TARGET_PSP2 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_TARGET_SWITCH
|
||||
#define IL2CPP_TARGET_SWITCH 0
|
||||
#endif
|
||||
|
||||
#define IL2CPP_TARGET_POSIX (IL2CPP_TARGET_DARWIN || IL2CPP_TARGET_JAVASCRIPT || IL2CPP_TARGET_LINUX || IL2CPP_TARGET_ANDROID || IL2CPP_TARGET_PS4 || IL2CPP_TARGET_PSP2 || IL2CPP_TARGET_NOVA)
|
||||
|
||||
#define IL2CPP_SUPPORT_THREADS !IL2CPP_TARGET_JAVASCRIPT
|
||||
|
||||
#ifndef IL2CPP_PLATFORM_SUPPORTS_SYSTEM_CERTIFICATES
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_SYSTEM_CERTIFICATES 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_PLATFORM_SUPPORTS_TIMEZONEINFO
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_TIMEZONEINFO 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_PLATFORM_SUPPORTS_CUSTOM_SECTIONS
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_CUSTOM_SECTIONS 0
|
||||
#endif
|
||||
|
||||
#if IL2CPP_TARGET_WINDOWS || IL2CPP_TARGET_XBOXONE || IL2CPP_TARGET_WINRT
|
||||
#include <crtdbg.h>
|
||||
#define IL2CPP_ASSERT(expr) \
|
||||
_ASSERTE(expr)
|
||||
#else
|
||||
#define IL2CPP_ASSERT(expr) \
|
||||
assert(expr)
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_PLATFORM_SUPPORTS_CPU_INFO
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_CPU_INFO 0
|
||||
#endif
|
||||
|
||||
#ifndef IL2CPP_PLATFORM_SUPPORTS_DEBUGGER_PRESENT
|
||||
#define IL2CPP_PLATFORM_SUPPORTS_DEBUGGER_PRESENT 0
|
||||
#endif
|
||||
|
||||
#define IL2CPP_USE_STD_THREAD 0
|
||||
|
||||
#define IL2CPP_THREADS_STD IL2CPP_USE_STD_THREAD
|
||||
#define IL2CPP_THREADS_PTHREAD (!IL2CPP_THREADS_STD && IL2CPP_TARGET_POSIX)
|
||||
#define IL2CPP_THREADS_WIN32 (!IL2CPP_THREADS_STD && IL2CPP_TARGET_WINDOWS)
|
||||
#define IL2CPP_THREADS_N3DS (!IL2CPP_THREADS_STD && IL2CPP_TARGET_N3DS)
|
||||
#define IL2CPP_THREADS_PS4 (!IL2CPP_THREADS_STD && IL2CPP_TARGET_PS4)
|
||||
#define IL2CPP_THREADS_PSP2 (!IL2CPP_THREADS_STD && IL2CPP_TARGET_PSP2)
|
||||
#define IL2CPP_THREADS_SWITCH (!IL2CPP_THREADS_STD && IL2CPP_TARGET_SWITCH)
|
||||
|
||||
/* Trigger assert if 'ptr' is not aligned to 'alignment'. */
|
||||
#define ASSERT_ALIGNMENT(ptr, alignment) \
|
||||
IL2CPP_ASSERT((((ptrdiff_t) ptr) & (alignment - 1)) == 0 && "Unaligned pointer!")
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#if defined(_M_X64)
|
||||
#define IL2CPP_SIZEOF_VOID_P 8
|
||||
#elif defined(_M_IX86) || defined(_M_ARM)
|
||||
#define IL2CPP_SIZEOF_VOID_P 4
|
||||
#else
|
||||
#error invalid windows architecture
|
||||
#endif
|
||||
#elif defined(__GNUC__) || defined(__SNC__)
|
||||
#if defined(__x86_64__)
|
||||
#define IL2CPP_SIZEOF_VOID_P 8
|
||||
#elif defined(__i386__)
|
||||
#define IL2CPP_SIZEOF_VOID_P 4
|
||||
#elif defined(EMSCRIPTEN)
|
||||
#define IL2CPP_SIZEOF_VOID_P 4
|
||||
#elif defined(__arm__)
|
||||
#define IL2CPP_SIZEOF_VOID_P 4
|
||||
#elif defined(__arm64__) || defined(__aarch64__)
|
||||
#define IL2CPP_SIZEOF_VOID_P 8
|
||||
#else
|
||||
#error invalid windows architecture
|
||||
#endif
|
||||
#else
|
||||
#error please define your target architecture size
|
||||
#endif
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#if IL2CPP_TARGET_PS4
|
||||
#define FILE_PATH_PREFIX "/app0/"
|
||||
#else
|
||||
#define FILE_PATH_PREFIX
|
||||
#endif
|
||||
|
||||
#define CURRENT_DIRECTORY(filename) FILE_PATH_PREFIX filename
|
||||
Reference in New Issue
Block a user