mirror of https://github.com/dotnet/runtime
Merge 88c66b4b38
into 02596ba8d9
This commit is contained in:
commit
b1be43e0aa
|
@ -41,6 +41,7 @@
|
|||
#include <cstdarg>
|
||||
#include <signal.h>
|
||||
#include <minipal/thread.h>
|
||||
#include <minipal/env.h>
|
||||
|
||||
#ifdef TARGET_LINUX
|
||||
#include <sys/syscall.h>
|
||||
|
@ -988,21 +989,25 @@ UInt32_BOOL PalResetEvent(HANDLE event)
|
|||
|
||||
uint32_t PalGetEnvironmentVariable(const char * name, char * buffer, uint32_t size)
|
||||
{
|
||||
const char* value = getenv(name);
|
||||
if (value == NULL)
|
||||
size_t valueLen = 0;
|
||||
if (!minipal_env_get_s(&valueLen, buffer, size, name))
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t valueLen = strlen(value);
|
||||
// minipal_env_get_s returns the length of the value including the null terminator.
|
||||
if (valueLen > 0)
|
||||
{
|
||||
valueLen--;
|
||||
}
|
||||
|
||||
if (valueLen < size)
|
||||
{
|
||||
strcpy(buffer, value);
|
||||
return valueLen;
|
||||
return (uint32_t)valueLen;
|
||||
}
|
||||
|
||||
// return required size including the null character or 0 if the size doesn't fit into uint32_t
|
||||
return (valueLen < UINT32_MAX) ? (valueLen + 1) : 0;
|
||||
return valueLen < UINT32_MAX ? (uint32_t)(valueLen + 1) : 0;
|
||||
}
|
||||
|
||||
uint16_t PalCaptureStackBackTrace(uint32_t arg1, uint32_t arg2, void* arg3, uint32_t* arg4)
|
||||
|
|
|
@ -99,7 +99,6 @@
|
|||
#define PAL_THREAD_PRIORITY_MIN 0
|
||||
#define PAL_THREAD_PRIORITY_MAX 0
|
||||
|
||||
#cmakedefine01 HAVE__NSGETENVIRON
|
||||
#cmakedefine01 DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX
|
||||
#cmakedefine PAL_PTRACE(cmd, pid, addr, data) @PAL_PTRACE@
|
||||
#cmakedefine01 SYNCHMGR_SUSPENSION_SAFE_CONDITION_SIGNALING
|
||||
|
|
|
@ -890,7 +890,6 @@ if(NOT CLR_CMAKE_HOST_ARCH_ARM AND NOT CLR_CMAKE_HOST_ARCH_ARM64)
|
|||
endif()
|
||||
|
||||
if(CLR_CMAKE_TARGET_APPLE)
|
||||
set(HAVE__NSGETENVIRON 1)
|
||||
set(DEADLOCK_WHEN_THREAD_IS_SUSPENDED_WHILE_BLOCKED_ON_MUTEX 1)
|
||||
set(PAL_PTRACE "ptrace((cmd), (pid), (caddr_t)(addr), (data))")
|
||||
set(HAVE_SCHED_OTHER_ASSIGNABLE 1)
|
||||
|
|
|
@ -23,9 +23,8 @@ Revision History:
|
|||
#include "pal/dbgmsg.h"
|
||||
#include "pal/environ.h"
|
||||
|
||||
#if HAVE_CRT_EXTERNS_H
|
||||
#include <crt_externs.h>
|
||||
#endif
|
||||
#include "minipal/env.h"
|
||||
#include "minipal/mutex.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
|
@ -895,35 +894,6 @@ char* EnvironGetenv(const char* name, BOOL copyValue)
|
|||
return retValue;
|
||||
}
|
||||
|
||||
|
||||
/*++
|
||||
Function:
|
||||
EnvironGetSystemEnvironment
|
||||
|
||||
Get a pointer to the array of pointers representing the process's
|
||||
environment.
|
||||
|
||||
See 'man environ' for details.
|
||||
|
||||
Return Value
|
||||
|
||||
A pointer to the environment.
|
||||
|
||||
--*/
|
||||
char** EnvironGetSystemEnvironment()
|
||||
{
|
||||
char** sysEnviron;
|
||||
|
||||
#if HAVE__NSGETENVIRON
|
||||
sysEnviron = *(_NSGetEnviron());
|
||||
#else // HAVE__NSGETENVIRON
|
||||
extern char **environ;
|
||||
sysEnviron = environ;
|
||||
#endif // HAVE__NSGETENVIRON
|
||||
|
||||
return sysEnviron;
|
||||
}
|
||||
|
||||
/*++
|
||||
Function:
|
||||
EnvironInitialize
|
||||
|
@ -943,7 +913,8 @@ EnvironInitialize(void)
|
|||
CPalThread * pthrCurrent = InternalGetCurrentThread();
|
||||
minipal_mutex_enter(&gcsEnvironment);
|
||||
|
||||
char** sourceEnviron = EnvironGetSystemEnvironment();
|
||||
char** sourceEnviron = minipal_env_get_environ_copy();
|
||||
_ASSERT(sourceEnviron != NULL);
|
||||
|
||||
int variableCount = 0;
|
||||
while (sourceEnviron[variableCount] != nullptr)
|
||||
|
@ -965,7 +936,9 @@ EnvironInitialize(void)
|
|||
_ASSERTE(palEnvironment != nullptr);
|
||||
for (int i = 0; i < variableCount; ++i)
|
||||
{
|
||||
palEnvironment[i] = strdup(sourceEnviron[i]);
|
||||
// Transfer ownership of the string to palEnvironment.
|
||||
palEnvironment[i] = sourceEnviron[i];
|
||||
sourceEnviron[i] = nullptr;
|
||||
palEnvironmentCount++;
|
||||
}
|
||||
|
||||
|
@ -973,6 +946,8 @@ EnvironInitialize(void)
|
|||
palEnvironment[variableCount] = nullptr;
|
||||
}
|
||||
|
||||
minipal_env_free_environ(sourceEnviron);
|
||||
|
||||
minipal_mutex_leave(&gcsEnvironment);
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -235,14 +235,25 @@ void StressLog::Initialize(unsigned facilities, unsigned level, unsigned maxByte
|
|||
// in this case, interpret the number as GB
|
||||
maxBytesPerThread *= (1024 * 1024 * 1024);
|
||||
}
|
||||
|
||||
theLog.MaxSizePerThread = (unsigned)min(maxBytesPerThread,(size_t)0xffffffff);
|
||||
|
||||
size_t maxBytesTotal = maxBytesTotalArg;
|
||||
|
||||
#ifdef MEMORY_MAPPED_STRESSLOG
|
||||
if (logFilename != nullptr && logFilename[0] != '\0')
|
||||
{
|
||||
// we need at least sizeof(StressLogHeader) bytes for memory mapped stress log
|
||||
maxBytesTotal = sizeof(StressLogHeader) + maxBytesTotal;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (maxBytesTotal < STRESSLOG_CHUNK_SIZE * 256)
|
||||
{
|
||||
// in this case, interpret the number as GB
|
||||
maxBytesTotal *= (1024 * 1024 * 1024);
|
||||
}
|
||||
|
||||
theLog.MaxSizeTotal = (unsigned)min(maxBytesTotal, (size_t)0xffffffff);
|
||||
theLog.totalChunk = 0;
|
||||
theLog.facilitiesToLog = facilities | LF_ALWAYS;
|
||||
|
|
|
@ -70,11 +70,16 @@ if (CLR_CMAKE_TARGET_APPLE)
|
|||
else()
|
||||
list (APPEND NATIVE_SOURCES
|
||||
pal_autoreleasepool.c
|
||||
pal_environment.c
|
||||
pal_searchpath.c
|
||||
pal_log.c
|
||||
pal_iossupportversion.c)
|
||||
|
||||
if (CLR_CMAKE_TARGET_ANDROID)
|
||||
list (APPEND NATIVE_SOURCES pal_environment_android.c)
|
||||
else()
|
||||
list (APPEND NATIVE_SOURCES pal_environment.c)
|
||||
endif()
|
||||
|
||||
if (CLR_CMAKE_TARGET_WASI)
|
||||
list (APPEND NATIVE_SOURCES pal_console_wasi.c)
|
||||
else()
|
||||
|
|
|
@ -3,26 +3,16 @@
|
|||
|
||||
#include "pal_config.h"
|
||||
#include "pal_environment.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#if HAVE_NSGETENVIRON
|
||||
#include <crt_externs.h>
|
||||
#endif
|
||||
#include <minipal/env.h>
|
||||
|
||||
char* SystemNative_GetEnv(const char* variable)
|
||||
{
|
||||
return getenv(variable);
|
||||
return minipal_env_get(variable);
|
||||
}
|
||||
|
||||
char** SystemNative_GetEnviron(void)
|
||||
{
|
||||
#if HAVE_NSGETENVIRON
|
||||
return *(_NSGetEnviron());
|
||||
#else
|
||||
extern char **environ;
|
||||
return environ;
|
||||
#endif
|
||||
return minipal_env_get_environ();
|
||||
}
|
||||
|
||||
void SystemNative_FreeEnviron(char** environ)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#include "pal_config.h"
|
||||
#include "pal_environment.h"
|
||||
|
||||
#include <minipal/env.h>
|
||||
|
||||
char* SystemNative_GetEnv(const char* variable)
|
||||
{
|
||||
return minipal_env_get(variable);
|
||||
}
|
||||
|
||||
char** SystemNative_GetEnviron(void)
|
||||
{
|
||||
return minipal_env_get_environ_copy();
|
||||
}
|
||||
|
||||
void SystemNative_FreeEnviron(char** environ)
|
||||
{
|
||||
minipal_env_free_environ(environ);
|
||||
}
|
|
@ -12,6 +12,7 @@ set(SOURCES
|
|||
utf8.c
|
||||
xoshiro128pp.c
|
||||
log.c
|
||||
env.c
|
||||
)
|
||||
|
||||
# Provide an object library for scenarios where we ship static libraries
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#ifndef HAVE_MINIPAL_ATOMIC_H
|
||||
#define HAVE_MINIPAL_ATOMIC_H
|
||||
|
||||
#ifdef HOST_WINDOWS
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <stdatomic.h>
|
||||
#if ATOMIC_POINTER_LOCK_FREE != 2
|
||||
#pragma message("C11 atomic pointer types are not lock free on targeted platform")
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif // __cplusplus
|
||||
|
||||
/**
|
||||
* @brief Atomic compares and exchange a pointer value.
|
||||
*
|
||||
* @param dest Pointer to the destination pointer to compare and swap.
|
||||
* @param exch The value to store if the comparison succeeds.
|
||||
* @param comp The value to compare against.
|
||||
*
|
||||
* @return The previous value of the pointer.
|
||||
*/
|
||||
static inline void* minipal_atomic_compare_exchange_ptr(volatile void** dest, void* exch, void* comp)
|
||||
{
|
||||
#ifdef HOST_WINDOWS
|
||||
return InterlockedCompareExchangePointer((PVOID volatile *)dest, (PVOID)exch, (PVOID)comp);
|
||||
#else
|
||||
atomic_compare_exchange_strong((volatile _Atomic(void *) *)dest, &comp, exch);
|
||||
atomic_thread_fence(memory_order_seq_cst);
|
||||
return comp;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif /* HAVE_MINIPAL_ATOMIC_H */
|
|
@ -5,15 +5,43 @@ include(CheckSymbolExists)
|
|||
check_include_files("windows.h;bcrypt.h" HAVE_BCRYPT_H)
|
||||
check_include_files("sys/auxv.h;asm/hwcap.h" HAVE_AUXV_HWCAP_H)
|
||||
check_include_files("asm/hwprobe.h" HAVE_HWPROBE_H)
|
||||
check_include_files("crt_externs.h" HAVE_CRT_EXTERNS_H)
|
||||
|
||||
check_function_exists(sysctlbyname HAVE_SYSCTLBYNAME)
|
||||
check_function_exists(fsync HAVE_FSYNC)
|
||||
check_symbol_exists(sysctlbyname "sys/sysctl.h" HAVE_SYSCTLBYNAME)
|
||||
check_symbol_exists(fsync "unistd.h" HAVE_FSYNC)
|
||||
|
||||
check_symbol_exists(arc4random_buf "stdlib.h" HAVE_ARC4RANDOM_BUF)
|
||||
check_symbol_exists(O_CLOEXEC fcntl.h HAVE_O_CLOEXEC)
|
||||
check_symbol_exists(CLOCK_MONOTONIC time.h HAVE_CLOCK_MONOTONIC)
|
||||
check_symbol_exists(CLOCK_MONOTONIC_COARSE time.h HAVE_CLOCK_MONOTONIC_COARSE)
|
||||
check_symbol_exists(clock_gettime_nsec_np time.h HAVE_CLOCK_GETTIME_NSEC_NP)
|
||||
check_symbol_exists(O_CLOEXEC "fcntl.h" HAVE_O_CLOEXEC)
|
||||
check_symbol_exists(CLOCK_MONOTONIC "time.h" HAVE_CLOCK_MONOTONIC)
|
||||
check_symbol_exists(CLOCK_MONOTONIC_COARSE "time.h" HAVE_CLOCK_MONOTONIC_COARSE)
|
||||
check_symbol_exists(clock_gettime_nsec_np "time.h" HAVE_CLOCK_GETTIME_NSEC_NP)
|
||||
|
||||
check_symbol_exists(getenv "stdlib.h" HAVE_GETENV)
|
||||
check_symbol_exists(strcpy_s "string.h" HAVE_STRCPY_S)
|
||||
check_symbol_exists(strncpy_s "string.h" HAVE_STRNCPY_S)
|
||||
check_symbol_exists(strcat_s "string.h" HAVE_STRCAT_S)
|
||||
|
||||
if (HAVE_CRT_EXTERNS_H)
|
||||
check_c_source_compiles(
|
||||
"
|
||||
#include <crt_externs.h>
|
||||
int main(void) { char** e = *(_NSGetEnviron()); return 0; }
|
||||
"
|
||||
HAVE__NSGETENVIRON)
|
||||
endif()
|
||||
|
||||
check_c_source_compiles(
|
||||
"
|
||||
#include <stdlib.h>
|
||||
int main(void) { char** e = _environ; return 0; }
|
||||
"
|
||||
HAVE__ENVIRON)
|
||||
|
||||
check_c_source_compiles(
|
||||
"
|
||||
int main(void) { extern char **environ; char** e = environ; return 0; }
|
||||
"
|
||||
HAVE_ENVIRON)
|
||||
|
||||
if(CMAKE_C_BYTE_ORDER STREQUAL "BIG_ENDIAN")
|
||||
set(BIGENDIAN 1)
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,177 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#ifndef HAVE_MINIPAL_ENV_H
|
||||
#define HAVE_MINIPAL_ENV_H
|
||||
|
||||
#include <minipal/types.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif // __cplusplus
|
||||
|
||||
/**
|
||||
* @brief Loads and cache the environment variable subsystem using process data.
|
||||
*
|
||||
* Loads and cache environment variables from the system and prepares internal data structures.
|
||||
* If environment variables have already been used through minipal_env_get, minipal_env_get_copy, minipal_env_get_s,
|
||||
* minipal_env_set or minipal_env_put existing cached values will be merged into loaded environment.
|
||||
*
|
||||
* Function exists to explicitly load and cache environment.
|
||||
*
|
||||
* @return true on success, false on failure.
|
||||
*/
|
||||
bool minipal_env_load_environ(void);
|
||||
|
||||
/**
|
||||
* @brief Unload and free cached environment subsystem.
|
||||
*
|
||||
* Unloads and free cache environment variables. Any changes done to the environment will be lost.
|
||||
* This function should be called when the environment is no longer needed or if the environment needs
|
||||
* to be reloaded using minipal_env_load_environ.
|
||||
*/
|
||||
void minipal_env_unload_environ(void);
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to an internal environment variable array.
|
||||
*
|
||||
* @warning The returned pointer is not thread-safe and should not be modified.
|
||||
* This function should only be called from code that guarantees environment won't
|
||||
* change while using returned pointer.
|
||||
*
|
||||
* @return Pointer to the environment variable array.
|
||||
*
|
||||
* @remarks
|
||||
* - Access internal environment variable array wihout doing allocs or taking locks.
|
||||
*/
|
||||
char** minipal_env_get_environ(void);
|
||||
|
||||
/**
|
||||
* @brief Get a pointer to the environment variable array.
|
||||
*
|
||||
* @return Pointer to the environment variable array, or NULL on failure.
|
||||
*
|
||||
* @remarks
|
||||
* - Returned environment is a copy and owned by caller, freed using minipal_env_free_environ.
|
||||
* - If environment has NOT been explicitly loaded, a copy of the underlying system environment
|
||||
* will created and returned on each call. To avoid recreating environment on each call,
|
||||
* explicit load environment using minipal_env_load_environ before calling this function.
|
||||
*/
|
||||
char** minipal_env_get_environ_copy(void);
|
||||
|
||||
/**
|
||||
* @brief Frees an environment variable array previously returned by minipal_env_get_environ_copy.
|
||||
*
|
||||
* This function releases all memory associated with the environment array returned by
|
||||
* minipal_env_get_environ_copy. The pointer passed must not be used after this call.
|
||||
*
|
||||
* @param data Pointer to the environment variable array to free. May be NULL.
|
||||
*
|
||||
* @remarks
|
||||
* - Only use this function to free arrays returned by minipal_env_get_environ_copy.
|
||||
* - Passing NULL is safe and has no effect.
|
||||
*/
|
||||
void minipal_env_free_environ(char** data);
|
||||
|
||||
/**
|
||||
* @brief Checks if specified environment variable exists.
|
||||
*
|
||||
* @param name Name of the environment variable to check.
|
||||
*
|
||||
* @return true if the variable was found, false otherwise.
|
||||
*/
|
||||
bool minipal_env_exists(const char* name);
|
||||
|
||||
/**
|
||||
* @brief Get the value of an environment variable.
|
||||
*
|
||||
* @param name The name of the environment variable to get.
|
||||
*
|
||||
* @warning The returned pointer is not thread-safe and should not be modified.
|
||||
* This function should only be called from code that guarantees environment won't
|
||||
* change while using returned pointer.
|
||||
*
|
||||
* @return String containing the value, ownership is still held by the environment and should NOT
|
||||
* be freed by caller. Returns NULL if not found or on error.
|
||||
*/
|
||||
char* minipal_env_get(const char* name);
|
||||
|
||||
/**
|
||||
* @brief Get a copy of the value of an environment variable.
|
||||
*
|
||||
* @param name The name of the environment variable to get.
|
||||
*
|
||||
* @return Newly allocated string containing the value. Returns NULL if not found or on error.
|
||||
*
|
||||
* @remarks
|
||||
* - Caller is responsible freeing the returned string.
|
||||
*/
|
||||
char* minipal_env_get_copy(const char* name);
|
||||
|
||||
/**
|
||||
* @brief Get the value of an environment variable into a user allocated buffer.
|
||||
*
|
||||
* This functions gives callers ability to use a pre-allocated buffer when
|
||||
* requesting an environment variable. Passing in a pointer for len, but NULL
|
||||
* for value and 0 for valuesz returns needed size in bytes to hold full environment
|
||||
* variable value in len.
|
||||
*
|
||||
* @param len If not NULL, receives the length of the value in bytes.
|
||||
* @param value Buffer receiving the value.
|
||||
* @param valuesz Size of the value buffer in bytes.
|
||||
* @param name Name of the environment variable value to get.
|
||||
*
|
||||
* @return true if the variable was found, false otherwise.
|
||||
*
|
||||
* @remarks
|
||||
* - If the buffer is too small, len is set to the required size in bytes
|
||||
* (including null terminator) and function returns success.
|
||||
* - If complete value fit into buffer, len includes the number copied bytes
|
||||
* (including the null terminator).
|
||||
*/
|
||||
bool minipal_env_get_s(size_t* len, char* value, size_t valuesz, const char* name);
|
||||
|
||||
/**
|
||||
* @brief Set or update an environment variable.
|
||||
*
|
||||
* @param name Name of the environment variable.
|
||||
* @param value Value to set. If NULL, sets the variable to an empty string.
|
||||
* @param overwrite If false and the variable exists, does not update it.
|
||||
*
|
||||
* @return true on success, false on failure.
|
||||
*/
|
||||
bool minipal_env_set(const char* name, const char* value, bool overwrite);
|
||||
|
||||
/**
|
||||
* @brief Add or update an environment variable from a "NAME=VALUE" string.
|
||||
*
|
||||
* @param env_s Environment variable to add/update.
|
||||
*
|
||||
* @return true on success, false on failure.
|
||||
*
|
||||
* @remarks
|
||||
* - Function makes a copy so caller continues to owns env_s.
|
||||
*/
|
||||
bool minipal_env_put(const char* env_s);
|
||||
|
||||
/**
|
||||
* @brief Remove an environment variable.
|
||||
*
|
||||
* @param name Name of the environment variable to remove.
|
||||
*
|
||||
* @return true if environment variable is successfully removed or not found, false on failure.
|
||||
*
|
||||
* @remarks
|
||||
* - If environment has NOT been explicitly loaded, function will automatically load
|
||||
* enviroment maintaining a unified view of all changes.
|
||||
*/
|
||||
bool minipal_env_unset(const char* name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif /* HAVE_MINIPAL_ENV_H */
|
|
@ -4,6 +4,7 @@
|
|||
#cmakedefine01 HAVE_ARC4RANDOM_BUF
|
||||
#cmakedefine01 HAVE_AUXV_HWCAP_H
|
||||
#cmakedefine01 HAVE_HWPROBE_H
|
||||
#cmakedefine01 HAVE_CRT_EXTERNS_H
|
||||
#cmakedefine01 HAVE_O_CLOEXEC
|
||||
#cmakedefine01 HAVE_SYSCTLBYNAME
|
||||
#cmakedefine01 HAVE_CLOCK_MONOTONIC
|
||||
|
@ -12,5 +13,12 @@
|
|||
#cmakedefine01 BIGENDIAN
|
||||
#cmakedefine01 HAVE_BCRYPT_H
|
||||
#cmakedefine01 HAVE_FSYNC
|
||||
#cmakedefine01 HAVE__NSGETENVIRON
|
||||
#cmakedefine01 HAVE__ENVIRON
|
||||
#cmakedefine01 HAVE_ENVIRON
|
||||
#cmakedefine01 HAVE_GETENV
|
||||
#cmakedefine01 HAVE_STRCPY_S
|
||||
#cmakedefine01 HAVE_STRNCPY_S
|
||||
#cmakedefine01 HAVE_STRCAT_S
|
||||
|
||||
#endif
|
||||
|
|
|
@ -2,11 +2,16 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#include "strings.h"
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef HOST_WINDOWS
|
||||
#include <wchar.h>
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @see strings.h
|
||||
*/
|
||||
size_t minipal_u16_strlen(const CHAR16_T* str)
|
||||
{
|
||||
#ifdef HOST_WINDOWS
|
||||
|
@ -20,3 +25,125 @@ size_t minipal_u16_strlen(const CHAR16_T* str)
|
|||
return len;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @see strings.h
|
||||
*/
|
||||
char * minipal_strdup(const char* str)
|
||||
{
|
||||
#ifdef HOST_WINDOWS
|
||||
return _strdup(str);
|
||||
#else
|
||||
return strdup(str);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @see strings.h
|
||||
*/
|
||||
int minipal_strcpy_s(char* dest, size_t destsz, const char* src)
|
||||
{
|
||||
#if HAVE_STRCPY_S
|
||||
return strcpy_s(dest, destsz, src);
|
||||
#else
|
||||
if (dest == NULL || src == NULL || destsz == 0)
|
||||
{
|
||||
if (dest && destsz > 0)
|
||||
{
|
||||
dest[0] = '\0';
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
size_t src_len = strlen(src);
|
||||
if (src_len + 1 > destsz)
|
||||
{
|
||||
dest[0] = '\0';
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
memcpy(dest, src, src_len + 1);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @see strings.h
|
||||
*/
|
||||
int minipal_strncpy_s(char* dest, size_t destsz, const char* src, size_t count)
|
||||
{
|
||||
#if HAVE_STRNCPY_S
|
||||
return strncpy_s(dest, destsz, src, count);
|
||||
#else
|
||||
if (dest == NULL || src == NULL || destsz == 0)
|
||||
{
|
||||
if (dest && destsz > 0)
|
||||
{
|
||||
dest[0] = '\0';
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
if (count >= destsz)
|
||||
{
|
||||
dest[0] = '\0';
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
size_t i = 0;
|
||||
for (; i < count && i < destsz - 1 && src[i] != '\0'; ++i)
|
||||
{
|
||||
dest[i] = src[i];
|
||||
}
|
||||
|
||||
dest[i] = '\0';
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* @see strings.h
|
||||
*/
|
||||
int minipal_strcat_s(char* dest, size_t destsz, const char* src)
|
||||
{
|
||||
#if HAVE_STRCAT_S
|
||||
return strcat_s(dest, destsz, src);
|
||||
#else
|
||||
if (dest == NULL || src == NULL || destsz == 0)
|
||||
{
|
||||
if (dest && destsz > 0)
|
||||
{
|
||||
dest[0] = '\0';
|
||||
}
|
||||
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
size_t dest_len = 0;
|
||||
for (; dest_len < destsz; ++dest_len)
|
||||
{
|
||||
if (dest[dest_len] == '\0')
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (dest_len == destsz)
|
||||
{
|
||||
dest[0] = '\0';
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
size_t src_len = strlen(src);
|
||||
if (dest_len + src_len + 1 > destsz)
|
||||
{
|
||||
dest[0] = '\0';
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
memcpy(dest + dest_len, src, src_len + 1);
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -35,6 +35,26 @@ CHAR16_T minipal_tolower_invariant(CHAR16_T code);
|
|||
*/
|
||||
size_t minipal_u16_strlen(const CHAR16_T* str);
|
||||
|
||||
/**
|
||||
* @brief xplat implementation of strdup.
|
||||
*/
|
||||
char* minipal_strdup(const char *str);
|
||||
|
||||
/**
|
||||
* @brief xplat implementation of strcpy_s.
|
||||
*/
|
||||
int minipal_strcpy_s(char* dest, size_t destsz, const char* src);
|
||||
|
||||
/**
|
||||
* @brief xplat implementation of strncpy_s.
|
||||
*/
|
||||
int minipal_strncpy_s(char* dest, size_t destsz, const char* src, size_t count);
|
||||
|
||||
/**
|
||||
* @brief xplat implementation of strcat_s.
|
||||
*/
|
||||
int minipal_strcat_s(char* dest, size_t destsz, const char* src);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
|
|
@ -0,0 +1,235 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
|
||||
#ifndef HAVE_MINIPAL_VOLATILE_H
|
||||
#define HAVE_MINIPAL_VOLATILE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <intrin.h>
|
||||
#ifdef HOST_ARM64
|
||||
#include <arm64intr.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
//
|
||||
// This code is extremely compiler- and CPU-specific, and will need to be altered to
|
||||
// support new compilers and/or CPUs. Here we enforce that we can only compile using
|
||||
// VC++, or GCC on x86 or AMD64.
|
||||
//
|
||||
#if !defined(_MSC_VER) && !defined(__GNUC__)
|
||||
#error The Volatile type is currently only defined for Visual C++ and GNU C++
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__) && !defined(HOST_X86) && !defined(HOST_AMD64) && !defined(HOST_ARM) && !defined(HOST_ARM64) && !defined(HOST_LOONGARCH64) && !defined(HOST_WASM) && !defined(HOST_RISCV64)
|
||||
#error The Volatile type is currently only defined for GCC when targeting x86, AMD64, ARM, ARM64, LOONGARCH64, Wasm, RISCV64
|
||||
#endif
|
||||
|
||||
#if defined(__GNUC__)
|
||||
#if defined(HOST_ARM) || defined(HOST_ARM64)
|
||||
// This is functionally equivalent to the MemoryBarrier() macro used on ARM on Windows.
|
||||
#define MINIPAL_VOLATILE_MEMORY_BARRIER() asm volatile ("dmb ish" : : : "memory")
|
||||
#elif defined(HOST_LOONGARCH64)
|
||||
#define MINIPAL_VOLATILE_MEMORY_BARRIER() asm volatile ("dbar 0 " : : : "memory")
|
||||
#elif defined(HOST_RISCV64)
|
||||
#define MINIPAL_VOLATILE_MEMORY_BARRIER() asm volatile ("fence rw,rw" : : : "memory")
|
||||
#else
|
||||
//
|
||||
// For GCC, we prevent reordering by the compiler by inserting the following after a volatile
|
||||
// load (to prevent subsequent operations from moving before the read), and before a volatile
|
||||
// write (to prevent prior operations from moving past the write). We don't need to do anything
|
||||
// special to prevent CPU reorderings, because the x86 and AMD64 architectures are already
|
||||
// sufficiently constrained for our purposes. If we ever need to run on weaker CPU architectures
|
||||
// (such as PowerPC), then we will need to do more work.
|
||||
//
|
||||
// Please do not use this macro outside of this file. It is subject to change or removal without
|
||||
// notice.
|
||||
//
|
||||
#define MINIPAL_VOLATILE_MEMORY_BARRIER() asm volatile ("" : : : "memory")
|
||||
#endif // HOST_ARM || HOST_ARM64
|
||||
#elif (defined(HOST_ARM) || defined(HOST_ARM64)) && _ISO_VOLATILE
|
||||
// ARM & ARM64 have a very weak memory model and very few tools to control that model. We're forced to perform a full
|
||||
// memory barrier to preserve the volatile semantics. Technically this is only necessary on MP systems but we
|
||||
// currently don't have a cheap way to determine the number of CPUs from this header file. Revisit this if it
|
||||
// turns out to be a performance issue for the uni-proc case.
|
||||
#define MINIPAL_VOLATILE_MEMORY_BARRIER() MemoryBarrier()
|
||||
#else
|
||||
//
|
||||
// On VC++, reorderings at the compiler and machine level are prevented by the use of the
|
||||
// "volatile" keyword in volatile_load and volatile_store. This should work on any CPU architecture
|
||||
// targeted by VC++ with /iso_volatile-.
|
||||
//
|
||||
#define MINIPAL_VOLATILE_MEMORY_BARRIER()
|
||||
#endif // __GNUC__
|
||||
|
||||
#if defined(HOST_ARM64) && defined(__GNUC__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
// Starting at version 3.8, clang errors out on initializing of type int * to volatile int *. To fix this, we add two templates to cast away volatility
|
||||
// Helper structures for casting away volatileness
|
||||
template<typename T>
|
||||
struct RemoveVolatile
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
struct RemoveVolatile<volatile T>
|
||||
{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
#define REMOVE_VOLATILE_T(T, val) const_cast<typename RemoveVolatile<T>::type *>(&val)
|
||||
#else
|
||||
#define REMOVE_VOLATILE_T(T, val) (T*)(&val)
|
||||
#endif // __cplusplus
|
||||
|
||||
#define MINIPAL_VOLATILE_GCC_ATOMIC_LOAD(T, ptr, val) \
|
||||
do { __atomic_load((T const*)(ptr), REMOVE_VOLATILE_T(T, val), __ATOMIC_ACQUIRE); } while (0)
|
||||
|
||||
#define MINIPAL_VOLATILE_GCC_ATOMIC_STORE(T, ptr, val) \
|
||||
do { __atomic_store((T volatile*)(ptr), &val, __ATOMIC_RELEASE); } while (0)
|
||||
|
||||
#define MINIPAL_VOLATILE_LOAD_T(T, ptr, val) do { val = *(T volatile const*)(ptr); asm volatile ("dmb ishld" : : : "memory"); } while (0)
|
||||
#define MINIPAL_VOLATILE_LOAD_8(T, ptr, val) do { MINIPAL_VOLATILE_GCC_ATOMIC_LOAD(T, ptr, val); } while (0)
|
||||
#define MINIPAL_VOLATILE_LOAD_16(T, ptr, val) do { MINIPAL_VOLATILE_GCC_ATOMIC_LOAD(T, ptr, val); } while (0)
|
||||
#define MINIPAL_VOLATILE_LOAD_32(T, ptr, val) do { MINIPAL_VOLATILE_GCC_ATOMIC_LOAD(T, ptr, val); } while (0)
|
||||
#define MINIPAL_VOLATILE_LOAD_64(T, ptr, val) do { MINIPAL_VOLATILE_GCC_ATOMIC_LOAD(T, ptr, val); } while (0)
|
||||
|
||||
#define MINIPAL_VOLATILE_STORE_T(T, ptr, val) do { MINIPAL_VOLATILE_MEMORY_BARRIER(); *(T volatile*)(ptr) = val; } while (0)
|
||||
#define MINIPAL_VOLATILE_STORE_8(T, ptr, val) do { MINIPAL_VOLATILE_GCC_ATOMIC_STORE(T, ptr, val); } while (0)
|
||||
#define MINIPAL_VOLATILE_STORE_16(T, ptr, val) do { MINIPAL_VOLATILE_GCC_ATOMIC_STORE(T, ptr, val); } while (0)
|
||||
#define MINIPAL_VOLATILE_STORE_32(T, ptr, val) do { MINIPAL_VOLATILE_GCC_ATOMIC_STORE(T, ptr, val); } while (0)
|
||||
#define MINIPAL_VOLATILE_STORE_64(T, ptr, val) do { MINIPAL_VOLATILE_GCC_ATOMIC_STORE(T, ptr, val); } while (0)
|
||||
|
||||
#elif defined(HOST_ARM64) && defined(_MSC_VER)
|
||||
|
||||
#define MINIPAL_VOLATILE_LOAD_T(T, ptr, val) do { val = *(T volatile const*)(ptr); __dmb(_ARM64_BARRIER_ISHLD); } while (0)
|
||||
#define MINIPAL_VOLATILE_LOAD_8(T, ptr, val) do { *(uint8_t*)&val = __ldar8((uint8_t volatile*)(ptr)); } while (0)
|
||||
#define MINIPAL_VOLATILE_LOAD_16(T, ptr, val) do { *(uint16_t*)&val = __ldar16((uint16_t volatile*)(ptr)); } while (0)
|
||||
#define MINIPAL_VOLATILE_LOAD_32(T, ptr, val) do { *(uint32_t*)&val = __ldar32((uint32_t volatile*)(ptr)); } while (0)
|
||||
#define MINIPAL_VOLATILE_LOAD_64(T, ptr, val) do { *(uint64_t*)&val = __ldar64((uint64_t volatile*)(ptr)); } while (0)
|
||||
|
||||
#define MINIPAL_VOLATILE_STORE_T(T, ptr, val) do { __dmb(_ARM64_BARRIER_ISHLD); *(T volatile*)ptr = val; } while (0)
|
||||
#define MINIPAL_VOLATILE_STORE_8(T, ptr, val) do { __stlr8((uint8_t volatile*)(ptr), *(uint8_t*)&val); } while (0)
|
||||
#define MINIPAL_VOLATILE_STORE_16(T, ptr, val) do { __stlr16((uint16_t volatile*)(ptr), *(uint16_t*)&val); } while (0)
|
||||
#define MINIPAL_VOLATILE_STORE_32(T, ptr, val) do { __stlr32((uint32_t volatile*)(ptr), *(uint32_t*)&val); } while (0)
|
||||
#define MINIPAL_VOLATILE_STORE_64(T, ptr, val) do { __stlr64((uint64_t volatile*)(ptr), *(uint64_t*)&val); } while (0)
|
||||
|
||||
#else
|
||||
|
||||
#define MINIPAL_VOLATILE_LOAD_T(T, ptr, val) do { val = *(T volatile const*)(ptr); MINIPAL_VOLATILE_MEMORY_BARRIER(); } while (0)
|
||||
#define MINIPAL_VOLATILE_LOAD_8(T, ptr, val) do { MINIPAL_VOLATILE_LOAD_T(T, ptr, val); } while (0)
|
||||
#define MINIPAL_VOLATILE_LOAD_16(T, ptr, val) do { MINIPAL_VOLATILE_LOAD_T(T, ptr, val); } while (0)
|
||||
#define MINIPAL_VOLATILE_LOAD_32(T, ptr, val) do { MINIPAL_VOLATILE_LOAD_T(T, ptr, val); } while (0)
|
||||
#define MINIPAL_VOLATILE_LOAD_64(T, ptr, val) do { MINIPAL_VOLATILE_LOAD_T(T, ptr, val); } while (0)
|
||||
|
||||
#define MINIPAL_VOLATILE_STORE_T(T, ptr, val) do { MINIPAL_VOLATILE_MEMORY_BARRIER(); *(T volatile*)(ptr) = val; } while (0)
|
||||
#define MINIPAL_VOLATILE_STORE_8(T, ptr, val) do { MINIPAL_VOLATILE_STORE_T(T, ptr, val); } while (0)
|
||||
#define MINIPAL_VOLATILE_STORE_16(T, ptr, val) do { MINIPAL_VOLATILE_STORE_T(T, ptr, val); } while (0)
|
||||
#define MINIPAL_VOLATILE_STORE_32(T, ptr, val) do { MINIPAL_VOLATILE_STORE_T(T, ptr, val); } while (0)
|
||||
#define MINIPAL_VOLATILE_STORE_64(T, ptr, val) do { MINIPAL_VOLATILE_STORE_T(T, ptr, val); } while (0)
|
||||
|
||||
#endif // defined(HOST_ARM64) && defined(__GNUC__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif // __cplusplus
|
||||
|
||||
// minipal_volatile_load_* loads a T from a pointer to T. It is guaranteed that this load will not be optimized
|
||||
// away by the compiler, and that any operation that occurs after this load, in program order, will
|
||||
// not be moved before this load. In general it is not guaranteed that the load will be atomic, though
|
||||
// this is the case for most aligned scalar data types. If you need atomic loads or stores, you need
|
||||
// to consult the compiler and CPU manuals to find which circumstances allow atomicity.
|
||||
|
||||
static inline uint8_t minipal_volatile_load_uint8_t(uint8_t const* ptr)
|
||||
{
|
||||
uint8_t value;
|
||||
MINIPAL_VOLATILE_LOAD_8(uint8_t, ptr, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline uint16_t minipal_volatile_load_uint16_t(uint16_t const* ptr)
|
||||
{
|
||||
uint16_t value;
|
||||
MINIPAL_VOLATILE_LOAD_16(uint16_t, ptr, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline uint32_t minipal_volatile_load_uint32_t(uint32_t const* ptr)
|
||||
{
|
||||
uint32_t value;
|
||||
MINIPAL_VOLATILE_LOAD_32(uint32_t, ptr, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline uint64_t minipal_volatile_load_uint64_t(uint64_t const* ptr)
|
||||
{
|
||||
uint64_t value;
|
||||
MINIPAL_VOLATILE_LOAD_64(uint64_t, ptr, value);
|
||||
return value;
|
||||
}
|
||||
|
||||
static inline void* minipal_volatile_load_ptr(void* const* ptr)
|
||||
{
|
||||
if (sizeof(uintptr_t) == 4)
|
||||
{
|
||||
uint32_t value;
|
||||
MINIPAL_VOLATILE_LOAD_32(uint32_t, ptr, value);
|
||||
return (void*)(uintptr_t)value;
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t value;
|
||||
MINIPAL_VOLATILE_LOAD_64(uint64_t, ptr, value);
|
||||
return (void*)(uintptr_t)value;
|
||||
}
|
||||
}
|
||||
|
||||
// minipal_volatile_store_* stores a T into the target of a pointer to T. It is guaranteed that this store will
|
||||
// not be optimized away by the compiler, and that any operation that occurs before this store, in program
|
||||
// order, will not be moved after this store. In general, it is not guaranteed that the store will be
|
||||
// atomic, though this is the case for most aligned scalar data types. If you need atomic loads or stores,
|
||||
// you need to consult the compiler and CPU manuals to find which circumstances allow atomicity.
|
||||
|
||||
static inline void minipal_volatile_store_uint8_t(uint8_t* ptr, uint8_t value)
|
||||
{
|
||||
MINIPAL_VOLATILE_STORE_8(uint8_t, ptr, value);
|
||||
}
|
||||
|
||||
static inline void minipal_volatile_store_uint16_t(uint16_t* ptr, uint16_t value)
|
||||
{
|
||||
MINIPAL_VOLATILE_STORE_16(uint16_t, ptr, value);
|
||||
}
|
||||
|
||||
static inline void minipal_volatile_store_uint32_t(uint32_t* ptr, uint32_t value)
|
||||
{
|
||||
MINIPAL_VOLATILE_STORE_32(uint32_t, ptr, value);
|
||||
}
|
||||
|
||||
static inline void minipal_volatile_store_uint64_t(uint64_t* ptr, uint64_t value)
|
||||
{
|
||||
MINIPAL_VOLATILE_STORE_64(uint64_t, ptr, value);
|
||||
}
|
||||
|
||||
static inline void minipal_volatile_store_ptr(void** ptr, void* value)
|
||||
{
|
||||
if (sizeof(uintptr_t) == 4)
|
||||
{
|
||||
uint32_t value32 = (uint32_t)(uintptr_t)value;
|
||||
MINIPAL_VOLATILE_STORE_32(uint32_t, ptr, value32);
|
||||
}
|
||||
else
|
||||
{
|
||||
uint64_t value64 = (uint64_t)(uintptr_t)value;
|
||||
MINIPAL_VOLATILE_STORE_64(uint64_t, ptr, value64);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
#endif /* HAVE_MINIPAL_VOLATILE_H */
|
Loading…
Reference in New Issue