diff --git a/configure.ac b/configure.ac index c074490..c07d46e 100644 --- a/configure.ac +++ b/configure.ac @@ -27,6 +27,12 @@ AC_FUNC_MALLOC AC_FUNC_MEMCMP AC_CHECK_FUNCS([gettimeofday memset snprintf strcasecmp strncasecmp vsnprintf]) +# Check for clock_gettime() +AC_CHECK_FUNCS([clock_gettime], [], + [AC_CHECK_LIB([rt], [clock_gettime], + [AC_DEFINE(HAVE_CLOCK_GETTIME, 1) + AC_SUBST([REALTIME_LIBS], [-lrt])])]) + # Check for pthread support AC_CHECK_LIB([pthread], [pthread_create], diff --git a/examples/Makefile.am b/examples/Makefile.am index 3344b5d..a1c2cb0 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -2,4 +2,4 @@ noinst_PROGRAMS = hash_usage large_hash strings conf_example \ conf_example2 opt_example AM_CFLAGS = -I$(top_srcdir)/src -LDADD = $(top_builddir)/src/libcfu.la @PTHREAD_LIBS@ +LDADD = $(top_builddir)/src/libcfu.la @PTHREAD_LIBS@ @REALTIME_LIBS@ diff --git a/libcfu.pc.in b/libcfu.pc.in index 07b4c3f..afb2043 100644 --- a/libcfu.pc.in +++ b/libcfu.pc.in @@ -6,5 +6,5 @@ includedir=@includedir@ Name: @PACKAGE_NAME@ Description: Portable C data structure and utility library Version: @PACKAGE_VERSION@ -Libs.private: @PTHREAD_LIBS@ +Libs.private: @PTHREAD_LIBS@ @REALTIME_LIBS@ Cflags: -I${includedir}/cfu diff --git a/src/Makefile.am b/src/Makefile.am index e8318c3..4caae70 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,12 +1,13 @@ lib_LTLIBRARIES = libcfu.la -libcfu_la_SOURCES = cfuhash.c cfutime.c cfustring.c cfulist.c \ - cfuconf.c cfu.c cfuopt.c snprintf.c +libcfu_la_SOURCES = cfuhash.c cfutime.c cfutimer.c cfustring.c \ + cfulist.c cfuconf.c cfu.c cfuopt.c snprintf.c +libcfu_la_LIBADD = @PTHREAD_LIBS@ @REALTIME_LIBS@ libcfuincdir = $(includedir)/cfu -libcfuinc_HEADERS = cfu.h cfuhash.h cfutime.h cfustring.h cfulist.h \ - cfuconf.h cfuopt.h +libcfuinc_HEADERS = cfu.h cfuhash.h cfutime.h cfutimer.h cfustring.h \ + cfulist.h cfuconf.h cfuopt.h if USE_PTHREADS libcfu_la_SOURCES += cfuthread_queue.c diff --git a/src/cfu.c b/src/cfu.c index 66935b4..49bf1e5 100644 --- a/src/cfu.c +++ b/src/cfu.c @@ -71,6 +71,14 @@ cfu_is_time(void *item) { return 0; } +int +cfu_is_timer(void *item) +{ + if (cfu_get_type(item) == libcfu_t_time) + return 1; + return 0; +} + extern int cfu_is_conf(void *item) { if (cfu_get_type(item) == libcfu_t_conf) return 1; diff --git a/src/cfu.h b/src/cfu.h index 02050b0..5207e55 100644 --- a/src/cfu.h +++ b/src/cfu.h @@ -59,7 +59,7 @@ CFU_BEGIN_DECLS #define LIBCFU_VERSION "0.04" typedef enum { libcfu_t_none = 0, libcfu_t_hash_table, libcfu_t_list, libcfu_t_string, - libcfu_t_time, libcfu_t_conf } libcfu_type; + libcfu_t_time, libcfu_t_timer, libcfu_t_conf } libcfu_type; typedef struct libcfu_item libcfu_item_t; @@ -68,6 +68,7 @@ extern int cfu_is_hash(void *item); extern int cfu_is_list(void *item); extern int cfu_is_string(void *item); extern int cfu_is_time(void *item); +int cfu_is_timer(void *item); extern int cfu_is_conf(void *item); CFU_END_DECLS diff --git a/src/cfutimer.c b/src/cfutimer.c new file mode 100644 index 0000000..b6f07db --- /dev/null +++ b/src/cfutimer.c @@ -0,0 +1,101 @@ +/* + * cfutimer.c - This file is part of the libcfu library + * + * Copyright (c) Matthew Brush . + * All rights reserved. + * + * This code is released under the BSD license, see COPYING file + * for full license text. + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "cfu.h" +#include "cfutimer.h" + +#include +#include +#include +#include + +#ifdef HAVE_SYS_TIME_H +# include +#endif + +/* For Windows, use a fairly accurate timer. This could probably be + * improved quite a bit (if it even works at all), by using performance + * counters stuff or thread cycle time from the API. Setting the afinity + * mask is probably also helpful. Note: not tested at all. */ +#ifdef _WIN32 +# define WIN32_LEAN_AND_MEAN +# include +# define TIMEVALUE_TYPE FILETIME +# define TIMEVALUE_NOW(tv) GetSystemTimeAsFileTime(&(tv)) +# define TIMEVALUE_SEC(tv) ((double)(((uint64_t)(tv).dwHighDataTime << 32) + (tv).dwLowDateTime) * 10000000.0) +/* another option for windows, also untested +#define TIMEVALUE_TYPE LARGE_INTEGER +// future: set thread afinity mask +#define TIMEVALUE_NOW(tv) QueryPerformanceCounter(&(tv)) +static INLINE double timevalue_sec_(TIMEVALUE_TYPE *tv) { + LARGE_INTEGER freq; + QueryPerformanceFrequency(&freq); + return (double) tv->QuadPart / (double) freq.QuadPart; +} +#define TIMEVALUE_SEC(tv) timevalue_sec_(&(tv)) +*/ +#else +/* For non-Windows systems check to see if the nano-second timer is + * available from POSIX. Note: must also be linked with -lrt.*/ +# if defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) +# define TIMEVALUE_TYPE struct timespec +# define TIMEVALUE_NOW(tv) clock_gettime(CLOCK_MONOTONIC, &(tv)) +# define TIMEVALUE_SEC(tv) ((double)(tv).tv_sec + ((double) (tv).tv_nsec / 1000000000.0)) +/* For non-Windows systems that don't have the more accurate clock_gettime() + * then use the gettimeofday() function from POSIX if available. */ +# elif defined(HAVE_GETTIMEOFDAY) +# define TIMEVALUE_TYPE struct timeval +# define TIMEVALUE_NOW(tv) gettimeofday(&(tv), NULL) +# define TIMEVALUE_SEC(tv) ((double)(tv).tv_sec + ((double) (tv).tv_usec / 1000000.0)) +# else /* Fall-back to time() from stdlib */ +# define TIMEVALUE_TYPE time_t +# define TIMEVALUE_NOW(tv) time(&(tv)) +# define TIMEVALUE_SEC(tv) ((double)(tv)) +# endif +#endif + +struct cfutimer +{ + libcfu_type type; + TIMEVALUE_TYPE t1; + TIMEVALUE_TYPE t2; +}; + +cfutimer_t *cfutimer_new(void) +{ + cfutimer_t *timer = calloc(1, sizeof(cfutimer_t)); + timer->type = libcfu_t_time; + return timer; +} + +void cfutimer_start(cfutimer_t *timer) +{ + memset(&(timer->t2), 0, sizeof(TIMEVALUE_TYPE)); + TIMEVALUE_NOW(timer->t1); +} + +void cfutimer_stop(cfutimer_t *timer) +{ + TIMEVALUE_NOW(timer->t2); +} + +double cfutimer_elapsed(cfutimer_t *timer) +{ + return TIMEVALUE_SEC(timer->t2) - TIMEVALUE_SEC(timer->t1); +} + +void cfutimer_free(cfutimer_t *timer) +{ + free(timer); +} diff --git a/src/cfutimer.h b/src/cfutimer.h new file mode 100644 index 0000000..5a1dcba --- /dev/null +++ b/src/cfutimer.h @@ -0,0 +1,37 @@ +/* + * cfutimer.h - This file is part of the libcfu library + * + * Copyright (c) Matthew Brush . + * All rights reserved. + * + * This code is released under the BSD license, see COPYING file + * for full license text. + */ + +#ifndef CFU_TIMER_H_ +#define CFU_TIMER_H_ + +#include + +CFU_BEGIN_DECLS + +typedef struct cfutimer cfutimer_t; + +/* Return a new cfutimer structure. */ +cfutimer_t *cfutimer_new(void); + +/* Start the timer. */ +void cfutimer_start(cfutimer_t *timer); + +/* Stop the timer. */ +void cfutimer_stop(cfutimer_t *timer); + +/* Return the number of seconds elapsed as a double. */ +double cfutimer_elapsed(cfutimer_t *timer); + +/* Deallocate resources allocated for time. */ +void cfutimer_free(cfutimer_t *timer); + +CFU_END_DECLS + +#endif /* CFU_TIMER_H_ */