text: $NetBSD: patch-Modules_timemodule.c,v 1.2 2020/11/18 10:51:01 sjmulder Exp $
  
  Support for macOS 11 and Apple Silicon (ARM). Mostly backported from:
  https://github.com/python/cpython/pull/22855
  
  --- Modules/timemodule.c.orig	2020-09-23 12:36:32.000000000 +0000
  +++ Modules/timemodule.c
  @@ -48,6 +48,15 @@
   #define _Py_tzname tzname
   #endif
   
  +#if defined(__APPLE__ ) && defined(__has_builtin)
  +#  if __has_builtin(__builtin_available)
  +#    define HAVE_CLOCK_GETTIME_RUNTIME __builtin_available(macOS 10.12, iOS 10.0, tvOS 10.0, watchOS 3.0, *)
  +#  endif
  +#endif
  +#ifndef HAVE_CLOCK_GETTIME_RUNTIME
  +#  define HAVE_CLOCK_GETTIME_RUNTIME 1
  +#endif
  +
   #define SEC_TO_NS (1000 * 1000 * 1000)
   
   /* Forward declarations */
  @@ -146,6 +155,16 @@ perf_counter(_Py_clock_info_t *info)
   }
   
   #ifdef HAVE_CLOCK_GETTIME
  +
  +#ifdef __APPLE__
  +/*
  + * The clock_* functions will be removed from the module
  + * dict entirely when the C API is not available.
  + */
  +#pragma clang diagnostic push
  +#pragma clang diagnostic ignored "-Wunguarded-availability"
  +#endif
  +
   static PyObject *
   time_clock_gettime(PyObject *self, PyObject *args)
   {
  @@ -294,6 +313,11 @@ PyDoc_STRVAR(clock_getres_doc,
   "clock_getres(clk_id) -> floating point number\n\
   \n\
   Return the resolution (precision) of the specified clock clk_id.");
  +
  +#ifdef __APPLE__
  +#pragma clang diagnostic pop
  +#endif
  +
   #endif   /* HAVE_CLOCK_GETRES */
   
   #ifdef HAVE_PTHREAD_GETCPUCLOCKID
  @@ -1159,31 +1183,35 @@ _PyTime_GetProcessTimeWithInfo(_PyTime_t
   #if defined(HAVE_CLOCK_GETTIME) \
       && (defined(CLOCK_PROCESS_CPUTIME_ID) || defined(CLOCK_PROF))
       struct timespec ts;
  +
  +    if (HAVE_CLOCK_GETTIME_RUNTIME) {
  +
   #ifdef CLOCK_PROF
  -    const clockid_t clk_id = CLOCK_PROF;
  -    const char *function = "clock_gettime(CLOCK_PROF)";
  +        const clockid_t clk_id = CLOCK_PROF;
  +        const char *function = "clock_gettime(CLOCK_PROF)";
   #else
  -    const clockid_t clk_id = CLOCK_PROCESS_CPUTIME_ID;
  -    const char *function = "clock_gettime(CLOCK_PROCESS_CPUTIME_ID)";
  +        const clockid_t clk_id = CLOCK_PROCESS_CPUTIME_ID;
  +        const char *function = "clock_gettime(CLOCK_PROCESS_CPUTIME_ID)";
   #endif
   
  -    if (clock_gettime(clk_id, &ts) == 0) {
  -        if (info) {
  -            struct timespec res;
  -            info->implementation = function;
  -            info->monotonic = 1;
  -            info->adjustable = 0;
  -            if (clock_getres(clk_id, &res)) {
  -                PyErr_SetFromErrno(PyExc_OSError);
  -                return -1;
  +        if (clock_gettime(clk_id, &ts) == 0) {
  +            if (info) {
  +                struct timespec res;
  +                info->implementation = function;
  +                info->monotonic = 1;
  +                info->adjustable = 0;
  +                if (clock_getres(clk_id, &res)) {
  +                    PyErr_SetFromErrno(PyExc_OSError);
  +                    return -1;
  +                }
  +                info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
               }
  -            info->resolution = res.tv_sec + res.tv_nsec * 1e-9;
  -        }
   
  -        if (_PyTime_FromTimespec(tp, &ts) < 0) {
  -            return -1;
  +            if (_PyTime_FromTimespec(tp, &ts) < 0) {
  +                return -1;
  +            }
  +            return 0;
           }
  -        return 0;
       }
   #endif
   
  @@ -1346,6 +1374,18 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t
   
   #elif defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_PROCESS_CPUTIME_ID)
   #define HAVE_THREAD_TIME
  +
  +#if defined(__APPLE__) && defined(__has_attribute)
  +# if __has_attribute(availability)
  +static int
  +_PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
  +     __attribute__((availability(macos, introduced=10.12)))
  +     __attribute__((availability(ios, introduced=10.0)))
  +     __attribute__((availability(tvos, introduced=10.0)))
  +     __attribute__((availability(watchos, introduced=3.0)));
  +# endif
  +#endif
  +
   static int
   _PyTime_GetThreadTimeWithInfo(_PyTime_t *tp, _Py_clock_info_t *info)
   {
  @@ -1377,6 +1417,15 @@ _PyTime_GetThreadTimeWithInfo(_PyTime_t
   #endif
   
   #ifdef HAVE_THREAD_TIME
  +#ifdef __APPLE__
  +/*
  + * The clock_* functions will be removed from the module
  + * dict entirely when the C API is not available.
  + */
  +#pragma clang diagnostic push
  +#pragma clang diagnostic ignored "-Wunguarded-availability"
  +#endif
  +
   static PyObject *
   time_thread_time(PyObject *self, PyObject *unused)
   {
  @@ -1407,6 +1456,11 @@ PyDoc_STRVAR(thread_time_ns_doc,
   \n\
   Thread time for profiling as nanoseconds:\n\
   sum of the kernel and user-space CPU time.");
  +
  +#ifdef __APPLE__
  +#pragma clang diagnostic pop
  +#endif
  +
   #endif
   
   
  @@ -1456,9 +1510,19 @@ time_get_clock_info(PyObject *self, PyOb
       }
   #ifdef HAVE_THREAD_TIME
       else if (strcmp(name, "thread_time") == 0) {
  -        if (_PyTime_GetThreadTimeWithInfo(&t, &info) < 0) {
  +
  +#ifdef __APPLE__
  +        if (HAVE_CLOCK_GETTIME_RUNTIME) {
  +#endif
  +            if (_PyTime_GetThreadTimeWithInfo(&t, &info) < 0) {
  +                return NULL;
  +            }
  +#ifdef __APPLE__
  +        } else {
  +            PyErr_SetString(PyExc_ValueError, "unknown clock");
               return NULL;
           }
  +#endif
       }
   #endif
       else {
  @@ -1757,43 +1821,88 @@ PyInit_time(void)
       if (m == NULL)
           return NULL;
   
  +#if defined(__APPLE__) && defined(HAVE_CLOCK_GETTIME)
  +    if (HAVE_CLOCK_GETTIME_RUNTIME) {
  +        /* pass: ^^^ cannot use '!' here */
  +    } else {
  +        PyObject* dct = PyModule_GetDict(m);
  +        if (dct == NULL) {
  +            return -1;
  +        }
  +
  +        if (PyDict_DelItemString(dct, "clock_gettime") == -1) {
  +            PyErr_Clear();
  +        }
  +        if (PyDict_DelItemString(dct, "clock_gettime_ns") == -1) {
  +            PyErr_Clear();
  +        }
  +        if (PyDict_DelItemString(dct, "clock_settime") == -1) {
  +            PyErr_Clear();
  +        }
  +        if (PyDict_DelItemString(dct, "clock_settime_ns") == -1) {
  +            PyErr_Clear();
  +        }
  +        if (PyDict_DelItemString(dct, "clock_getres") == -1) {
  +            PyErr_Clear();
  +        }
  +    }
  +#endif
  +#if defined(__APPLE__) && defined(HAVE_THREAD_TIME)
  +    if (HAVE_CLOCK_GETTIME_RUNTIME) {
  +        /* pass: ^^^ cannot use '!' here */
  +    } else {
  +        PyObject* dct = PyModule_GetDict(m);
  +
  +        if (PyDict_DelItemString(dct, "thread_time") == -1) {
  +            PyErr_Clear();
  +        }
  +        if (PyDict_DelItemString(dct, "thread_time_ns") == -1) {
  +            PyErr_Clear();
  +        }
  +    }
  +#endif
       /* Set, or reset, module variables like time.timezone */
       if (init_timezone(m) < 0) {
           return NULL;
       }
   
   #if defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_CLOCK_GETRES)
  +    if (HAVE_CLOCK_GETTIME_RUNTIME) {
   
   #ifdef CLOCK_REALTIME
  -    PyModule_AddIntMacro(m, CLOCK_REALTIME);
  +        PyModule_AddIntMacro(m, CLOCK_REALTIME);
   #endif
  +
   #ifdef CLOCK_MONOTONIC
  -    PyModule_AddIntMacro(m, CLOCK_MONOTONIC);
  +        PyModule_AddIntMacro(m, CLOCK_MONOTONIC);
   #endif
   #ifdef CLOCK_MONOTONIC_RAW
  -    PyModule_AddIntMacro(m, CLOCK_MONOTONIC_RAW);
  +        PyModule_AddIntMacro(m, CLOCK_MONOTONIC_RAW);
   #endif
  +
   #ifdef CLOCK_HIGHRES
  -    PyModule_AddIntMacro(m, CLOCK_HIGHRES);
  +        PyModule_AddIntMacro(m, CLOCK_HIGHRES);
   #endif
   #ifdef CLOCK_PROCESS_CPUTIME_ID
  -    PyModule_AddIntMacro(m, CLOCK_PROCESS_CPUTIME_ID);
  +        PyModule_AddIntMacro(m, CLOCK_PROCESS_CPUTIME_ID);
   #endif
  +
   #ifdef CLOCK_THREAD_CPUTIME_ID
  -    PyModule_AddIntMacro(m, CLOCK_THREAD_CPUTIME_ID);
  +        PyModule_AddIntMacro(m, CLOCK_THREAD_CPUTIME_ID);
   #endif
   #ifdef CLOCK_PROF
  -    PyModule_AddIntMacro(m, CLOCK_PROF);
  +        PyModule_AddIntMacro(m, CLOCK_PROF);
   #endif
   #ifdef CLOCK_BOOTTIME
  -    PyModule_AddIntMacro(m, CLOCK_BOOTTIME);
  +        PyModule_AddIntMacro(m, CLOCK_BOOTTIME);
   #endif
   #ifdef CLOCK_UPTIME
  -    PyModule_AddIntMacro(m, CLOCK_UPTIME);
  +        PyModule_AddIntMacro(m, CLOCK_UPTIME);
   #endif
   #ifdef CLOCK_UPTIME_RAW
  -    PyModule_AddIntMacro(m, CLOCK_UPTIME_RAW);
  +        PyModule_AddIntMacro(m, CLOCK_UPTIME_RAW);
   #endif
  +    }
   
   #endif  /* defined(HAVE_CLOCK_GETTIME) || defined(HAVE_CLOCK_SETTIME) || defined(HAVE_CLOCK_GETRES) */
   
  