Show misc_time.c syntax highlighted
/*
*
* Copyright (c) 2003 The Regents of the University of California. All
* rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Neither the name of the University nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
/*
* time-related utilities
*
* part of libmisc
*
* $Id: misc_time.c,v 1.26 2005/10/29 23:15:30 cerpa Exp $
*/
char misc_time_c_cvsid[] = "$Id: misc_time.c,v 1.26 2005/10/29 23:15:30 cerpa Exp $";
#include "misc.h"
#include <time.h>
/* resolve seconds carry */
static inline void update_tv(struct timeval *t1)
{
if (t1->tv_usec >= MILLION_I) {
t1->tv_sec++;
t1->tv_usec -= MILLION_I;
}
if (t1->tv_usec < 0) {
t1->tv_sec--;
t1->tv_usec += MILLION_I;
}
}
//
// struct timeval subtraction: t1 -= t2: negative values OK
//
void misc_tv_sub_neg(struct timeval *t1, const struct timeval *t2)
{
t1->tv_sec -= t2->tv_sec;
t1->tv_usec -= t2->tv_usec;
update_tv(t1);
}
//
// struct timeval subtraction: t1 -= t2: negative values turned into 0
//
int misc_tv_sub(struct timeval *t1, const struct timeval *t2)
{
misc_tv_sub_neg(t1, t2);
if (t1->tv_sec < 0) {
t1->tv_sec = t1->tv_usec = 0;
return 1;
}
return 0;
}
//
// struct timeval comparison function
//
int misc_tv_cmp(struct timeval *t1, struct timeval *t2)
{
int cmp = t1->tv_sec - t2->tv_sec;
if (cmp) return cmp;
return t1->tv_usec - t2->tv_usec;
}
static void copy_or_gettimeofday(struct timeval *dest, const struct timeval *src)
{
if (src)
memcpy(dest, src, sizeof(*dest));
else
gettimeofday(dest, NULL);
}
long misc_tv_offset_neg(const struct timeval *late,
const struct timeval *early)
{
struct timeval tmp;
copy_or_gettimeofday(&tmp, late);
misc_tv_sub_neg(&tmp, early);
return tmp.tv_sec * MILLION_I + tmp.tv_usec;
}
int64_t misc_tv_offset_neg64(const struct timeval *late,
const struct timeval *early)
{
struct timeval tmp;
copy_or_gettimeofday(&tmp, late);
return tv_to_ll(&tmp) - tv_to_ll(early);
}
unsigned long misc_tv_offset(const struct timeval *late,
const struct timeval *early)
{
struct timeval tmp;
copy_or_gettimeofday(&tmp, late);
misc_tv_sub(&tmp, early);
return tmp.tv_sec * MILLION_I + tmp.tv_usec;
}
long misc_tv_offset_neg_msec(const struct timeval *late,
const struct timeval *early)
{
struct timeval tmp;
copy_or_gettimeofday(&tmp, late);
misc_tv_sub_neg(&tmp, early);
return (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000);
}
unsigned long misc_tv_offset_msec(const struct timeval *late,
const struct timeval *early)
{
struct timeval tmp;
copy_or_gettimeofday(&tmp, late);
misc_tv_sub(&tmp, early);
return (tmp.tv_sec * 1000) + (tmp.tv_usec / 1000);
}
//
// simple function for computing how many msec since the last time
// something happened -- but with protection for the clock going
// backwards. if the result is negative *and* more than 1ms, a very
// large positive number is returned, i.e. to make it look like the
// event happened far in the past so it'll happen again. If the
// difference is negative but less than 2ms, we return zero. The
// reason here is that small time differences that do not really
// account for events in the future but events that are very close in
// time that may have been scheduled in advance. The prime example of
// this is the Emstar sim_radio, that may schedule recv_time of packet
// arrival before it acutally happens. We picked 2ms as a guard band.
// The last comment is a pseudo-hack! The real fix would be to fix
// this in the simulator.
//
unsigned long msec_since(const struct timeval *when)
{
long elapsed = misc_tv_offset_neg_msec(NULL, when);
if (elapsed < -2)
return (1 << 30);
if (elapsed < 0)
return 0;
else
return elapsed;
}
//
//
///////// timeval addition ///////////
//
//
//
// timeval add: t1 += t2
//
void misc_tv_add(struct timeval *t1, struct timeval *t2)
{
t1->tv_sec += t2->tv_sec;
t1->tv_usec += t2->tv_usec;
update_tv(t1);
}
/* add an int (milliseconds) to a timeval */
void misc_tv_addms(struct timeval *t1, long ms)
{
t1->tv_sec += (ms / 1000);
t1->tv_usec += 1000*(ms % 1000);
update_tv(t1);
}
/* add an int (microseconds) to a timeval */
void misc_tv_addus(struct timeval *t1, long us)
{
t1->tv_sec += us / MILLION_I;
t1->tv_usec += us % MILLION_I;
update_tv(t1);
}
int misc_tv_overlap(struct timeval *tv1, int ms_dur1, struct timeval *tv2, int ms_dur2,
struct timeval *end)
{
struct timeval end1;
struct timeval end2;
memcpy(&end1, tv1, sizeof(end1));
misc_tv_addms(&end1, ms_dur1);
memcpy(&end2, tv2, sizeof(end2));
misc_tv_addms(&end2, ms_dur2);
// collision?
if (((misc_tv_cmp(tv1, tv2) >= 0) &&
(misc_tv_cmp(tv1, &end2) < 0)) ||
((misc_tv_cmp(tv2, tv1) >= 0) &&
(misc_tv_cmp(tv2, &end1) < 0))) {
if (end) {
if (misc_tv_cmp(&end1, &end2) < 0)
memcpy(end, &end2, sizeof(*end));
else
memcpy(end, &end1, sizeof(*end));
}
return 1;
}
return 0;
}
int misc_tv_overlap_us(struct timeval *tv1, int us_dur1, struct timeval *tv2, int us_dur2,
struct timeval *end)
{
struct timeval end1;
struct timeval end2;
memcpy(&end1, tv1, sizeof(end1));
misc_tv_addus(&end1, us_dur1);
memcpy(&end2, tv2, sizeof(end2));
misc_tv_addus(&end2, us_dur2);
// collision?
if (((misc_tv_cmp(tv1, tv2) >= 0) &&
(misc_tv_cmp(tv1, &end2) < 0)) ||
((misc_tv_cmp(tv2, tv1) >= 0) &&
(misc_tv_cmp(tv2, &end1) < 0))) {
if (end) {
if (misc_tv_cmp(&end1, &end2) < 0)
memcpy(end, &end2, sizeof(*end));
else
memcpy(end, &end1, sizeof(*end));
}
return 1;
}
return 0;
}
/* Convert a timeval to microseconds as a long */
long misc_tv_usec_l(struct timeval *t)
{
return ((long) t->tv_sec * MILLION_I) + t->tv_usec;
}
/* Convert a timeval to microseconds as a float */
float misc_tv_usec_f(struct timeval *t)
{
return ((float) t->tv_sec * MILLION_F) + t->tv_usec;
}
/* Convert a timeval to milliseconds as a float */
float misc_tv_msec_f(struct timeval *t)
{
return misc_tv_usec_f(t) / 1000.0;
}
/* Convert a timeval to seconds as a float */
float misc_tv_sec_f(struct timeval *t)
{
return misc_tv_usec_f(t) / MILLION_F;
}
// convert a timeval to microseconds as a long
long misc_tv_usec_l(struct timeval *t);
// convert a timeval to seconds or milliseconds as a float
float misc_tv_msec_f(struct timeval *t);
float misc_tv_sec_f(struct timeval *t);
////////////////// Printing Functions /////////////////////////
//
// convert timeval to a string like "Tue Jul 20 14:52:18 PDT 2004"
//
// this is basically an interface to asctime, but
// 1 -- it takes a timeval rather than an int
// 2 -- has a static buf ring so it can be called multiple times from
// printf without overwriting previous results
// 3 -- removes the trailing lf for you
//
char *misc_print_date(const struct timeval *tv)
{
DECLARE_STATIC_BUF_RING(buf, 3, 32);
if (tv->tv_sec == 0 && tv->tv_usec == 0)
return "never";
else {
sprintf(buf, asctime(localtime(&tv->tv_sec)));
misc_strip_trailing_crlfs(buf);
return buf;
}
}
// convert timeval to a localtime string like "Tue Jul 20 14:52:18 PDT 2004"
// where format in this example is "%a %b %e %T %Z %Y"
// see the strftime() function for more choices
char *misc_print_formated_date(const struct timeval *tv, const char *format) {
DECLARE_STATIC_BUF_RING(buf, 3, 64);
if (tv->tv_sec == 0 && tv->tv_usec == 0)
return "never";
else {
strftime(buf, 64, format, localtime(&tv->tv_sec));
misc_strip_trailing_crlfs(buf);
return buf;
}
}
// convert a timeval to a floating point-like string, e.g. "12345.006789"
char *misc_tv_to_str(const struct timeval *tv)
{
DECLARE_STATIC_BUF_RING(buf, 3, 24);
struct timeval tmp;
if (tv) {
memcpy(&tmp, tv, sizeof(tmp));
/* this strangeness is to make negative numbers "look right": the
* internal representation doesn't look the same as what we expect */
if (tmp.tv_sec < 0 && tmp.tv_usec > 0) {
tmp.tv_sec++;
tmp.tv_usec = MILLION_I - tmp.tv_usec;
}
sprintf(buf, "%ld.%06ld", tmp.tv_sec, tmp.tv_usec);
return buf;
}
return NULL;
}
char *misc_secs_to_str(int t)
{
DECLARE_STATIC_BUF_RING(sbuf, 3, 32);
buf_t *b = buf_new();
int tmp;
if (t == 0) {
buf_free(b);
return "0s";
}
if ((tmp = (t / 86400)) > 0) {
bufprintf(b, " %dd", tmp);
t %= 86400;
}
if ((tmp = (t / 3600)) > 0) {
bufprintf(b, " %dh", tmp);
t %= 3600;
}
if ((tmp = (t / 60)) > 0) {
bufprintf(b, " %dm", tmp);
t %= 60;
}
if (t)
bufprintf(b, " %ds", t);
strcpy(sbuf, b->buf+1);
buf_free(b);
return sbuf;
}
int64_t misc_timeval_to_int64(struct timeval *tv)
{
int64_t clock = tv->tv_sec;
clock *= MILLION_I;
clock += tv->tv_usec;
return clock;
}
void misc_int64_to_timeval(struct timeval *tv, int64_t index)
{
tv->tv_usec = index % MILLION_I;
tv->tv_sec = index / MILLION_I;
}
void misc_str_to_tv(char* time_str, struct timeval *tv)
{
int i;
int64_t time;
double time2;
char *decimal, intVal[30];
if (time_str) {
time = 0;
time2 = 0;
decimal = strpbrk(time_str, ".");
/* Just get integer */
for (i = 0; i < strcspn(time_str, ".") + 1; i++)
intVal[i] = 0;
strncpy(intVal, time_str, strcspn(time_str, "."));
if (intVal[0] != 0) {
time2 = atof(intVal);
/* convert to micro-seconds */
time = time2 * MILLION_F;
}
if (decimal) {
/* conv decimal to usec */
time2 = atof(decimal) * MILLION_F;
time += time2;
}
/* Check for negative num, and if translated correctly */
if (atof(time_str) < 0)
time = time * (time < 0 ? 1 : -1);
}
else
time = 0;
misc_int64_to_timeval(tv, time);
}
static struct timeval elapsed_time = {};
static struct timeval sys_elapsed_time = {};
/* returns current elapsed time since start of program */
uint64_t misc_time_elapsed()
{
struct timeval tv;
gettimeofday(&tv, NULL);
misc_tv_sub_neg(&tv, &elapsed_time);
return misc_timeval_to_int64(&tv);
}
/* returns current elapsed time since start of system (from emrun) */
uint64_t misc_time_elapsed_sys()
{
struct timeval tv;
gettimeofday(&tv, NULL);
misc_tv_sub_neg(&tv, &sys_elapsed_time);
return misc_timeval_to_int64(&tv);
}
void misc_time_get_start(struct timeval *tv)
{
*tv = elapsed_time;
}
int64_t misc_time_get_sys_start64()
{
return misc_timeval_to_int64(&sys_elapsed_time);
}
int64_t misc_time_get_start64()
{
return misc_timeval_to_int64(&elapsed_time);
}
/* resets the start time -- called by misc_init() */
void misc_time_set_start(struct timeval *tv)
{
if (tv)
elapsed_time = *tv;
else
gettimeofday(&elapsed_time, NULL);
}
/* resets the start time -- called by emrun_init() */
void misc_time_set_sys_start(struct timeval *tv)
{
sys_elapsed_time = *tv;
}
#define MAX_BUSYWAIT 10000
void misc_busy_wait(int microseconds)
{
struct timeval start;
gettimeofday(&start, NULL);
while (1) {
struct timeval now;
gettimeofday(&now, NULL);
long int micros = misc_tv_offset_neg(&now, &start);
if (micros < 0) {
elog(LOG_WARNING, "Time went backwards??");
return;
}
if (micros > microseconds)
return;
if ((microseconds - micros) > MAX_BUSYWAIT)
usleep((microseconds - micros) - MAX_BUSYWAIT);
}
}
void misc_busy_wait_until(struct timeval *tv)
{
while (1) {
struct timeval now;
gettimeofday(&now, NULL);
if (misc_tv_cmp(&now, tv) > 0) return;
uint64_t micros = tv_to_ll(tv) - tv_to_ll(&now);
if (micros > MILLION_I)
sleep(micros/MILLION_I);
else
if (micros > MAX_BUSYWAIT)
usleep(micros - MAX_BUSYWAIT);
}
}
See more files for this project here