Port cross oxs-arm64 build support from runtime (#1642)
authorSteve MacLean <Steve.MacLean@microsoft.com>
Sat, 10 Oct 2020 15:16:49 +0000 (11:16 -0400)
committerGitHub <noreply@github.com>
Sat, 10 Oct 2020 15:16:49 +0000 (11:16 -0400)
* Add osx-arm64 support to tryrun.cmake
* Use clock_gettime_nsec_np for osx time source
* Cross build changes

eng/build.sh
eng/cross/tryrun.cmake
eng/gen-buildsys-clang.sh
src/pal/src/config.h.in
src/pal/src/configure.cmake
src/pal/src/include/pal/misc.h
src/pal/src/init/pal.cpp
src/pal/src/misc/time.cpp

index c817060a81356af574a057397c3108a8a91bbc4a..d6df50ab3d29a798c39aaacef734b3c8cc726bf5 100755 (executable)
@@ -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
 
index ee5ac59b2c934bcd7abee3554665192d7dc7458f..b6e17ddcc06da9b299dad43ff529c8e6563ef8ea 100644 (file)
@@ -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)
index 7c2158587cc445e4f23ef3abbc55472d1b500acf..2f8dd790e1969b5ff6c39b1da8e6064035e9d624 100755 (executable)
@@ -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"
index 24ea14d39e0aad1c19a4ed45ad5477ec16993f5e..c89cd43498d089fa870855607c129e4217b8bd32 100644 (file)
 #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
index 8b3fb099a429596627f7c58d4a67ee578f71f077..0b9f0e6aa060f85f08a656e66922656d0a3865ac 100644 (file)
@@ -406,16 +406,14 @@ int main()
 }" HAVE_CLOCK_MONOTONIC_COARSE)
 check_cxx_source_runs("
 #include <stdlib.h>
-#include <mach/mach_time.h>
+#include <time.h>
 
 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 <stdlib.h>
 #include <time.h>
index 65d59aee60bbce03b5940d8c048752b3cac5a90e..aa5b2b4852b6ea5ce270bc32b3b00da7623e5e74 100644 (file)
@@ -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
index a38d525cd737e8bb89fe9fe98fa4568b878aeaaa..583e98f28e594a312c9bd8eaaa588d4a9b19bdb7 100644 (file)
@@ -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())
         {
index 192f2fc9807ce4d63e3a773af261f93a55f92bf5..2fddd2ff770c24fe0184a82eccc1a4cf8231cfc9 100644 (file)
@@ -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 @@ Abstract:
 #include <string.h>
 #include <sched.h>
 
-#if HAVE_MACH_ABSOLUTE_TIME
-#include <mach/mach.h>
-#include <mach/mach_time.h>
-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);
 }
 
 /*++