gcc/libgm2/libm2iso/wrapclock.cc
Gaius Mulley 63fb0bedb8 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>
2023-08-12 18:17:41 +01:00

339 lines
7 KiB
C++

/* wrapclock.cc provides access to time related system calls.
Copyright (C) 2009-2022 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.
This file is part of GNU Modula-2.
GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
GNU Modula-2 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
General Public License for more details.
Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.
You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
<http://www.gnu.org/licenses/>. */
#include "config.h"
#include <m2rts.h>
#define EXPORT(FUNC) m2iso ## _wrapclock_ ## FUNC
#define M2EXPORT(FUNC) m2iso ## _M2_wrapclock_ ## FUNC
#define M2LIBNAME "m2iso"
#if defined(HAVE_STDLIB_H)
#include "stdlib.h"
#endif
#if defined(HAVE_UNISTD_H)
#include "unistd.h"
#endif
#if defined(HAVE_SYS_TYPES_H)
#include "sys/types.h"
#endif
#if defined(HAVE_SYS_TIME_H)
#include "sys/time.h"
#endif
#if defined(HAVE_TIME_H)
#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
#if defined(HAVE_LIMITS_H)
#include "limits.h"
#endif
#if !defined(NULL)
#define NULL (void *)0
#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) && defined(_GLIBCXX_USE_CLOCK_REALTIME)
extern "C" int
EXPORT(GetTimeRealtime) (struct timespec *ts)
{
timespec tp;
#if defined(_GLIBCXX_USE_CLOCK_GETTIME_SYSCALL)
return syscall (SYS_clock_gettime, CLOCK_REALTIME, ts);
#else
return clock_gettime (CLOCK_REALTIME, ts);
#endif
}
#else
extern "C" int
EXPORT(GetTimeRealtime) (void *ts)
{
return 1;
}
#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) && defined(_GLIBCXX_USE_CLOCK_REALTIME)
extern "C" int
EXPORT(SetTimeRealtime) (struct timespec *ts)
{
#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;
#endif
}
#else
extern "C" int
EXPORT(SetTimeRealtime) (void *ts)
{
return 1;
}
#endif
/* InitTimespec returns a newly created opaque type. */
#if defined(HAVE_STRUCT_TIMESPEC)
extern "C" struct timespec *
EXPORT(InitTimespec) (void)
{
#if defined(HAVE_STRUCT_TIMESPEC) && defined(HAVE_MALLOC_H)
return (struct timespec *)malloc (sizeof (struct timespec));
#else
return NULL;
#endif
}
#else
extern "C" void *
EXPORT(InitTimespec) (void)
{
return NULL;
}
#endif
/* KillTimeval deallocates the memory associated with an opaque type. */
#if defined(HAVE_STRUCT_TIMESPEC)
extern "C" struct timespec *
EXPORT(KillTimespec) (void *ts)
{
#if defined(HAVE_MALLOC_H)
free (ts);
#endif
return NULL;
}
#else
extern "C" void *
EXPORT(KillTimespec) (void *ts)
{
return NULL;
}
#endif
/* GetTimespec retrieves the number of seconds and nanoseconds from the
timespec. 1 is returned if successful and 0 otherwise. */
#if defined(HAVE_STRUCT_TIMESPEC)
extern "C" int
EXPORT(GetTimespec) (timespec *ts, unsigned long *sec, unsigned long *nano)
{
#if defined(HAVE_STRUCT_TIMESPEC)
*sec = ts->tv_sec;
*nano = ts->tv_nsec;
return 1;
#else
return 0;
#endif
}
#else
extern "C" int
EXPORT(GetTimespec) (void *ts, unsigned long *sec, unsigned long *nano)
{
return 0;
}
#endif
/* 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
EXPORT(SetTimespec) (timespec *ts, unsigned long sec, unsigned long nano)
{
#if defined(HAVE_STRUCT_TIMESPEC)
ts->tv_sec = sec;
ts->tv_nsec = nano;
return 1;
#else
return 0;
#endif
}
#else
extern "C" int
EXPORT(SetTimespec) (void *ts, unsigned long sec, unsigned long nano)
{
return 0;
}
#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 */
/* GNU Modula-2 linking hooks. */
extern "C" void
M2EXPORT(init) (int, char **, char **)
{
}
extern "C" void
M2EXPORT(fini) (int, char **, char **)
{
}
extern "C" void
M2EXPORT(dep) (void)
{
}
extern "C" void __attribute__((__constructor__))
M2EXPORT(ctor) (void)
{
m2iso_M2RTS_RegisterModule ("wrapclock", M2LIBNAME,
M2EXPORT(init), M2EXPORT(fini),
M2EXPORT(dep));
}