From 24758c5f17064273786e704b84ceff56c234e347 Mon Sep 17 00:00:00 2001
From: Andre Noll <maan@systemlinux.org>
Date: Sun, 31 Mar 2013 02:03:04 +0000
Subject: [PATCH] Replace gettimeofday() by clock_gettime().

POSIX.1-2008 marks gettimeofday() as obsolete, so let's switch to
clock_gettime().

clock_gettime() operates on timespecs rather than on timevals like
gettimeofday() does. Since timevals are extensively used in all
parts of paraslash, and select() takes a timeval pointer as the
timeout parameter, it seems to be easiest to add a new wrapper,
clock_get_realtime(). It calls clock_gettime(), performs error
checking (all errors are treated fatal and abort the program), and
converts the result to a timeval.

Another difference between gettimeofday() and clock_gettime()
is that sys/time.h needs to be included for gettimeofday(), while
clock_gettime() is declared in time.h which gets included from para.h.
Hence we can remove the include statement for sys/time.h everywhere.

Programs which call clock_gettime need to be linked against librt on
glibc versions before 2.17 while BSD and newer glibc-based systems
have no such requirement. To make matters more interesting,
MacOS lacks clock_gettime() completely although this function conforms
to SUSv2 and POSIX.1-2001.

We'd like to avoid the unnecessary dependence on librt on systems that
have clock_gettime() in -lc, and we must fall back to gettimeofday()
on MacOS. Hence this commit also introduces a check in configure.ac
which determines whether clock_gettime() is available and, if it is,
whether -lrt is needed. Executables are only linked with -lrt if
configure found that this is necessary.
---
 Makefile.in     |  2 ++
 afh.c           |  1 -
 afh_common.c    |  1 -
 alsa_write.c    |  1 -
 command.c       |  3 +--
 configure.ac    | 12 ++++++++++++
 daemon.c        |  3 +--
 file_write.c    |  5 +----
 para.h          |  1 +
 play.c          |  3 +--
 sched.c         |  9 ++++-----
 sched.h         |  2 +-
 server.c        |  3 +--
 string.c        |  1 -
 time.c          | 37 +++++++++++++++++++++++++++++++++++++
 udp_send.c      |  1 -
 wmadec_filter.c |  1 -
 17 files changed, 62 insertions(+), 24 deletions(-)

diff --git a/Makefile.in b/Makefile.in
index d577ce29..7ccd970d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -79,6 +79,8 @@ CPPFLAGS += -I/usr/local/include
 CPPFLAGS += -I$(cmdline_dir)
 CPPFLAGS += @osl_cppflags@
 
+LDFLAGS += @clock_gettime_ldflags@
+
 man_pages := $(patsubst %, $(man_dir)/%.1, @executables@)
 
 autocrap := config.h.in configure
diff --git a/afh.c b/afh.c
index aab664c2..4c65d7c1 100644
--- a/afh.c
+++ b/afh.c
@@ -7,7 +7,6 @@
 /** \file afh.c Paraslash's standalone audio format handler tool. */
 
 #include <regex.h>
-#include <sys/time.h>
 
 #include "para.h"
 #include "string.h"
diff --git a/afh_common.c b/afh_common.c
index 5c866c1f..6c161a7c 100644
--- a/afh_common.c
+++ b/afh_common.c
@@ -7,7 +7,6 @@
 /** \file afh_common.c Common audio format handler functions. */
 
 #include <sys/mman.h> /* mmap */
-#include <sys/time.h> /* gettimeofday */
 #include <sys/types.h>
 #include <regex.h>
 
diff --git a/alsa_write.c b/alsa_write.c
index ba844db2..43f0811a 100644
--- a/alsa_write.c
+++ b/alsa_write.c
@@ -15,7 +15,6 @@
 #include <regex.h>
 #include <sys/types.h>
 #include <alsa/asoundlib.h>
-#include <sys/time.h>
 
 #include "para.h"
 #include "fd.h"
diff --git a/command.c b/command.c
index aaaaaecf..ec822c82 100644
--- a/command.c
+++ b/command.c
@@ -8,7 +8,6 @@
 
 #include <regex.h>
 #include <signal.h>
-#include <sys/time.h>
 #include <sys/types.h>
 #include <osl.h>
 
@@ -124,7 +123,7 @@ static unsigned get_status(struct misc_meta_data *nmmd, int parser_friendly,
 		localtime_r(&nmmd->mtime, &mtime_tm);
 		strftime(mtime, 29, "%b %d %Y", &mtime_tm);
 	}
