diff options
author | Christof Arnosti <charno@charno.ch> | 2020-03-10 22:58:24 +0100 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2020-03-10 17:42:54 -0700 |
commit | cb28158b9abe10f08142f12f11ddbb5d23686fd5 (patch) | |
tree | 1d3aec604dfe116accf10326a3f4fe2cca3bf975 /core/timer.c | |
parent | b6163804fd56acf23bf6156a84cad02bc6f6eb08 (diff) | |
download | subsurface-cb28158b9abe10f08142f12f11ddbb5d23686fd5.tar.gz |
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 <charno@charno.ch>
Diffstat (limited to 'core/timer.c')
-rw-r--r-- | core/timer.c | 161 |
1 files changed, 161 insertions, 0 deletions
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 <stdlib.h> + +#ifdef _WIN32 +#define NOGDI +#include <windows.h> +#else +#include <time.h> +#include <sys/time.h> +#ifdef HAVE_MACH_MACH_TIME_H +#include <mach/mach_time.h> +#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; +} |