Commit 4204f25b authored by Philippe Gerum's avatar Philippe Gerum
Browse files

lib: y2038: convert to timespec64 kernel interface



This set of changes makes libevl y2038-safe by switching to the ABI
revision 19 of the EVL core, which generalizes the use of a 64bit
timespec type. These changes also go a long way preparing for the
upcoming mixed 32/64 ABI support (aka compat mode).

The changes only affect the internal interface between libevl and the
kernel, not the API.  Nevertheless, the API was bumped to revision 10
with the removal of the evl_adjust_clock() service, which neither had
proper specification nor defined use case currently, but would stand
in the way of the sanitization work for y2038. At any rate, any future
service implementing some sort of EVL clock adjustment should
definitely not depend on the legacy struct timex which is
y2038-unsafe.
Signed-off-by: Philippe Gerum's avatarPhilippe Gerum <rpm@xenomai.org>
parent d075fbab
......@@ -10,13 +10,15 @@ uapi: $(O_UAPI)
$(O_UAPI): $(O_DIR)/.uapi_stamp
$(Q)$(MKDIR_P) $(O_UAPI)
$(Q)$(RM) -f $(O_UAPI)/asm $(O_UAPI)/evl
$(Q)$(RM) -f $(O_UAPI)/asm $(O_UAPI)/evl $(O_UAPI)/linux
$(Q)if test -r $(UAPI)/Kbuild; then \
$(LN_S) $(UAPI)/arch/$(ARCH)/include/uapi/asm $(O_UAPI)/asm; \
$(LN_S) $(UAPI)/include/uapi/evl $(O_UAPI)/evl; \
$(LN_S) $(UAPI)/include/uapi/linux $(O_UAPI)/linux; \
elif test \! -L $(O_UAPI)/asm; then \
$(LN_S) $(UAPI)/asm $(O_UAPI)/asm; \
$(LN_S) $(UAPI)/evl $(O_UAPI)/evl; \
$(LN_S) $(UAPI)/linux $(O_UAPI)/linux; \
fi
$(O_DIR)/.uapi_stamp: FORCE
......@@ -26,12 +28,12 @@ all: output-Makefile $(TARGETS)
# Remove the UAPI links. Careful with removing $(O_UAPI), just in case.
clean clobber mrproper: output-Makefile
$(Q)$(RM) -f $(O_DIR)/.uapi_stamp $(O_UAPI)/asm $(O_UAPI)/evl
$(Q)$(RM) -f $(O_DIR)/.uapi_stamp $(O_UAPI)/asm $(O_UAPI)/evl $(O_UAPI)/linux
$(Q)test -d $(O_UAPI) && $(RMDIR_SAFE) $(O_UAPI) || :
install: all
$(Q)$(MKDIR_P) $(DESTDIR)/$(includedir)/uapi
$(call inst-cmd,uapi-headers,cd $(O_UAPI) && find -L evl \! \( -name '*~' \) -type f | $(CPIO) -Lpdum --quiet $(DESTDIR)/$(includedir)/uapi)
$(call inst-cmd,uapi-headers,cd $(O_UAPI) && find -L evl linux \! \( -name '*~' \) -type f | $(CPIO) -Lpdum --quiet $(DESTDIR)/$(includedir)/uapi)
$(call inst-cmd,interface-headers,find evl \! \( -name '*~' \) -type f | $(CPIO) -Lpdum --quiet $(DESTDIR)/$(includedir))
$(call inst-cmd,eshi-headers,find eshi \! \( -name '*~' \) -type f | $(CPIO) -Lpdum --quiet $(DESTDIR)/$(includedir))
$(call inst-cmd,eshi-headers,$(CP) evl/atomic.h evl/list.h evl/heap.h $(DESTDIR)/$(includedir)/eshi/evl)
......@@ -36,8 +36,6 @@ int evl_set_clock(int clockfd, const struct timespec *tp);
int evl_get_clock_resolution(int clockfd, struct timespec *tp);
int evl_adjust_clock(int clockfd, struct timex *tx);
int evl_sleep_until(int clockfd, const struct timespec *timeout);
int evl_usleep(useconds_t usecs);
......
......@@ -20,9 +20,9 @@
#include <evl/poll.h>
#include <evl/proxy.h>
#define __EVL__ 9 /* API version */
#define __EVL__ 10 /* API version */
#define EVL_KABI_PREREQ 18
#define EVL_KABI_PREREQ 19
struct evl_version {
int api_level; /* libevl.so: __EVL__ */
......
......@@ -27,7 +27,7 @@ int evl_mod_pollfd(int efd, int modfd,
unsigned int events);
int evl_timedpoll(int efd, struct evl_poll_event *pollset,
int nrset, struct timespec *timeout);
int nrset, const struct timespec *timeout);
int evl_poll(int efd, struct evl_poll_event *pollset,
int nrset);
......
......@@ -30,6 +30,7 @@ int evl_mono_clockfd = -ENXIO,
int evl_set_clock(int clockfd, const struct timespec *tp)
{
struct __evl_timespec kts;
int ret;
switch (clockfd) {
......@@ -40,7 +41,8 @@ int evl_set_clock(int clockfd, const struct timespec *tp)
return -errno;
break;
default:
ret = do_call(clockfd, EVL_CLKIOC_SET_TIME, tp);
ret = do_call(clockfd, EVL_CLKIOC_SET_TIME,
__evl_ktimespec(tp, kts));
}
return ret;
......@@ -64,23 +66,17 @@ int evl_get_clock_resolution(int clockfd, struct timespec *tp)
return ret;
}
int evl_adjust_clock(int clockfd, struct timex *tx)
{
return do_call(clockfd, EVL_CLKIOC_ADJ_TIME, tx);
}
int evl_sleep_until(int clockfd, const struct timespec *timeout)
{
struct evl_clock_sleepreq req = {
.timeout = *timeout,
};
struct __evl_timespec kts;
if (clockfd == EVL_CLOCK_MONOTONIC)
clockfd = evl_mono_clockfd;
else if (clockfd == EVL_CLOCK_REALTIME)
clockfd = evl_real_clockfd;
return oob_ioctl(clockfd, EVL_CLKIOC_SLEEP, &req) ? -errno : 0;
return oob_ioctl(clockfd, EVL_CLKIOC_SLEEP,
__evl_ktimespec(timeout, kts)) ? -errno : 0;
}
static void timespec_add_ns(struct timespec *__restrict r,
......
......@@ -4,7 +4,6 @@
* Copyright (C) 2018 Philippe Gerum <rpm@xenomai.org>
*/
#include <stdarg.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdbool.h>
......@@ -205,6 +204,7 @@ int evl_timedwait_event(struct evl_event *evt,
{
struct evl_monitor_waitreq req;
struct unwait_data unwait;
struct __evl_timespec kts;
int ret;
if (mutex->magic != __MUTEX_ACTIVE_MAGIC)
......@@ -215,7 +215,7 @@ int evl_timedwait_event(struct evl_event *evt,
return ret;
req.gatefd = mutex->active.efd;
req.timeout = *timeout;
req.timeout = __evl_ktimespec(timeout, kts);
req.status = -EINVAL;
req.value = 0; /* dummy */
unwait.ureq.gatefd = req.gatefd;
......
......@@ -4,7 +4,6 @@
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
*/
#include <stdarg.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/ioctl.h>
......@@ -166,6 +165,7 @@ int evl_timedwait_flags(struct evl_flags *flg,
{
struct evl_monitor_state *state;
struct evl_monitor_waitreq req;
struct __evl_timespec kts;
fundle_t current;
int ret;
......@@ -187,7 +187,7 @@ int evl_timedwait_flags(struct evl_flags *flg,
}
req.gatefd = -1;
req.timeout = *timeout;
req.timeout = __evl_ktimespec(timeout, kts);
req.status = -EINVAL;
req.value = 0;
......
......@@ -7,11 +7,65 @@
#ifndef _LIB_EVL_INTERNAL_H
#define _LIB_EVL_INTERNAL_H
#include <time.h>
#include <stdarg.h>
#include <time.h>
#include <stdint.h>
#include <evl/thread.h>
#include <uapi/evl/types.h>
#if __WORDSIZE == 64 || __TIMESIZE == 64
/*
* If timespec is y2038-safe, we don't need to bounce via an
* __evl_timespec buffer, since both types are guaranteed compatible
* bitwise. y2038-proof glibc sets __TIMESIZE to the architecture
* bitness, others (including earlier releases) might not so we check
* __WORDSIZE too.
*
* CAUTION: the assumption here is that a y2038-safe timespec type has
* to be compatible bitwise with __kernel_timespec, and __evl_timespec
* is guaranteed compatible bitwise with __kernel_timespec too. So we
* may cast values safely between these types.
*/
#define __evl_ktimespec(__ts, __kts) \
({ \
(void)__kts; \
(struct __evl_timespec *)__ts; \
})
#define __evl_kitimerspec(__its, __kits) \
({ \
(void)__kits; \
(struct __evl_itimerspec *)__its; \
})
#else
/*
* Bummer, we have to bounce the 32bit timespec to a 64bit one the
* kernel would accept. Downside of it: we might get SIGSEGV if __ts
* is an invalid pointer instead of -EFAULT as one would
* expect. Upside: this interface won't break user code which did not
* switch to timespec64, which would be the only reasonable thing to
* do when support for y2038 is generally available from *libc.
*/
#define __evl_ktimespec(__ts, __kts) \
({ \
__kts.tv_sec = (__ts)->tv_sec; \
__kts.tv_nsec = (__ts)->tv_nsec; \
&__kts; \
})
#define __evl_kitimerspec(__its, __kits) \
({ \
struct __evl_itimerspec *__kitp = NULL; \
struct __evl_timespec __kts; \
if (__its) { \
__kits.it_value = *__evl_ktimespec( \
&(__its)->it_value, __kts); \
__kits.it_interval = *__evl_ktimespec( \
&(__its)->it_interval, __kts); \
__kitp = &__kits; \
} \
__kitp; \
})
#endif
extern __thread __attribute__ ((tls_model (EVL_TLS_MODEL)))
fundle_t evl_current;
......
......@@ -4,7 +4,6 @@
* Copyright (C) 2018 Philippe Gerum <rpm@xenomai.org>
*/
#include <stdarg.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <stdbool.h>
......@@ -268,18 +267,17 @@ static int try_lock(struct evl_mutex *mutex)
int evl_timedlock_mutex(struct evl_mutex *mutex,
const struct timespec *timeout)
{
struct evl_monitor_lockreq lreq;
struct evl_monitor_state *gst;
struct __evl_timespec kts;
int ret;
ret = try_lock(mutex);
if (ret != -ENODATA)
return ret;
lreq.timeout = *timeout;
do
ret = oob_ioctl(mutex->active.efd, EVL_MONIOC_ENTER, &lreq);
ret = oob_ioctl(mutex->active.efd, EVL_MONIOC_ENTER,
__evl_ktimespec(timeout, kts));
while (ret && errno == EINTR);
if (ret == 0) {
......
......@@ -47,12 +47,13 @@ int evl_mod_pollfd(int efd, int fd, unsigned int events)
}
static int do_poll(int efd, struct evl_poll_event *pollset,
int nrset, struct timespec *timeout)
int nrset, const struct timespec *timeout)
{
struct evl_poll_waitreq wreq;
struct __evl_timespec kts;
int ret;
wreq.timeout = *timeout;
wreq.timeout = __evl_ktimespec(timeout, kts);
wreq.pollset = pollset;
wreq.nrset = nrset;
ret = oob_ioctl(efd, EVL_POLIOC_WAIT, &wreq);
......@@ -63,7 +64,7 @@ static int do_poll(int efd, struct evl_poll_event *pollset,
}
int evl_timedpoll(int efd, struct evl_poll_event *pollset,
int nrset, struct timespec *timeout)
int nrset, const struct timespec *timeout)
{
return do_poll(efd, pollset, nrset, timeout);
}
......
......@@ -4,7 +4,6 @@
* Copyright (C) 2019 Philippe Gerum <rpm@xenomai.org>
*/
#include <stdarg.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
......
......@@ -4,7 +4,6 @@
* Copyright (C) 2018 Philippe Gerum <rpm@xenomai.org>
*/
#include <stdarg.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/ioctl.h>
......@@ -173,6 +172,7 @@ int evl_timedget_sem(struct evl_sem *sem, const struct timespec *timeout)
{
struct evl_monitor_state *state;
struct evl_monitor_waitreq req;
struct __evl_timespec kts;
fundle_t current;
int ret;
......@@ -190,7 +190,7 @@ int evl_timedget_sem(struct evl_sem *sem, const struct timespec *timeout)
return ret;
req.gatefd = -1;
req.timeout = *timeout;
req.timeout = __evl_ktimespec(timeout, kts);
req.status = -EINVAL;
req.value = 0; /* dummy */
......
......@@ -4,7 +4,6 @@
* Copyright (C) 2018 Philippe Gerum <rpm@xenomai.org>
*/
#include <stdarg.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <errno.h>
......
......@@ -44,19 +44,18 @@ int evl_set_timer(int efd,
struct itimerspec *value,
struct itimerspec *ovalue)
{
struct __evl_itimerspec kits, koits;
struct evl_timerfd_setreq sreq;
sreq.value = value;
sreq.ovalue = ovalue;
sreq.value = __evl_kitimerspec(value, kits);
sreq.ovalue = __evl_kitimerspec(ovalue, koits);
return do_call(efd, EVL_TFDIOC_SET, &sreq);
}
int evl_get_timer(int efd, struct itimerspec *value)
{
struct evl_timerfd_getreq greq;
struct __evl_itimerspec kits;
greq.value = value;
return do_call(efd, EVL_TFDIOC_GET, &greq);
return do_call(efd, EVL_TFDIOC_GET, __evl_kitimerspec(value, kits));
}
......@@ -4,7 +4,6 @@
* 2018 - Philippe Gerum <rpm@xenomai.org>
*/
#include <stdarg.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment