diff --git a/eng/build.sh b/eng/build.sh index c817060a81..d6df50ab3d 100755 --- a/eng/build.sh +++ b/eng/build.sh @@ -320,14 +320,16 @@ if [[ "$__BuildArch" == "armel" ]]; then fi # Configure environment if we are doing a cross compile. -if [ "${__BuildArch}" != "${__HostArch}" -a "${__BuildOS}" != "OSX" ]; then +if [ "${__BuildArch}" != "${__HostArch}" ]; then __CrossBuild=true export CROSSCOMPILE=1 - if ! [[ -n "$ROOTFS_DIR" ]]; then - echo "ERROR: ROOTFS_DIR not set for cross build" - exit 1 + if [ "${__BuildOS}" != "OSX" ]; then + if ! [[ -n "$ROOTFS_DIR" ]]; then + echo "ERROR: ROOTFS_DIR not set for cross build" + exit 1 + fi + echo "ROOTFS_DIR: $ROOTFS_DIR" fi - echo "ROOTFS_DIR: $ROOTFS_DIR" fi mkdir -p "$__IntermediatesDir" @@ -378,8 +380,8 @@ initTargetDistroRid() local passedRootfsDir="" - # Only pass ROOTFS_DIR if cross is specified. - if [ $__CrossBuild == true ]; then + # Only pass ROOTFS_DIR if cross is specified and the current platform is not OSX that doesn't use rootfs + if [ $__CrossBuild == true -a "$__HostOS" != "OSX" ]; then passedRootfsDir=${ROOTFS_DIR} fi diff --git a/eng/cross/tryrun.cmake b/eng/cross/tryrun.cmake index ee5ac59b2c..b6e17ddcc0 100644 --- a/eng/cross/tryrun.cmake +++ b/eng/cross/tryrun.cmake @@ -6,15 +6,60 @@ macro(set_cache_value) set(${ARGV0}__TRYRUN_OUTPUT "dummy output" CACHE STRING "Output from TRY_RUN" FORCE) endmacro() -if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf OR +if(EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv7-alpine-linux-musleabihf OR + EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/armv6-alpine-linux-musleabihf OR EXISTS ${CROSS_ROOTFS}/usr/lib/gcc/aarch64-alpine-linux-musl) SET(ALPINE_LINUX 1) -else() - SET(ALPINE_LINUX 0) +elseif(EXISTS /System/Library/CoreServices) + set(DARWIN 1) endif() -if(TARGET_ARCH_NAME MATCHES "^(armel|arm|arm64|mips64|x86)$") +if(DARWIN) + if(TARGET_ARCH_NAME MATCHES "^(arm64|x64)$") + set_cache_value(FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL_EXITCODE 1) + set_cache_value(GETPWUID_R_SETS_ERRNO_EXITCODE 1) + set_cache_value(HAS_POSIX_SEMAPHORES_EXITCODE 1) + set_cache_value(HAVE_BROKEN_FIFO_KEVENT_EXITCODE 1) + set_cache_value(HAVE_BROKEN_FIFO_SELECT_EXITCODE 1) + set_cache_value(HAVE_CLOCK_MONOTONIC_COARSE_EXITCODE 1) + set_cache_value(HAVE_CLOCK_MONOTONIC_EXITCODE 0) + set_cache_value(HAVE_CLOCK_THREAD_CPUTIME_EXITCODE 0) + set_cache_value(HAVE_CLOCK_GETTIME_NSEC_NP_EXITCODE 0) + set_cache_value(HAVE_COMPATIBLE_ACOS_EXITCODE 0) + set_cache_value(HAVE_COMPATIBLE_ASIN_EXITCODE 0) + set_cache_value(HAVE_COMPATIBLE_ATAN2_EXITCODE 0) + set_cache_value(HAVE_COMPATIBLE_EXP_EXITCODE 1) + set_cache_value(HAVE_COMPATIBLE_ILOGB0_EXITCODE 0) + set_cache_value(HAVE_COMPATIBLE_ILOGBNAN_EXITCODE 1) + set_cache_value(HAVE_COMPATIBLE_LOG10_EXITCODE 0) + set_cache_value(HAVE_COMPATIBLE_LOG_EXITCODE 0) + set_cache_value(HAVE_COMPATIBLE_POW_EXITCODE 0) + set_cache_value(HAVE_FUNCTIONAL_PTHREAD_ROBUST_MUTEXES_EXITCODE 1) + set_cache_value(HAVE_LARGE_SNPRINTF_SUPPORT_EXITCODE 0) + set_cache_value(HAVE_MMAP_DEV_ZERO_EXITCODE 1) + set_cache_value(HAVE_PROCFS_CTL_EXITCODE 1) + set_cache_value(HAVE_PROCFS_MAPS_EXITCODE 1) + set_cache_value(HAVE_PROCFS_STATUS_EXITCODE 1) + set_cache_value(HAVE_PROCFS_STAT_EXITCODE 1) + set_cache_value(HAVE_SCHED_GETCPU_EXITCODE 1) + set_cache_value(HAVE_SCHED_GET_PRIORITY_EXITCODE 0) + set_cache_value(HAVE_VALID_NEGATIVE_INF_POW_EXITCODE 0) + set_cache_value(HAVE_VALID_POSITIVE_INF_POW_EXITCODE 0) + set_cache_value(HAVE_WORKING_CLOCK_GETTIME_EXITCODE 0) + set_cache_value(HAVE_WORKING_GETTIMEOFDAY_EXITCODE 0) + set_cache_value(MMAP_ANON_IGNORES_PROTECTION_EXITCODE 1) + set_cache_value(ONE_SHARED_MAPPING_PER_FILEREGION_PER_PROCESS_EXITCODE 1) + set_cache_value(PTHREAD_CREATE_MODIFIES_ERRNO_EXITCODE 1) + set_cache_value(REALPATH_SUPPORTS_NONEXISTENT_FILES_EXITCODE 1) + set_cache_value(SEM_INIT_MODIFIES_ERRNO_EXITCODE 1) + set_cache_value(SSCANF_CANNOT_HANDLE_MISSING_EXPONENT_EXITCODE 1) + set_cache_value(SSCANF_SUPPORT_ll_EXITCODE 0) + set_cache_value(UNGETC_NOT_RETURN_EOF_EXITCODE 1) + else() + message(FATAL_ERROR "Arch is ${TARGET_ARCH_NAME}. Only arm64 or x64 is supported for OSX cross build!") + endif() +elseif(TARGET_ARCH_NAME MATCHES "^(armel|arm|arm64|mips64|x86)$") set_cache_value(FILE_OPS_CHECK_FERROR_OF_PREVIOUS_CALL_EXITCODE 1) set_cache_value(GETPWUID_R_SETS_ERRNO_EXITCODE 0) set_cache_value(HAS_POSIX_SEMAPHORES_EXITCODE 0) diff --git a/eng/gen-buildsys-clang.sh b/eng/gen-buildsys-clang.sh index 7c2158587c..2f8dd790e1 100755 --- a/eng/gen-buildsys-clang.sh +++ b/eng/gen-buildsys-clang.sh @@ -121,7 +121,9 @@ if [[ -n "$LLDB_INCLUDE_DIR" ]]; then cmake_extra_defines="$cmake_extra_defines -DWITH_LLDB_INCLUDES=$LLDB_INCLUDE_DIR" fi if [ "$CROSSCOMPILE" == "1" ]; then - if ! [[ -n "$ROOTFS_DIR" ]]; then + platform="$(uname)" + # OSX doesn't use rootfs + if ! [[ -n "$ROOTFS_DIR" || "$platform" == "Darwin" ]]; then echo "ROOTFS_DIR not set for crosscompile" exit 1 fi @@ -130,8 +132,13 @@ if [ "$CROSSCOMPILE" == "1" ]; then fi export TARGET_BUILD_ARCH=$build_arch cmake_extra_defines="$cmake_extra_defines -C $CONFIG_DIR/tryrun.cmake" - cmake_extra_defines="$cmake_extra_defines -DCMAKE_TOOLCHAIN_FILE=$CONFIG_DIR/toolchain.cmake" cmake_extra_defines="$cmake_extra_defines -DCLR_UNIX_CROSS_BUILD=1" + + if [[ "$platform" == "Darwin" ]]; then + cmake_extra_defines="$cmake_extra_defines -DCMAKE_SYSTEM_NAME=Darwin" + else + cmake_extra_defines="$cmake_extra_defines -DCMAKE_TOOLCHAIN_FILE=$CONFIG_DIR/toolchain.cmake" + fi fi if [ $OS == "Linux" ]; then linux_id_file="/etc/os-release" diff --git a/src/pal/src/config.h.in b/src/pal/src/config.h.in index 24ea14d39e..c89cd43498 100644 --- a/src/pal/src/config.h.in +++ b/src/pal/src/config.h.in @@ -105,7 +105,7 @@ #cmakedefine01 HAVE_WORKING_CLOCK_GETTIME #cmakedefine01 HAVE_CLOCK_MONOTONIC #cmakedefine01 HAVE_CLOCK_MONOTONIC_COARSE -#cmakedefine01 HAVE_MACH_ABSOLUTE_TIME +#cmakedefine01 HAVE_CLOCK_GETTIME_NSEC_NP #cmakedefine01 HAVE_CLOCK_THREAD_CPUTIME #cmakedefine01 HAVE_PTHREAD_CONDATTR_SETCLOCK #cmakedefine01 STATVFS64_PROTOTYPE_BROKEN diff --git a/src/pal/src/configure.cmake b/src/pal/src/configure.cmake index 8b3fb099a4..0b9f0e6aa0 100644 --- a/src/pal/src/configure.cmake +++ b/src/pal/src/configure.cmake @@ -406,16 +406,14 @@ int main() }" HAVE_CLOCK_MONOTONIC_COARSE) check_cxx_source_runs(" #include -#include +#include int main() { int ret; - mach_timebase_info_data_t timebaseInfo; - ret = mach_timebase_info(&timebaseInfo); - mach_absolute_time(); - exit(ret); -}" HAVE_MACH_ABSOLUTE_TIME) + ret = clock_gettime_nsec_np(CLOCK_UPTIME_RAW); + exit((ret == 0) ? 1 : 0); +}" HAVE_CLOCK_GETTIME_NSEC_NP) check_cxx_source_runs(" #include #include diff --git a/src/pal/src/include/pal/misc.h b/src/pal/src/include/pal/misc.h index 65d59aee60..aa5b2b4852 100644 --- a/src/pal/src/include/pal/misc.h +++ b/src/pal/src/include/pal/misc.h @@ -1,6 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. /*++ @@ -43,17 +42,6 @@ Function : --*/ PAL_time_t __cdecl PAL_time(PAL_time_t*); -/*++ -Function: -TIMEInitialize - -Return value: -TRUE if initialize succeeded -FALSE otherwise - ---*/ -BOOL TIMEInitialize( void ); - /*++ Function : MsgBoxInitialize diff --git a/src/pal/src/init/pal.cpp b/src/pal/src/init/pal.cpp index a38d525cd7..583e98f28e 100644 --- a/src/pal/src/init/pal.cpp +++ b/src/pal/src/init/pal.cpp @@ -369,12 +369,6 @@ Initialize( { palError = ERROR_GEN_FAILURE; - if (FALSE == TIMEInitialize()) - { - ERROR("Unable to initialize TIME support\n"); - goto CLEANUP2; - } - /* Initialize the File mapping critical section. */ if (FALSE == MAPInitialize()) { diff --git a/src/pal/src/misc/time.cpp b/src/pal/src/misc/time.cpp index 192f2fc980..2fddd2ff77 100644 --- a/src/pal/src/misc/time.cpp +++ b/src/pal/src/misc/time.cpp @@ -1,6 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. /*++ @@ -28,43 +27,10 @@ Module Name: #include #include -#if HAVE_MACH_ABSOLUTE_TIME -#include -#include -static mach_timebase_info_data_t s_TimebaseInfo; -#endif - using namespace CorUnix; SET_DEFAULT_DEBUG_CHANNEL(MISC); -/*++ -Function : -TIMEInitialize - -Initialize all Time-related stuff related - -(no parameters) - -Return value : -TRUE if Time support initialization succeeded -FALSE otherwise ---*/ -BOOL TIMEInitialize(void) -{ -#if HAVE_MACH_ABSOLUTE_TIME - kern_return_t machRet; - if ((machRet = mach_timebase_info(&s_TimebaseInfo)) != KERN_SUCCESS) - { - ASSERT("mach_timebase_info() failed: %s\n", mach_error_string(machRet)); - return FALSE; - } -#endif - - return TRUE; -} - - /*++ Function: GetSystemTime @@ -75,8 +41,8 @@ time. The system time is expressed in Coordinated Universal Time Parameters -lpSystemTime - [out] Pointer to a SYSTEMTIME structure to receive the current system date and time. +lpSystemTime + [out] Pointer to a SYSTEMTIME structure to receive the current system date and time. Return Values @@ -101,10 +67,10 @@ GetSystemTime( tt = time(NULL); - /* We can't get millisecond resolution from time(), so we get it from + /* We can't get millisecond resolution from time(), so we get it from gettimeofday() */ timeofday_retval = gettimeofday(&timeval,NULL); - + #if HAVE_GMTIME_R utPtr = &ut; if (gmtime_r(&tt, utPtr) == NULL) @@ -134,20 +100,20 @@ GetSystemTime( { int old_seconds; int new_seconds; - + lpSystemTime->wMilliseconds = timeval.tv_usec/tccMillieSecondsToMicroSeconds; - + old_seconds = utPtr->tm_sec; new_seconds = timeval.tv_sec%60; - - /* just in case we reached the next second in the interval between + + /* just in case we reached the next second in the interval between time() and gettimeofday() */ if( old_seconds!=new_seconds ) { TRACE("crossed seconds boundary; setting milliseconds to 999\n"); lpSystemTime->wMilliseconds = 999; - } - } + } + } EXIT: LOGEXIT("GetSystemTime returns void\n"); PERF_EXIT(GetSystemTime); @@ -164,14 +130,14 @@ use the GetSystemTimeAdjustment function. Parameters -This function has no parameters. +This function has no parameters. Return Values The return value is the number of milliseconds that have elapsed since the system was started. -In the ROTOR implementation the return value is the elapsed time since +In the PAL implementation the return value is the elapsed time since the start of the epoch. --*/ @@ -199,57 +165,28 @@ QueryPerformanceCounter( ) { BOOL retval = TRUE; - PERF_ENTRY(QueryPerformanceCounter); ENTRY("QueryPerformanceCounter()\n"); - do -#if HAVE_MACH_ABSOLUTE_TIME - { - lpPerformanceCount->QuadPart = (LONGLONG)mach_absolute_time(); - } + +#if HAVE_CLOCK_GETTIME_NSEC_NP + lpPerformanceCount->QuadPart = (LONGLONG)clock_gettime_nsec_np(CLOCK_UPTIME_RAW); #elif HAVE_CLOCK_MONOTONIC + struct timespec ts; + int result = clock_gettime(CLOCK_MONOTONIC, &ts); + + if (result != 0) { - struct timespec ts; - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) - { - ASSERT("clock_gettime(CLOCK_MONOTONIC) failed; errno is %d (%s)\n", errno, strerror(errno)); - retval = FALSE; - break; - } - lpPerformanceCount->QuadPart = - (LONGLONG)ts.tv_sec * (LONGLONG)tccSecondsToNanoSeconds + (LONGLONG)ts.tv_nsec; - } -#elif HAVE_GETHRTIME - { - lpPerformanceCount->QuadPart = (LONGLONG)gethrtime(); + ASSERT("clock_gettime(CLOCK_MONOTONIC) failed: %d\n", result); + retval = FALSE; } -#elif HAVE_READ_REAL_TIME + else { - timebasestruct_t tb; - read_real_time(&tb, TIMEBASE_SZ); - if (time_base_to_time(&tb, TIMEBASE_SZ) != 0) - { - ASSERT("time_base_to_time() failed; errno is %d (%s)\n", errno, strerror(errno)); - retval = FALSE; - break; - } - lpPerformanceCount->QuadPart = - (LONGLONG)tb.tb_high * (LONGLONG)tccSecondsToNanoSeconds + (LONGLONG)tb.tb_low; + lpPerformanceCount->QuadPart = + ((LONGLONG)(ts.tv_sec) * (LONGLONG)(tccSecondsToNanoSeconds)) + (LONGLONG)(ts.tv_nsec); } #else - { - struct timeval tv; - if (gettimeofday(&tv, NULL) == -1) - { - ASSERT("gettimeofday() failed; errno is %d (%s)\n", errno, strerror(errno)); - retval = FALSE; - break; - } - lpPerformanceCount->QuadPart = - (LONGLONG)tv.tv_sec * (LONGLONG)tccSecondsToMicroSeconds + (LONGLONG)tv.tv_usec; - } -#endif // HAVE_CLOCK_MONOTONIC - while (false); + #error "The PAL requires either mach_absolute_time() or clock_gettime(CLOCK_MONOTONIC) to be supported." +#endif LOGEXIT("QueryPerformanceCounter\n"); PERF_EXIT(QueryPerformanceCounter); @@ -265,22 +202,21 @@ QueryPerformanceFrequency( BOOL retval = TRUE; PERF_ENTRY(QueryPerformanceFrequency); ENTRY("QueryPerformanceFrequency()\n"); -#if HAVE_MACH_ABSOLUTE_TIME - // use denom == 0 to indicate that s_TimebaseInfo is uninitialised. - if (s_TimebaseInfo.denom == 0) - { - ASSERT("s_TimebaseInfo is uninitialized.\n"); - retval = FALSE; - } - else - { - lpFrequency->QuadPart = (LONGLONG)tccSecondsToNanoSeconds * ((LONGLONG)s_TimebaseInfo.denom / (LONGLONG)s_TimebaseInfo.numer); - } -#elif HAVE_GETHRTIME || HAVE_READ_REAL_TIME || HAVE_CLOCK_MONOTONIC - lpFrequency->QuadPart = (LONGLONG)tccSecondsToNanoSeconds; + +#if HAVE_CLOCK_GETTIME_NSEC_NP + lpFrequency->QuadPart = (LONGLONG)(tccSecondsToNanoSeconds); +#elif HAVE_CLOCK_MONOTONIC + // clock_gettime() returns a result in terms of nanoseconds rather than a count. This + // means that we need to either always scale the result by the actual resolution (to + // get a count) or we need to say the resolution is in terms of nanoseconds. We prefer + // the latter since it allows the highest throughput and should minimize error propagated + // to the user. + + lpFrequency->QuadPart = (LONGLONG)(tccSecondsToNanoSeconds); #else - lpFrequency->QuadPart = (LONGLONG)tccSecondsToMicroSeconds; -#endif // HAVE_MACH_ABSOLUTE_TIME + #error "The PAL requires either mach_absolute_time() or clock_gettime(CLOCK_MONOTONIC) to be supported." +#endif + LOGEXIT("QueryPerformanceFrequency\n"); PERF_EXIT(QueryPerformanceFrequency); return retval; @@ -299,62 +235,43 @@ PALAPI ULONGLONG GetTickCount64() { - ULONGLONG retval = 0; + LONGLONG retval = 0; + +#if HAVE_CLOCK_GETTIME_NSEC_NP + return (LONGLONG)clock_gettime_nsec_np(CLOCK_UPTIME_RAW) / (LONGLONG)(tccMillieSecondsToNanoSeconds); +#elif HAVE_CLOCK_MONOTONIC || HAVE_CLOCK_MONOTONIC_COARSE + struct timespec ts; -#if HAVE_MACH_ABSOLUTE_TIME - { - // use denom == 0 to indicate that s_TimebaseInfo is uninitialised. - if (s_TimebaseInfo.denom == 0) - { - ASSERT("s_TimebaseInfo is uninitialized.\n"); - goto EXIT; - } - retval = (mach_absolute_time() * s_TimebaseInfo.numer / s_TimebaseInfo.denom) / tccMillieSecondsToNanoSeconds; - } -#elif HAVE_CLOCK_MONOTONIC_COARSE || HAVE_CLOCK_MONOTONIC - { - clockid_t clockType = #if HAVE_CLOCK_MONOTONIC_COARSE - CLOCK_MONOTONIC_COARSE; // good enough resolution, fastest speed + // CLOCK_MONOTONIC_COARSE has enough precision for GetTickCount but + // doesn't have the same overhead as CLOCK_MONOTONIC. This allows + // overall higher throughput. See dotnet/coreclr#2257 for more details. + + const clockid_t clockType = CLOCK_MONOTONIC_COARSE; #else - CLOCK_MONOTONIC; + const clockid_t clockType = CLOCK_MONOTONIC; #endif - struct timespec ts; - if (clock_gettime(clockType, &ts) != 0) - { - ASSERT("clock_gettime(CLOCK_MONOTONIC*) failed; errno is %d (%s)\n", errno, strerror(errno)); - goto EXIT; - } - retval = (ts.tv_sec * tccSecondsToMillieSeconds)+(ts.tv_nsec / tccMillieSecondsToNanoSeconds); - } -#elif HAVE_GETHRTIME + + int result = clock_gettime(clockType, &ts); + + if (result != 0) { - retval = (ULONGLONG)(gethrtime() / tccMillieSecondsToNanoSeconds); +#if HAVE_CLOCK_MONOTONIC_COARSE + ASSERT("clock_gettime(CLOCK_MONOTONIC_COARSE) failed: %d\n", result); +#else + ASSERT("clock_gettime(CLOCK_MONOTONIC) failed: %d\n", result); +#endif + retval = FALSE; } -#elif HAVE_READ_REAL_TIME + else { - timebasestruct_t tb; - read_real_time(&tb, TIMEBASE_SZ); - if (time_base_to_time(&tb, TIMEBASE_SZ) != 0) - { - ASSERT("time_base_to_time() failed; errno is %d (%s)\n", errno, strerror(errno)); - goto EXIT; - } - retval = (tb.tb_high * tccSecondsToMillieSeconds)+(tb.tb_low / tccMillieSecondsToNanoSeconds); + retval = ((LONGLONG)(ts.tv_sec) * (LONGLONG)(tccSecondsToMillieSeconds)) + ((LONGLONG)(ts.tv_nsec) / (LONGLONG)(tccMillieSecondsToNanoSeconds)); } #else - { - struct timeval tv; - if (gettimeofday(&tv, NULL) == -1) - { - ASSERT("gettimeofday() failed; errno is %d (%s)\n", errno, strerror(errno)); - goto EXIT; - } - retval = (tv.tv_sec * tccSecondsToMillieSeconds) + (tv.tv_usec / tccMillieSecondsToMicroSeconds); - } -#endif // HAVE_CLOCK_MONOTONIC -EXIT: - return retval; + #error "The PAL requires either mach_absolute_time() or clock_gettime(CLOCK_MONOTONIC) to be supported." +#endif + + return (ULONGLONG)(retval); } /*++