-	gettimeofday(&current_time, NULL);
+	clock_get_realtime(&current_time);
 	/*
 	 * The calls to WRITE_STATUS_ITEM() below never fail because
 	 * b->max_size is zero (unlimited), see para_printf(). However, clang
diff --git a/configure.ac b/configure.ac
index 4512c6fd..6f0fbc0c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -247,6 +247,18 @@ if test x$ac_cv_have_working_snprintf$ac_cv_have_working_vsnprintf != "xyesyes";
 AC_MSG_ERROR([fatal: buggy snprintf() detected])
 fi])
 AX_FUNC_SNPRINTF()
+################################################################## clock_gettime
+clock_gettime_lib=
+AC_CHECK_LIB([c], [clock_gettime], [clock_gettime_lib=c], [
+	AC_CHECK_LIB([rt], [clock_gettime], [clock_gettime_lib=rt], [], [])
+])
+if test -n "$clock_gettime_lib"; then
+	AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [
+		define to 1 if clock_gettime() is supported])
+fi
+if test "$clock_gettime_lib" = "rt"; then
+	AC_SUBST(clock_gettime_ldflags, -lrt)
+fi
 ########################################################################### osl
 have_osl=yes
 OLD_CPPFLAGS="$CPPFLAGS"
diff --git a/daemon.c b/daemon.c
index 29b00ed2..18ad1568 100644
--- a/daemon.c
+++ b/daemon.c
@@ -10,7 +10,6 @@
 #include <pwd.h>
 #include <sys/types.h> /* getgrnam() */
 #include <grp.h>
-#include <sys/time.h>
 #include <signal.h>
 
 #include "para.h"
