From cb28158b9abe10f08142f12f11ddbb5d23686fd5 Mon Sep 17 00:00:00 2001 From: Christof Arnosti Date: Tue, 10 Mar 2020 22:58:24 +0100 Subject: Add timestamps to libdivecomputer.log Since I learned while trying to implement this that getting sub-second resolution time in portable C99 is hard (especially for someone who is used to the comfort of std::chrono and Howard Hinnants date library) the timer-implemetation from libdivecomputer is now copied to the subsurface source. Signed-off-by: Christof Arnosti --- core/timer.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 161 insertions(+) create mode 100644 core/timer.c (limited to 'core/timer.c') diff --git a/core/timer.c b/core/timer.c new file mode 100644 index 000000000..14ccd4666 --- /dev/null +++ b/core/timer.c @@ -0,0 +1,161 @@ +/* + * libdivecomputer + * + * Copyright (C) 2018 Jef Driesen + * + * This library 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 library 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 library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, + * MA 02110-1301 USA + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#ifdef _WIN32 +#define NOGDI +#include +#else +#include +#include +#ifdef HAVE_MACH_MACH_TIME_H +#include +#endif +#endif + +#include "timer.h" + +struct dc_timer_t { +#if defined (_WIN32) + LARGE_INTEGER timestamp; + LARGE_INTEGER frequency; +#elif defined (HAVE_CLOCK_GETTIME) + struct timespec timestamp; +#elif defined (HAVE_MACH_ABSOLUTE_TIME) + uint64_t timestamp; + mach_timebase_info_data_t info; +#else + struct timeval timestamp; +#endif +}; + +dc_status_t +dc_timer_new (dc_timer_t **out) +{ + dc_timer_t *timer = NULL; + + if (out == NULL) + return DC_STATUS_INVALIDARGS; + + timer = (dc_timer_t *) malloc (sizeof (dc_timer_t)); + if (timer == NULL) { + return DC_STATUS_NOMEMORY; + } + +#if defined (_WIN32) + if (!QueryPerformanceFrequency(&timer->frequency) || + !QueryPerformanceCounter(&timer->timestamp)) { + free(timer); + return DC_STATUS_IO; + } +#elif defined (HAVE_CLOCK_GETTIME) + if (clock_gettime(CLOCK_MONOTONIC, &timer->timestamp) != 0) { + free(timer); + return DC_STATUS_IO; + } +#elif defined (HAVE_MACH_ABSOLUTE_TIME) + if (mach_timebase_info(&timer->info) != KERN_SUCCESS) { + free(timer); + return DC_STATUS_IO; + } + + timer->timestamp = mach_absolute_time(); +#else + if (gettimeofday (&timer->timestamp, NULL) != 0) { + free(timer); + return DC_STATUS_IO; + } +#endif + + *out = timer; + + return DC_STATUS_SUCCESS; +} + +dc_status_t +dc_timer_now (dc_timer_t *timer, dc_usecs_t *usecs) +{ + dc_status_t status = DC_STATUS_SUCCESS; + dc_usecs_t value = 0; + + if (timer == NULL) { + status = DC_STATUS_INVALIDARGS; + goto out; + } + +#if defined (_WIN32) + LARGE_INTEGER now; + if (!QueryPerformanceCounter(&now)) { + status = DC_STATUS_IO; + goto out; + } + + value = (now.QuadPart - timer->timestamp.QuadPart) * 1000000 / timer->frequency.QuadPart; +#elif defined (HAVE_CLOCK_GETTIME) + struct timespec now, delta; + if (clock_gettime(CLOCK_MONOTONIC, &now) != 0) { + status = DC_STATUS_IO; + goto out; + } + + if (now.tv_nsec < timer->timestamp.tv_nsec) { + delta.tv_nsec = 1000000000 + now.tv_nsec - timer->timestamp.tv_nsec; + delta.tv_sec = now.tv_sec - timer->timestamp.tv_sec - 1; + } else { + delta.tv_nsec = now.tv_nsec - timer->timestamp.tv_nsec; + delta.tv_sec = now.tv_sec - timer->timestamp.tv_sec; + } + + value = (dc_usecs_t) delta.tv_sec * 1000000 + delta.tv_nsec / 1000; +#elif defined (HAVE_MACH_ABSOLUTE_TIME) + uint64_t now = mach_absolute_time(); + value = (now - timer->timestamp) * timer->info.numer / (timer->info.denom * 1000); +#else + struct timeval now, delta; + if (gettimeofday (&now, NULL) != 0) { + status = DC_STATUS_IO; + goto out; + } + + timersub (&now, &timer->timestamp, &delta); + + value = (dc_usecs_t) delta.tv_sec * 1000000 + delta.tv_usec; +#endif + +out: + if (usecs) + *usecs = value; + + return status; +} + +dc_status_t +dc_timer_free (dc_timer_t *timer) +{ + free (timer); + + return DC_STATUS_SUCCESS; +} -- cgit v1.2.3-70-g09d2