From 63fb0bedb8077ac1e6b6337f198b4eae30813fbc Mon Sep 17 00:00:00 2001
From: Gaius Mulley <gaiusmod2@gmail.com>
Date: Sat, 12 Aug 2023 18:17:41 +0100
Subject: [PATCH] PR modula2/110779 SysClock can not read the clock (Darwin
 portability fixes)

This patch adds corrections to defensively check against glibc functions,
structures and contains fallbacks.  These fixes were required under Darwin.

gcc/m2/ChangeLog:

	PR modula2/110779
	* gm2-libs-iso/SysClock.mod (EpochTime): New procedure.
	(GetClock): Call EpochTime if the C time functions are
	unavailable.
	* gm2-libs-iso/wrapclock.def (istimezone): New function
	definition.

libgm2/ChangeLog:

	PR modula2/110779
	* configure: Regenerate.
	* configure.ac: Provide special case test for Darwin cross
	configuration.
	(GLIBCXX_CONFIGURE): New statement.
	(GLIBCXX_CHECK_GETTIMEOFDAY): New statement.
	(GLIBCXX_ENABLE_LIBSTDCXX_TIME): New statement.
	* libm2iso/wrapclock.cc: New sys/time.h conditional include.
	(sys/syscall.h): Conditional include.
	(unistd.h): Conditional include.
	(GetTimeRealtime): Re-implement.
	(SetTimeRealtime): Re-implement.
	(timezone): Re-implement.
	(istimezone): New function.
	(daylight): Re-implement.
	(isdst): Re-implement.
	(tzname): Re-implement.

Signed-off-by: Gaius Mulley <gaiusmod2@gmail.com>
---
 gcc/m2/gm2-libs-iso/SysClock.mod  |  34 +++--
 gcc/m2/gm2-libs-iso/wrapclock.def |  12 ++
 libgm2/configure                  |  40 +++++-
 libgm2/configure.ac               |  36 ++++++
 libgm2/libm2iso/wrapclock.cc      | 201 +++++++++++++++++-------------
 5 files changed, 227 insertions(+), 96 deletions(-)

diff --git a/gcc/m2/gm2-libs-iso/SysClock.mod b/gcc/m2/gm2-libs-iso/SysClock.mod
index 3313309d19ad..56d5503a87c5 100644
--- a/gcc/m2/gm2-libs-iso/SysClock.mod
+++ b/gcc/m2/gm2-libs-iso/SysClock.mod
@@ -173,6 +173,26 @@ BEGIN
 END ExtractDate ;
 
 
+(*
+   EpochTime - assigns all fields of userData to 0 or FALSE.
+*)
+
+PROCEDURE EpochTime (VAR userData: DateTime) ;
+BEGIN
+   WITH userData DO
+      second := 0 ;
+      minute :=  0 ;
+      hour := 0 ;
+      year := 0 ;
+      month := 0 ;
+      day := 0 ;
+      fractions := 0 ;
+      zone := 0 ;
+      summerTimeFlag := FALSE
+   END
+END EpochTime ;
+
+
 PROCEDURE GetClock (VAR userData: DateTime) ;
 (* Assigns local date and time of the day to userData *)
 VAR
@@ -207,10 +227,10 @@ BEGIN
                summerTimeFlag := (isdst () = 1)
             END
          ELSE
-            HALT
+            EpochTime (userData)
          END
       ELSE
-         HALT
+         EpochTime (userData)
       END ;
       ts := KillTimespec (ts)
    END
@@ -310,13 +330,11 @@ BEGIN
                            userData.month, userData.year) ;
       offset := timezone () ;
       sec := VAL (LONGINT, sec) - offset ;
-      IF SetTimespec (ts, sec, nano) = 0
-      THEN
-         HALT
-      END ;
-      IF SetTimeRealtime (ts) # 0
+      IF SetTimespec (ts, sec, nano) = 1
       THEN
-         HALT
+         IF SetTimeRealtime (ts) = 0
+         THEN
+         END
       END ;
       ts := KillTimespec (ts)
    END
diff --git a/gcc/m2/gm2-libs-iso/wrapclock.def b/gcc/m2/gm2-libs-iso/wrapclock.def
index 1dd12e1c6b89..9f5f28624448 100644
--- a/gcc/m2/gm2-libs-iso/wrapclock.def
+++ b/gcc/m2/gm2-libs-iso/wrapclock.def
@@ -36,11 +36,23 @@ TYPE
    timezone - return the glibc timezone value.
               This contains the difference between UTC and the latest
               local standard time, in seconds west of UTC.
