Initial commit.

This commit is contained in:
2019-07-01 14:33:21 +02:00
parent 92a04d779e
commit baa2e0279d
1624 changed files with 3204958 additions and 0 deletions
@@ -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
}
@@ -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;
}
@@ -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
@@ -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;
}
};
}
}
@@ -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, &params);
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
@@ -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)
@@ -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
@@ -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