@@ -374,7 +373,7 @@ __printf_2_3 void daemon_log(int ll, const char* fmt,...)
 		fprintf(fp, "%s", color);
 	if (log_time || log_timing) {
 		struct timeval tv;
-		gettimeofday(&tv, NULL);
+		clock_get_realtime(&tv);
 		if (daemon_test_flag(DF_LOG_TIME)) { /* print date and time */
 			time_t t1 = tv.tv_sec;
 			char str[100];
diff --git a/file_write.c b/file_write.c
index a12867d5..3f764766 100644
--- a/file_write.c
+++ b/file_write.c
@@ -8,7 +8,6 @@
 
 #include <regex.h>
 #include <sys/types.h>
-#include <sys/time.h>
 
 #include "para.h"
 #include "list.h"
@@ -38,10 +37,8 @@ struct private_file_write_data {
 __must_check __malloc static char *random_filename(void)
 {
 	char *result, *home = para_homedir();
-	struct timeval tv;
 
-	gettimeofday(&tv, NULL);
-	srandom(tv.tv_usec);
+	srandom(clock_get_realtime(NULL)->tv_usec);
 	result = make_message("%s/.paraslash/%08lu", home,
 		para_random(99999999));
 	free(home);
diff --git a/para.h b/para.h
index 4208ae6a..edab4871 100644
--- a/para.h
+++ b/para.h
@@ -109,6 +109,7 @@ void ms2tv(const long unsigned n, struct timeval *tv);
 void compute_chunk_time(long unsigned chunk_num,
 		struct timeval *chunk_tv, struct timeval *stream_start,
 		struct timeval *result);
+struct timeval *clock_get_realtime(struct timeval *tv);
 
 /** The enum of all status items. */
 enum status_items {STATUS_ITEM_ENUM NUM_STAT_ITEMS};
diff --git a/play.c b/play.c
index cca203b5..fb72bae4 100644
--- a/play.c
+++ b/play.c
@@ -7,7 +7,6 @@
 /** \file play.c Paraslash's standalone player. */
 
 #include <regex.h>
-#include <sys/time.h>
 #include <fnmatch.h>
 #include <signal.h>
 
@@ -1255,7 +1254,7 @@ int main(int argc, char *argv[])
 	filter_init();
 	writer_init();
 
-	gettimeofday(now, NULL);
+	clock_get_realtime(now);
 	sched.default_timeout.tv_sec = 5;
 
 	parse_config_or_die(argc, argv);
diff --git a/sched.c b/sched.c
index 05851621..95a07d29 100644
--- a/sched.c
+++ b/sched.c
@@ -8,7 +8,6 @@
 
 #include <regex.h>
 #include <assert.h>
-#include <sys/time.h>
 
 #include "para.h"
 #include "ipc.h"
@@ -68,9 +67,9 @@ static inline void call_post_select(struct sched *s, struct task *t)
 	struct timeval t1, t2, diff;
 	unsigned long pst;
 
-	gettimeofday(&t1, NULL);
+	clock_get_realtime(&t1);
 	t->post_select(s, t);
-	gettimeofday(&t2, NULL);
+	clock_get_realtime(&t2);
 	tv_diff(&t1, &t2, &diff);
 	pst = tv2ms(&diff);
 	if (pst > 50)
@@ -120,7 +119,7 @@ again:
 	FD_ZERO(&s->wfds);
 	s->select_timeout = s->default_timeout;
 	s->max_fileno = -1;
-	gettimeofday(now, NULL);
+	clock_get_realtime(now);
 	sched_preselect(s);
 	ret = s->select_function(s->max_fileno + 1, &s->rfds, &s->wfds,
 		&s->select_timeout);
@@ -136,7 +135,7 @@ again:
 		FD_ZERO(&s->rfds);
 		FD_ZERO(&s->wfds);
 	}
-	gettimeofday(now, NULL);
+	clock_get_realtime(now);
 	sched_post_select(s);
 	if (list_empty(&s->pre_select_list) && list_empty(&s->post_select_list))
 		return 0;
diff --git a/sched.h b/sched.h
index 7a5a4f86..021474a2 100644
--- a/sched.h
+++ b/sched.h
@@ -76,7 +76,7 @@ struct task {
  * This is set by the scheduler at the beginning of its main loop.  It may be
  * used (read-only) from everywhere. As none of the functions called by the
  * scheduler are allowed to block, this value should be accurate enough so that
- * there is no need to call gettimeofday() directly.
+ * there is no need to call clock_gettime() directly.
  */
 extern struct timeval *now;
 
diff --git a/server.c b/server.c
index 2595d9c4..57f0c26e 100644
--- a/server.c
+++ b/server.c
@@ -67,7 +67,6 @@
  */
 
 #include <signal.h>
-#include <sys/time.h>
 #include <regex.h>
 #include <osl.h>
 
@@ -493,7 +492,7 @@ static void server_init(int argc, char **argv)
 	log_welcome("para_server");
 	init_ipc_or_die(); /* init mmd struct and mmd->lock */
 	/* make sure, the global now pointer is uptodate */
-	gettimeofday(now, NULL);
+	clock_get_realtime(now);
 	set_server_start_time(now);
 	init_user_list(user_list_file);
 	/* become daemon */
diff --git a/string.c b/string.c
index c001b15d..e5de147c 100644
--- a/string.c
+++ b/string.c
@@ -6,7 +6,6 @@
 
 /** \file string.c Memory allocation and string handling functions. */
 
-#include <sys/time.h> /* gettimeofday */
 #include <pwd.h>
 #include <sys/utsname.h> /* uname() */
 #include <string.h>
diff --git a/time.c b/time.c
index 18b5a35f..6f6dd49e 100644
--- a/time.c
+++ b/time.c
@@ -191,3 +191,40 @@ void compute_chunk_time(long unsigned chunk_num,
 	tv_scale(chunk_num, chunk_tv, &tmp);
 	tv_add(&tmp, stream_start, result);
 }
+
+/**
+ * Retrieve the time of the realtime clock.
+ *
+ * \param tv Where to store the result.
+ *
+ * Gets the current value of the system-wide real-time clock (identified by id
+ * \p CLOCK_REALTIME). If \a tv is \p NULL, the value is stored in a static
+ * buffer, otherwise it is stored at the location given by \a tv.
+ *
+ * \return This function aborts on errors. On success it returns a pointer to
+ * memory containing the current time.
+ *
+ * \sa clock_gettime(2), gettimeofday(2).
+ */
+struct timeval *clock_get_realtime(struct timeval *tv)
+{
+	static struct timeval user_friendly;
+
+	if (!tv)
+		tv = &user_friendly;
+#ifdef HAVE_CLOCK_GETTIME
+	{
+		struct timespec t;
+		int ret;
+
+		ret = clock_gettime(CLOCK_REALTIME, &t);
+		assert(ret == 0);
+		tv->tv_sec = t.tv_sec;
+		tv->tv_usec = t.tv_nsec / 1000;
+	}
+#else
+	#include <sys/time.h>
+	gettimeofday(tv, NULL);
+#endif /* HAVE_CLOCK_GETTIME */
+	return tv;
+}
diff --git a/udp_send.c b/udp_send.c
index b41c0ebf..b1da3167 100644
--- a/udp_send.c
+++ b/udp_send.c
@@ -8,7 +8,6 @@
 
 
 #include <regex.h>
-#include <sys/time.h>
 #include <sys/socket.h>
 #include <netinet/udp.h>
 #include <net/if.h>
diff --git a/wmadec_filter.c b/wmadec_filter.c
index 20f9df44..ce8d7e87 100644
--- a/wmadec_filter.c
+++ b/wmadec_filter.c
@@ -17,7 +17,6 @@
 
 #define _XOPEN_SOURCE 600
 
-#include <sys/time.h>
 #include <inttypes.h>
 #include <stdio.h>
 #include <stdlib.h>
-- 
2.39.5