+              If the underlying timezone is unavailable and
+              clock_gettime, localtime_r, tm_gmtoff
+              is unavailable then 0 is returned.
 *)
 
 PROCEDURE timezone () : LONGINT ;
 
 
+(*
+   istimezone returns 1 if timezone in wrapclock.cc can resolve the
+              timezone value using the timezone C library call or by using
+              clock_gettime, localtime_r and tm_gmtoff.
+*)
+
+PROCEDURE istimezone () : INTEGER ;
+
+
 (*
    daylight - return the glibc daylight value.
               This variable has a nonzero value if Daylight Saving
diff --git a/libgm2/configure b/libgm2/configure
index 74f93ac5eec3..072d584544ec 100755
--- a/libgm2/configure
+++ b/libgm2/configure
@@ -3976,6 +3976,42 @@ test -n "$target_alias" &&
 target_alias=${target_alias-$host_alias}
 
 
+if test "$build" != "$host"; then
+  # We are being configured with some form of cross compiler.
+  GLIBCXX_IS_NATIVE=false
+  case "$host","$target" in
+    # Darwin crosses can use the host system's libraries and headers,
+    # because of the fat library support.  Of course, it must be the
+    # same version of Darwin on both sides.  Allow the user to
+    # just say --target=foo-darwin without a version number to mean
+    # "the version on this system".
+      *-*-darwin*,*-*-darwin*)
+	hostos=`echo $host | sed 's/.*-darwin/darwin/'`
+	targetos=`echo $target | sed 's/.*-darwin/darwin/'`
+	if test $hostos = $targetos || test $targetos = darwin ; then
+	  GLIBCXX_IS_NATIVE=true
+	fi
+	;;
+
+      *)
+
+	;;
+  esac
+else
+  GLIBCXX_IS_NATIVE=true
+fi
+
+# Runs configure.host, and assorted other critical bits.  Sets
+# up critical shell variables.
+GLIBCXX_CONFIGURE
+
+# For gettimeofday support.
+GLIBCXX_CHECK_GETTIMEOFDAY
+
+# For clock_gettime, nanosleep and sched_yield support.
+GLIBCXX_ENABLE_LIBSTDCXX_TIME
+
+
 am__api_version='1.15'
 
 # Find a good install program.  We prefer a C program (faster),
@@ -12702,7 +12738,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12705 "configure"
+#line 12741 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
@@ -12808,7 +12844,7 @@ else
   lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
   lt_status=$lt_dlunknown
   cat > conftest.$ac_ext <<_LT_EOF
-#line 12811 "configure"
+#line 12847 "configure"
 #include "confdefs.h"
 
 #if HAVE_DLFCN_H
diff --git a/libgm2/configure.ac b/libgm2/configure.ac
index 75ca603283f6..92e76c9346c9 100644
--- a/libgm2/configure.ac
+++ b/libgm2/configure.ac
@@ -42,6 +42,42 @@ AC_CANONICAL_SYSTEM
 target_alias=${target_alias-$host_alias}
 AC_SUBST(target_alias)
 
+if test "$build" != "$host"; then
+  # We are being configured with some form of cross compiler.
+  GLIBCXX_IS_NATIVE=false
+  case "$host","$target" in
+    # Darwin crosses can use the host system's libraries and headers,
+    # because of the fat library support.  Of course, it must be the
+    # same version of Darwin on both sides.  Allow the user to
+    # just say --target=foo-darwin without a version number to mean
+    # "the version on this system".
+      *-*-darwin*,*-*-darwin*)
+	hostos=`echo $host | sed 's/.*-darwin/darwin/'`
+	targetos=`echo $target | sed 's/.*-darwin/darwin/'`
+	if test $hostos = $targetos || test $targetos = darwin ; then
+	  GLIBCXX_IS_NATIVE=true
+	fi
+	;;
+
+      *)
+	GCC_NO_EXECUTABLES
+	;;
+  esac
+else
+  GLIBCXX_IS_NATIVE=true
+fi
+
+# Runs configure.host, and assorted other critical bits.  Sets
+# up critical shell variables.
+GLIBCXX_CONFIGURE
+
+# For gettimeofday support.
+GLIBCXX_CHECK_GETTIMEOFDAY
+
+# For clock_gettime, nanosleep and sched_yield support.
+GLIBCXX_ENABLE_LIBSTDCXX_TIME
+
+
 AM_INIT_AUTOMAKE([1.15.1 no-define foreign no-dist -Wall -Wno-portability])
 
 AH_TEMPLATE(PACKAGE, [Name of package])
