[vlc-devel] [PATCH] compat: add clock_gettime, clock_nanosleep for darwin

Rémi Denis-Courmont remi at remlab.net
Thu Feb 27 16:27:35 CET 2020


Hi,

- Using inline in a C file seems useless.
- Testing for cancellation on error other than EINTR is suspicious.
- Not sure LIBOBJ can be called conditionally.

Le 27 février 2020 16:56:01 GMT+02:00, Marvin Scholz <epirat07 at gmail.com> a écrit :
>---
> compat/clock_gettime.c   | 131 +++++++++++++++++++++++++++++++++++++++
> compat/clock_nanosleep.c | 108 ++++++++++++++++++++++++++++++++
> configure.ac             |   6 ++
> include/vlc_fixups.h     |  18 ++++++
> 4 files changed, 263 insertions(+)
> create mode 100644 compat/clock_gettime.c
> create mode 100644 compat/clock_nanosleep.c
>
>diff --git a/compat/clock_gettime.c b/compat/clock_gettime.c
>new file mode 100644
>index 0000000000..fb3312fd2d
>--- /dev/null
>+++ b/compat/clock_gettime.c
>@@ -0,0 +1,131 @@
>+/*****************************************************************************
>+ * clock_gettime.c: POSIX clock_gettime() replacement
>+
>*****************************************************************************
>+ * Copyright © 2020 VLC authors and VideoLAN
>+ *
>+ * Author: Marvin Scholz <epirat07 at gmail dot com>
>+ *
>+ * This program is free software; you can redistribute it and/or
>modify it
>+ * under the terms of the GNU Lesser General Public License as
>published by
>+ * the Free Software Foundation; either version 2.1 of the License, or
>+ * (at your option) any later version.
>+ *
>+ * This program is distributed in the hope that it will be useful,
>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>+ * GNU Lesser General Public License for more details.
>+ *
>+ * You should have received a copy of the GNU Lesser General Public
>License
>+ * along with this program; if not, write to the Free Software
>Foundation,
>+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
>+
>*****************************************************************************/
>+
>+#ifndef __APPLE__
>+# error clock_gettime not implemented on your platform!
>+#endif
>+
>+#ifdef HAVE_CONFIG_H
>+# include <config.h>
>+#endif
>+
>+#define _DARWIN_C_SOURCE
>+#define _POSIX_C_SOURCE  200809L
>+
>+#include <sys/errno.h>
>+#include <sys/types.h>
>+#include <sys/time.h>
>+#include <sys/sysctl.h>
>+#include <time.h>
>+
>+/**
>+ * Get the absolute time at which the system was booted
>+ * 
>+ * This time is changed whenever the clock is adjusted to
>+ * correctly reflect the boot time with the adjusted clock,
>+ * so just querying it once and reusing the value is not safe.
>+ *
>+ * \param[out]  tv   Timeval struct to write the boottime to
>+ * 
>+ * \note
>+ * The boot time only has microsecond precision
>+ *
>+ * \return 0 on success, else -1 and errno set
>+ */
>+static inline int vlc__get_system_boottime(struct timeval *tv)
>+{
>+    int ret = sysctl((int[]){ CTL_KERN, KERN_BOOTTIME }, 2,
>+                     tv, &(size_t){ sizeof(*tv) }, NULL, 0);
>+
>+    if (ret != 0)
>+        return errno;
>+
>+    return 0;
>+}
>+
>+/**
>+ * Get the monotonic time (CLOCK_MONOTONIC)
>+ * 
>+ * Calculates a monotically incrasing time since system boot
>+ * that continues to increment when the syste is asleep.
>+ * 
>+ * Warnings to everyone trying to simplify this:
>+ * - Using mach_continuous_time is not equivalent to this, see
>+ *   the darwin manpage about CLOCK_MONOTONIC_RAW for an explanation.
>+ * - Using mach_absolute_time is not equivalent to this, as it does
>+ *   not continue to increment when the system is asleep.
>+ * - The boot time is queried twice in a loop and only used if both
>+ *   match. This is done to detect if the boot time change since we
>+ *   obtained the current time of day, as the boot time can change
>+ *   when the system wallclock is adjusted, as that will adjust the
>+ *   boot time accordingly.
>+ *
>+ * \param[out]  tv   Timeval struct to write the monotonic time to
>+ *
>+ * \return 0 on success, else -1 and errno set
>+ */
>+static int vlc__get_monotonic(struct timeval *tv)
>+{
>+    int ret;
>+    struct timeval currenttime;
>+    struct timeval boottime_begin;
>+    struct timeval boottime_end;
>+
>+    do {
>+        ret = vlc__get_system_boottime(&boottime_begin);
>+        if (ret != 0)
>+            return ret;
>+
>+        ret = gettimeofday(&currenttime, NULL);
>+        if (ret != 0)
>+            return ret;
>+
>+        ret = vlc__get_system_boottime(&boottime_end);
>+        if (ret != 0)
>+            return ret;
>+    } while (timercmp(&boottime_begin, &boottime_end, !=));
>+
>+    timersub(&currenttime, &boottime_begin, tv);
>+    return 0;
>+}
>+
>+int clock_gettime(clockid_t clock_id, struct timespec *tp)
>+{
>+    int ret = 0;
>+    struct timeval tv;
>+
>+    switch (clock_id) {
>+        case CLOCK_MONOTONIC:
>+            ret = vlc__get_monotonic(&tv);
>+            break;
>+        case CLOCK_REALTIME:
>+            ret = gettimeofday(&tv, NULL);
>+            break;
>+        default:
>+            errno = EINVAL;
>+            return -1;
>+    }
>+
>+    if (ret == 0)
>+        TIMEVAL_TO_TIMESPEC(&tv, tp);
>+    return ret;
>+}
>diff --git a/compat/clock_nanosleep.c b/compat/clock_nanosleep.c
>new file mode 100644
>index 0000000000..f5cab11039
>--- /dev/null
>+++ b/compat/clock_nanosleep.c
>@@ -0,0 +1,108 @@
>+/*****************************************************************************
>+ * clock_nanosleep.c: POSIX clock_nanosleep() replacement
>+
>*****************************************************************************
>+ * Copyright © 2020 VLC authors and VideoLAN
>+ *
>+ * Author: Marvin Scholz <epirat07 at gmail dot com>
>+ *
>+ * This program is free software; you can redistribute it and/or
>modify it
>+ * under the terms of the GNU Lesser General Public License as
>published by
>+ * the Free Software Foundation; either version 2.1 of the License, or
>+ * (at your option) any later version.
>+ *
>+ * This program is distributed in the hope that it will be useful,
>+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
>+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
>+ * GNU Lesser General Public License for more details.
>+ *
>+ * You should have received a copy of the GNU Lesser General Public
>License
>+ * along with this program; if not, write to the Free Software
>Foundation,
>+ * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
>+
>*****************************************************************************/
>+
>+#ifndef __APPLE__
>+# error clock_nanosleep not implemented on your platform!
>+#endif
>+
>+#ifdef HAVE_CONFIG_H
>+# include <config.h>
>+#endif
>+
>+#define _DARWIN_C_SOURCE
>+#define _POSIX_C_SOURCE  200809L
>+
>+#include <pthread.h>
>+#include <sys/errno.h>
>+#include <sys/types.h>
>+#include <sys/time.h>
>+#include <sys/sysctl.h>
>+#include <mach/clock_types.h>
>+
>+#define timespecs_sub(tsa, tsb, tsr)                                \
>+	do {                                                            \
>+	        (tsr)->tv_sec = (tsa)->tv_sec - (tsb)->tv_sec;          \
>+	        (tsr)->tv_nsec = (tsa)->tv_nsec - (tsb)->tv_nsec;       \
>+	        if ((tsr)->tv_nsec < 0) {                               \
>+	                (tsr)->tv_sec--;                                \
>+	                (tsr)->tv_nsec += NSEC_PER_SEC;                 \
>+	        }                                                       \
>+	} while (0)
>+
>+#define timespec_zero(ts) \
>+	((ts)->tv_sec == 0 && (ts)->tv_nsec == 0)
>+
>+int clock_nanosleep(clockid_t clock_id, int flags,
>+        const struct timespec *rqtp, struct timespec *rmtp)
>+{
>+	int err = EINVAL;
>+	struct timespec ts_rel;
>+
>+	// Validate timespec
>+	if (rqtp == NULL || rqtp->tv_sec < 0 ||
>+		rqtp->tv_nsec < 0 || (unsigned long)rqtp->tv_nsec >= NSEC_PER_SEC)
>+		goto error;
>+
>+	if (flags == TIMER_ABSTIME) {
>+		struct timespec ts_now;
>+
>+		// We don't support waiting for a absolute
>+		// wallclock time currently
>+		if (clock_id == CLOCK_REALTIME) {
>+			err = ENOTSUP;
>+			goto error;
>+		}
>+
>+		// Get current time with requested clock
>+		if (clock_gettime(clock_id, &ts_now) != 0) {
>+			err = errno;
>+			goto error;
>+		}
>+
>+		// Calculate relative timespec
>+		timespecs_sub(rqtp, &ts_now, &ts_rel);
>+
>+		// Check if time already elapsed
>+		if (ts_rel.tv_sec < 0 || timespec_zero(&ts_rel)) {
>+			pthread_testcancel();
>+			return 0;
>+		}
>+	} else if (flags == 0) {
>+		ts_rel = *rqtp;
>+	} else {
>+		// Invalid flags
>+		goto error;
>+	}
>+
>+	switch (clock_id) {
>+		case CLOCK_MONOTONIC:
>+		case CLOCK_REALTIME:
>+			return nanosleep(&ts_rel, rmtp);
>+		default:
>+			goto error;
>+	}
>+
>+error:
>+	pthread_testcancel();
>+	errno = err;
>+	return -1;
>+}
>diff --git a/configure.ac b/configure.ac
>index bc1874cb97..c20ab3c75c 100644
>--- a/configure.ac
>+++ b/configure.ac
>@@ -179,6 +179,12 @@ case "${host_os}" in
>VLC_ADD_LIBS([libvlc
>vlc],[-Wl,-undefined,dynamic_lookup,-framework,AppKit])
>VLC_ADD_LIBS([libvlccore],[-Wl,-framework,CoreFoundation,-framework,CoreServices])
> 
>+    dnl macOS 10.11 lacks clock_gettime, introduced with 10.12
>+    AC_LIBOBJ([clock_gettime])
>+    dnl macOS lacks clock_nanosleep
>+    AC_LIBOBJ([clock_nanosleep])
>+    AC_CHECK_FUNCS([clock_gettime clock_nanosleep])
>+
>     AC_EGREP_CPP(yes,
>             [#import <TargetConditionals.h>
>              #if TARGET_OS_IPHONE
>diff --git a/include/vlc_fixups.h b/include/vlc_fixups.h
>index 8fd01da0ce..a296db0c32 100644
>--- a/include/vlc_fixups.h
>+++ b/include/vlc_fixups.h
>@@ -658,6 +658,24 @@ FILE *vlc_win32_tmpfile(void);
> 
> #ifdef __APPLE__
> # define fdatasync fsync
>+
>+# include <time.h>
>+# ifndef TIMER_ABSTIME
>+#  define TIMER_ABSTIME 0x01
>+# endif
>+# ifndef CLOCK_REALTIME
>+#  define CLOCK_REALTIME 0
>+# endif
>+# ifndef CLOCK_MONOTONIC
>+#  define CLOCK_MONOTONIC 6
>+# endif
>+# ifndef HAVE_CLOCK_GETTIME
>+int clock_gettime(clockid_t clock_id, struct timespec *tp);
>+# endif
>+# ifndef HAVE_CLOCK_NANOSLEEP
>+int clock_nanosleep(clockid_t clock_id, int flags,
>+        const struct timespec *rqtp, struct timespec *rmtp);
>+# endif
> #endif
> 
> #ifdef __cplusplus
>-- 
>2.21.1 (Apple Git-122.3)
>
>_______________________________________________
>vlc-devel mailing list
>To unsubscribe or modify your subscription options:
>https://mailman.videolan.org/listinfo/vlc-devel

-- 
Envoyé de mon appareil Android avec Courriel K-9 Mail. Veuillez excuser ma brièveté.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mailman.videolan.org/pipermail/vlc-devel/attachments/20200227/2ac14fed/attachment.html>


More information about the vlc-devel mailing list