diff --git a/libgm2/libm2iso/wrapclock.cc b/libgm2/libm2iso/wrapclock.cc
index 91ac96f26f92..1f4ca8c325d0 100644
--- a/libgm2/libm2iso/wrapclock.cc
+++ b/libgm2/libm2iso/wrapclock.cc
@@ -51,6 +51,18 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #include "time.h"
 #endif
 
+// Conditional inclusion of sys/time.h for gettimeofday
+#if !defined(_GLIBCXX_USE_CLOCK_MONOTONIC) && \
+    !defined(_GLIBCXX_USE_CLOCK_REALTIME) && \
+     defined(_GLIBCXX_USE_GETTIMEOFDAY)
+#include <sys/time.h>
+#endif
+
+#if defined(_GLIBCXX_USE_CLOCK_GETTIME_SYSCALL)
+#include <unistd.h>
+#include <sys/syscall.h>
+#endif
+
 #if defined(HAVE_MALLOC_H)
 #include "malloc.h"
 #endif
@@ -64,91 +76,19 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #endif
 
 
-extern "C" long int
-EXPORT(timezone) (void)
-{
-#if defined(HAVE_STRUCT_TM) && defined(HAVE_STRUCT_TIMESPEC)
-  struct tm result;
-  struct timespec ts;
-
-#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_TM_TM_GMTOFF)
-  if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
-    {
-      time_t time = ts.tv_sec;
-      localtime_r (&time, &result);
-      return result.tm_gmtoff;
-    }
-  else
-#endif
-#endif
-    return timezone;
-}
-
-
-extern "C" int
-EXPORT(daylight) (void)
-{
-#if defined(HAVE_DAYLIGHT)
-  return daylight;
-#else
-  return 0;
-#endif
-}
-
-
-/* isdst returns 1 if daylight saving time is currently in effect and
-   returns 0 if it is not.  */
-
-extern "C" int
-EXPORT(isdst) (void)
-{
-#if defined(HAVE_STRUCT_TM) && defined(HAVE_STRUCT_TIMESPEC)
-  struct tm result;
-  struct timespec ts;
-
-#if defined(HAVE_CLOCK_SETTIME)
-  if (clock_gettime (CLOCK_REALTIME, &ts) == 0)
-    {
-      time_t time = ts.tv_sec;
-      localtime_r (&time, &result);
-      return result.tm_isdst;
-    }
-  else
-#endif
-#endif
-    return 0;
-}
-
-
-/* tzname returns the string associated with the local timezone.
-   The daylight value is 0 or 1.  The value 0 returns the non
-   daylight saving timezone string and the value of 1 returns the
-   daylight saving timezone string.  It returns NULL if tzname is
-   unavailable.  */
-
-extern "C" char *
-EXPORT(tzname) (int daylight)
-{
-#if defined(HAVE_TZNAME)
-  return tzname[daylight];
-#else
-  return NULL;
-#endif
-}
-
-
 /* GetTimeRealtime performs return gettime (CLOCK_REALTIME, ts).
    gettime returns 0 on success and -1 on failure.  If the underlying
    system does not have gettime then GetTimeRealtime returns 1.  */
 
-#if defined(HAVE_STRUCT_TIMESPEC)
+#if defined(HAVE_STRUCT_TIMESPEC) && defined(_GLIBCXX_USE_CLOCK_REALTIME)
 extern "C" int
 EXPORT(GetTimeRealtime) (struct timespec *ts)
 {
-#if defined(HAVE_CLOCK_GETTIME)
-  return clock_gettime (CLOCK_REALTIME, ts);
+  timespec tp;
+#if defined(_GLIBCXX_USE_CLOCK_GETTIME_SYSCALL)
+  return syscall (SYS_clock_gettime, CLOCK_REALTIME, ts);
 #else
-  return 1;
+  return clock_gettime (CLOCK_REALTIME, ts);
 #endif
 }
 
@@ -161,16 +101,17 @@ EXPORT(GetTimeRealtime) (void *ts)
 }
 #endif
 
-
 /* SetTimeRealtime performs return settime (CLOCK_REALTIME, ts).
    gettime returns 0 on success and -1 on failure.  If the underlying
    system does not have gettime then GetTimeRealtime returns 1.  */
 
-#if defined(HAVE_STRUCT_TIMESPEC)
+#if defined(HAVE_STRUCT_TIMESPEC) && defined(_GLIBCXX_USE_CLOCK_REALTIME)
 extern "C" int
 EXPORT(SetTimeRealtime) (struct timespec *ts)
 {
-#if defined(HAVE_CLOCK_GETTIME)
+#if defined(_GLIBCXX_USE_CLOCK_SETTIME_SYSCALL)
+  return syscall (SYS_clock_settime, CLOCK_REALTIME, ts);
+#elif defined(HAVE_CLOCK_SETTIME)
   return clock_settime (CLOCK_REALTIME, ts);
 #else
   return 1;
@@ -186,7 +127,6 @@ EXPORT(SetTimeRealtime) (void *ts)
 }
 #endif
 
-
 /* InitTimespec returns a newly created opaque type.  */
 
 #if defined(HAVE_STRUCT_TIMESPEC)
@@ -209,7 +149,6 @@ EXPORT(InitTimespec) (void)
 }
 #endif
 
-
 /* KillTimeval deallocates the memory associated with an opaque type.  */
 
 #if defined(HAVE_STRUCT_TIMESPEC)
@@ -231,9 +170,8 @@ EXPORT(KillTimespec) (void *ts)
 }
 #endif
 
-
 /* GetTimespec retrieves the number of seconds and nanoseconds from the
-   timespec.  */
+   timespec.  1 is returned if successful and 0 otherwise.  */
 
 #if defined(HAVE_STRUCT_TIMESPEC)
 extern "C" int
@@ -256,8 +194,8 @@ EXPORT(GetTimespec) (void *ts, unsigned long *sec, unsigned long *nano)
 }
 #endif
 
-
-/* SetTimespec sets the number of seconds and nanoseconds into timespec.  */
+/* SetTimespec sets the number of seconds and nanoseconds into timespec.
+   1 is returned if successful and 0 otherwise.  */
 
 #if defined(HAVE_STRUCT_TIMESPEC)
 extern "C" int
@@ -281,6 +219,97 @@ EXPORT(SetTimespec) (void *ts, unsigned long sec, unsigned long nano)
 }
 #endif
 
+extern "C" long int
+EXPORT(timezone) (void)
+{
+#if defined(HAVE_STRUCT_TIMESPEC)
+  struct tm result;
+  struct timespec ts;
+
+#if defined(HAVE_TM_TM_GMTOFF)
+  if (EXPORT(GetTimeRealtime) (&ts) == 0)
+    {
+      time_t time = ts.tv_sec;
+      localtime_r (&time, &result);
+      return result.tm_gmtoff;
+    }
+  else
+#endif
+#endif
+    {
+#if defined(HAVE_TIMEZONE)
+      return timezone;
+#else
+      return 0;
+#endif
+    }
+}
+
+/* istimezone returns 1 if timezone in wrapclock.cc can resolve the
+   timezone value using the timezone C library call or by using
+   clock_gettime, localtime_r and tm_gmtoff.  */
+
+extern "C" int
+EXPORT(istimezone) (void)
+{
+#if defined(HAVE_STRUCT_TIMESPEC)
+#if defined(HAVE_TM_TM_GMTOFF)
+#if defined(_GLIBCXX_USE_CLOCK_REALTIME)
+  return 1;
+#endif
+#endif
+#endif
+  return 0;
+}
+
+extern "C" int
+EXPORT(daylight) (void)
+{
+#if defined(HAVE_DAYLIGHT)
+  return daylight;
+#else
+  return 0;
+#endif
+}
+
+/* isdst returns 1 if daylight saving time is currently in effect and
+   returns 0 if it is not.  */
+
+extern "C" int
+EXPORT(isdst) (void)
+{
+#if defined(HAVE_STRUCT_TIMESPEC)
+  struct tm result;
+  struct timespec ts;
+
+  if (EXPORT(GetTimeRealtime) (&ts) == 0)
+    {
+      time_t time = ts.tv_sec;
+      localtime_r (&time, &result);
+      return result.tm_isdst;
+    }
+  else
+    return 0;
+#else
+  return 0;
+#endif
+}
+
+/* tzname returns the string associated with the local timezone.
+   The daylight value is 0 or 1.  The value 0 returns the non
+   daylight saving timezone string and the value of 1 returns the
+   daylight saving timezone string.  It returns NULL if tzname is
+   unavailable.  */
+
+extern "C" char *
+EXPORT(tzname) (int daylight)
+{
+#if defined(HAVE_TZNAME)
+  return tzname[daylight];
+#else
+  return NULL;
+#endif
+}
 
 /* init - init/finish functions for the module */
 
-- 
GitLab