chiark / gitweb /
Shun time(), since on Linux it is not monotonic with gettimeofday().
authorRichard Kettlewell <rjk@greenend.org.uk>
Sun, 18 Oct 2009 13:00:03 +0000 (14:00 +0100)
committerRichard Kettlewell <rjk@greenend.org.uk>
Sun, 18 Oct 2009 13:00:03 +0000 (14:00 +0100)
http://ewx.livejournal.com/530850.html describes the underlying issue
and http://code.google.com/p/disorder/issues/detail?id=35 describes the
effect of this on DisOrder.

24 files changed:
cgi/actions.c
cgi/disorder-cgi.h
clients/playrtp.c
disobedience/client.c
disobedience/queue-generic.c
disobedience/queue.c
lib/cache.c
lib/cookies.c
lib/eclient.c
lib/sendmail.c
lib/syscalls.c
lib/syscalls.h
lib/trackdb.c
libtests/t-dateparse.c
libtests/t-event.c
server/choose.c
server/disorderd.c
server/play.c
server/queue-ops.c
server/rescan.c
server/schedule.c
server/server-queue.c
server/server.c
server/speaker.c

index d752660a141fe6d0d1406cf818028d39279851ea..ab52c2d9b1284b55e2a7f5468409ecc0e83a1581 100644 (file)
@@ -75,7 +75,7 @@ static void act_playing(void) {
      && length
      && dcgi_playing->sofar >= 0) {
     /* Try to put the next refresh at the start of the next track. */
-    time(&now);
+    xtime(&now);
     fin = now + length - dcgi_playing->sofar + config->gap;
     if(now + refresh > fin)
       refresh = fin - now;
index 9a455e9ed6f3ce978471f65a87e0082b1be8295a..4587e78795b7b17d2079563875b27e4bdba3cad3 100644 (file)
@@ -52,6 +52,7 @@
 #include "mime.h"
 #include "sendmail.h"
 #include "charset.h"
+#include "syscalls.h"
 
 extern disorder_client *dcgi_client;
 extern char *dcgi_cookie;
index c07c153e1938b71b5d0b409b4cac40844d8ed421..7eed9eb3529f75f58b4ca76f34ee0c1012bee766 100644 (file)
@@ -858,7 +858,7 @@ int main(int argc, char **argv) {
          || (nsamples > 0
              && contains(pheap_first(&packets), next_timestamp))) {
       if(monitor) {
-        time_t now = time(0);
+        time_t now = xtime(0);
 
         if(now >= lastlog + 60) {
           int offset = nsamples - minbuffer;
index dd40597fcc3962874b9166206629ddca90508119..45c6c0a94b2406d408a0c546d6722ca4bb71b640 100644 (file)
@@ -37,7 +37,7 @@ static gboolean gtkclient_prepare(GSource *source,
                                  gint *timeout) {
   const struct eclient_source *esource = (struct eclient_source *)source;
   D(("gtkclient_prepare"));
-  if(time(0) > esource->last_poll + 10)
+  if(xtime(0) > esource->last_poll + 10)
     return TRUE;               /* timed out */
   *timeout = 3000/*milliseconds*/;
   return FALSE;                        /* please poll */
@@ -65,7 +65,7 @@ static gboolean gtkclient_dispatch(GSource *source,
     mode |= DISORDER_POLL_READ;
   if(revents & (G_IO_OUT|G_IO_HUP|G_IO_ERR))
     mode |= DISORDER_POLL_WRITE;
-  time(&esource->last_poll);
+  xtime(&esource->last_poll);
   disorder_eclient_polled(esource->client, mode);
   return TRUE;                          /* ??? not documented */
 }
index 636f10ca005167d54dda4a2e3647617fbb0e75d1..aa29c28ead2751a72339af4ae28a99aef42dadd6 100644 (file)
@@ -129,7 +129,7 @@ const char *column_length(const struct queue_entry *q,
     else {
       if(!last_playing)
         return NULL;
-      time(&now);
+      xtime(&now);
       l = playing_track->sofar + (now - last_playing);
     }
     byte_xasprintf(&played, "%ld:%02ld/%s", l / 60, l % 60, length);
index 6dac960c6da05e927347aec92f6fea7cc6f40eb1..7779c0fc1ccb8b6c1792ee33cb9d37c7da59fdc5 100644 (file)
@@ -97,7 +97,7 @@ static void playing_completed(void attribute((unused)) *v,
   }
   actual_playing_track = q;
   queue_playing_changed();
-  time(&last_playing);
+  xtime(&last_playing);
 }
 
 /** @brief Schedule an update to the queue
index e0f69ef6225cff4048914529a6a9b976fa64ac33..52629de4234f6e31e72028622e4a6d6171aa17be 100644 (file)
@@ -24,6 +24,7 @@
 #include "hash.h"
 #include "mem.h"
 #include "log.h"
+#include "syscalls.h"
 #include "cache.h"
 
 /** @brief The global cache */
@@ -60,7 +61,7 @@ void cache_put(const struct cache_type *type,
   c = xmalloc(sizeof *c);
   c->type = type;
   c->value = value;
-  time(&c->birth);
+  xtime(&c->birth);
   hash_add(h, key, c,  HASH_INSERT_OR_REPLACE);
 }
 
@@ -75,7 +76,7 @@ const void *cache_get(const struct cache_type *type, const char *key) {
   if(h
      && (c = hash_find(h, key))
      && c->type == type
-     && !expired(c, time(0)))
+     && !expired(c, xtime(0)))
     return c->value;
   else
     return 0;
@@ -98,7 +99,7 @@ void cache_expire(void) {
   time_t now;
 
   if(h) {
-    time(&now);
+    xtime(&now);
     hash_foreach(h, expiry_callback, &now);
   }
 }
index 0ff17b5410643eb83efca8f6438cc24a713fb7a6..e32fc0c194fd2940790e77046fd81f2233d780b4 100644 (file)
@@ -35,6 +35,7 @@
 #include "configuration.h"
 #include "kvp.h"
 #include "trackdb.h"
+#include "syscalls.h"
 
 /** @brief Hash function used in signing HMAC */
 #define ALGO GCRY_MD_SHA1
@@ -66,7 +67,7 @@ static int revoked_cleanup_callback(const char *key, void *value,
 static void newkey(void) {
   time_t now;
 
-  time(&now);
+  xtime(&now);
   memcpy(old_signing_key, signing_key, HASHSIZE);
   gcry_randomize(signing_key, HASHSIZE, GCRY_STRONG_RANDOM);
   signing_key_validity_limit = now + config->cookie_key_lifetime;
@@ -134,7 +135,7 @@ char *make_cookie(const char *user) {
     return 0;
   }
   /* make sure we have a valid signing key */
-  time(&now);
+  xtime(&now);
   if(now >= signing_key_validity_limit)
     newkey();
   /* construct the subject */
@@ -187,7 +188,7 @@ char *verify_cookie(const char *cookie, rights_type *rights) {
   /* Extract the username */
   user = xstrndup(c1 + 1, c2 - (c1 + 1));
   /* check expiry */
-  time(&now);
+  xtime(&now);
   if(now >= t) {
     error(0, "cookie has expired");
     return 0;
index 40639f35d986f993a1e522971ca5e6cd7b653d4e..101a7bff049ccab4f82827f8e70af67788b18626 100644 (file)
@@ -417,7 +417,7 @@ void disorder_eclient_polled(disorder_eclient *c, unsigned mode) {
   /* Queue up a byte to send */
   if(c->state == state_log
      && c->output.nvec == 0
-     && time(&now) - c->last_prod > LOG_PROD_INTERVAL) {
+     && xtime(&now) - c->last_prod > LOG_PROD_INTERVAL) {
     put(c, "x", 1);
     c->last_prod = now;
   }
index 5b9a82cb26eef9dfd0acd33ecd9a6e28b148dc68..a01b9d3dec458b5d097bd26d856b196e57aba1ed 100644 (file)
@@ -126,7 +126,7 @@ static int sendmailfp(const char *tag, FILE *in, FILE *out,
   time_t now;
   char date[128];
 
-  time(&now);
+  xtime(&now);
   gmtime_r(&now, &ut);
   strftime(date, sizeof date, "%a, %d %b %Y %H:%M:%S +0000", &ut);
   gcry_create_nonce(idbuf, sizeof idbuf);
index 0d5dc187a0111eb637b32469951a769d50b27b60..b1756667fe22386283ea81f7054e2e7c9fcaf653 100644 (file)
@@ -148,6 +148,15 @@ void xgettimeofday(struct timeval *tv, struct timezone *tz) {
   mustnotbeminus1("gettimeofday", gettimeofday(tv, tz));
 }
 
+time_t xtime(time_t *whenp) {
+  struct timeval tv;
+
+  xgettimeofday(&tv, NULL);
+  if(whenp)
+    *whenp = tv.tv_sec;
+  return tv.tv_sec;
+}
+
 /*
 Local Variables:
 c-basic-offset:2
index 9f8bd206fb142c17ad6840804ac4b972c0c6eba3..e45125a8473449666cf9b86058470a1c34421c7e 100644 (file)
@@ -48,6 +48,7 @@ int xprintf(const char *, ...)
 void xfclose(FILE *);
 int xnice(int);
 void xgettimeofday(struct timeval *, struct timezone *);
+time_t xtime(time_t *when);
 /* the above all call @fatal@ if the system call fails */
 
 void nonblock(int fd);
index 83a67af3f1a499f9fb28677bff087993ecc35d46..6984b21f8623555b1769f24b97afc1cd8e05150c 100644 (file)
@@ -1042,7 +1042,7 @@ int trackdb_notice_tid(const char *track,
   /* this is a real track */
   t_changed += kvp_set(&t, "_alias_for", 0);
   t_changed += kvp_set(&t, "_path", path);
-  time(&now);
+  xtime(&now);
   if(ret == DB_NOTFOUND) {
     /* It's a new track; record the time */
     byte_xasprintf(&noticed, "%lld", (long long)now);
@@ -2598,7 +2598,7 @@ static int create_user(const char *user,
     kvp_set(&k, "email", email);
   if(confirmation)
     kvp_set(&k, "confirmation", confirmation);
-  snprintf(s, sizeof s, "%jd", (intmax_t)time(0));
+  snprintf(s, sizeof s, "%jd", (intmax_t)xtime(0));
   kvp_set(&k, "created", s);
   return trackdb_putdata(trackdb_usersdb, user, k, tid, flags);
 }
index a0a3b0d226c0ece42baea51c7c7947a4fc53ad1d..7926e016c0aed17459924951757ec11da95a50f1 100644 (file)
@@ -33,7 +33,7 @@ static void check_date(time_t when,
 }
 
 static void test_dateparse(void) {
-  time_t now = time(0);
+  time_t now = xtime(0);
   check_date(now, "%Y-%m-%d %H:%M:%S", localtime);
 #if 0         /* see dateparse.c */
   check_date(now, "%Y-%m-%d %H:%M:%S %Z", localtime);
index 3a723b4aaaff1a9c49e092075ebe0c8e44d6e871..1474408d5a74ad1f54d28f5e58ff439ea73a3a24 100644 (file)
@@ -51,13 +51,13 @@ static void test_event(void) {
   ev_source *ev;
 
   ev = ev_new();
-  w.tv_sec = time(0) + 2;
+  w.tv_sec = xtime(0) + 2;
   w.tv_usec = 0;
   ev_timeout(ev, &t1, &w, callback1, 0);
-  w.tv_sec = time(0) + 3;
+  w.tv_sec = xtime(0) + 3;
   w.tv_usec = 0;
   ev_timeout(ev, &t2, &w, callback2, 0);
-  w.tv_sec = time(0) + 4;
+  w.tv_sec = xtime(0) + 4;
   w.tv_usec = 0;
   ev_timeout(ev, &t3, &w, callback3, 0);
   check_integer(ev_run(ev), 1);
index 10ed360d962ad22113ea41418e029211c1cc1a02..733b3ca6bc5ddfa151b23cafa8dd1b4e03511703 100644 (file)
@@ -92,7 +92,7 @@ static unsigned long compute_weight(const char *track,
                                     struct kvp *prefs) {
   const char *s;
   char **track_tags;
-  time_t last, now = time(0);
+  time_t last, now = xtime(0);
 
   /* Reject tracks not in any collection (race between edit config and
    * rescan) */
index 31b70a4e917de00b7e3effa96a2fa61349baaa02..ab88190bfd6577b57c44f8bf73df064196a03f85 100644 (file)
@@ -207,7 +207,7 @@ int main(int argc, char **argv) {
   }
   info("process ID %lu", (unsigned long)getpid());
   fix_path();
-  srand(time(0));                      /* don't start the same every time */
+  srand(xtime(0));                     /* don't start the same every time */
   /* gcrypt initialization */
   if(!gcry_check_version(NULL))
     disorder_fatal(0, "gcry_check_version failed");
index f9719912f7f0b62d4c7db982cb37c7710dce962d..b9d452bb7f8ff9bc8352b708b154999c1100280e 100644 (file)
@@ -583,7 +583,7 @@ void play(ev_source *ev) {
     }
     /* It's become the playing track */
     playing = q;
-    time(&playing->played);
+    xtime(&playing->played);
     playing->state = playing_started;
     notify_play(playing->track, playing->submitter);
     eventlog("playing", playing->track,
@@ -685,7 +685,7 @@ void scratch(const char *who, const char *id) {
       q = queue_add(config->scratch.s[r], who, WHERE_START, origin_scratch);
     }
     notify_scratch(playing->track, playing->submitter, who,
-                  time(0) - playing->played);
+                  xtime(0) - playing->played);
   }
 }
 
@@ -735,7 +735,7 @@ int pause_playing(const char *who) {
       error(0, "player indicates it cannot pause");
       return -1;
     }
-    time(&playing->lastpaused);
+    xtime(&playing->lastpaused);
     playing->uptopause = played;
     playing->lastresumed = 0;
     break;
@@ -769,7 +769,7 @@ void resume_playing(const char *who) {
       return;
     }
     play_resume(playing->pl, playing->data);
-    time(&playing->lastresumed);
+    xtime(&playing->lastresumed);
     break;
   case DISORDER_PLAYER_RAW:
     memset(&sm, 0, sizeof sm);
index d5b5bf3169cf83813255578fbe06990e72b7be97..ed97c0c805d2227aba8683d96af2569e4f06d400 100644 (file)
@@ -59,7 +59,7 @@ struct queue_entry *queue_add(const char *track, const char *submitter,
   q->origin = origin;
   q->pid = -1;
   queue_id(q);
-  time(&q->when);
+  xtime(&q->when);
   switch(where) {
   case WHERE_START:
     queue_insert_entry(&qhead, q);
index ebff0989d04699cae4bd03fde9d3e2eb965ec6f0..dfe855a4afb6b0684153dc13cb3e56134f5db4ab 100644 (file)
@@ -134,9 +134,9 @@ static void rescan_collection(const struct collection *c) {
     if(n < config->player.n) {
       nnew += !!trackdb_notice(track, path);
       ++ntracks;
-      if(ntracks % 100 == 0 && time(0) > last_report + 10) {
+      if(ntracks % 100 == 0 && xtime(0) > last_report + 10) {
         info("rescanning %s, %ld tracks so far", c->root, ntracks);
-        time(&last_report);
+        xtime(&last_report);
       }
     }
   }
@@ -300,12 +300,12 @@ static void recheck_collection(const struct collection *c) {
       return;
     recheck_track(&cs, t);
     ++nrc;
-    if(nrc % 100 == 0 && time(0) > last_report + 10) {
+    if(nrc % 100 == 0 && xtime(0) > last_report + 10) {
       if(c)
         info("rechecking %s, %ld tracks so far", c->root, nrc);
       else
         info("rechecking all tracks, %ld tracks so far", nrc);
-      time(&last_report);
+      xtime(&last_report);
     }
   }
   if(c)
@@ -350,7 +350,7 @@ static void do_all(void (*fn)(const struct collection *c)) {
 static void expire_noticed(void) {
   time_t now;
 
-  time(&now);
+  xtime(&now);
   trackdb_expire_noticed(now - config->noticed_history * 86400);
 }
 
index ec7eddce118d49b901055994372be1b13035f23a..2669feded9aa0518a8812895d67a11afd4ea5143 100644 (file)
@@ -182,7 +182,7 @@ static int schedule_init_tid(ev_source *ev,
     }
     when.tv_usec = 0;
     /* The action might be in the past */
-    if(when.tv_sec < time(0)) {
+    if(when.tv_sec < xtime(0)) {
       const char *priority = kvp_get(actiondata, "priority");
 
       if(priority && !strcmp(priority, "junk")) {
@@ -287,7 +287,7 @@ const char *schedule_add(ev_source *ev,
   when.tv_sec = atoll(kvp_get(actiondata, "when"));
   when.tv_usec = 0;
   /* Reject events in the past */
-  if(when.tv_sec <= time(0)) {
+  if(when.tv_sec <= xtime(0)) {
     error(0, "new scheduled event is in the past");
     return 0;
   }
index 2efd94a361b46b00c1766db41a7215d63550e3ae..ab154748900cde84fd247b66e305cadb01180790 100644 (file)
@@ -50,11 +50,11 @@ void queue_fix_sofar(struct queue_entry *q) {
       if(q->uptopause == -1)           /* Don't know how far thru. */
        sofar = -1;
       else if(q->lastresumed)          /* Has been paused and resumed. */
-       sofar = q->uptopause + time(0) - q->lastresumed;
+       sofar = q->uptopause + xtime(0) - q->lastresumed;
       else                             /* Currently paused. */
        sofar = q->uptopause;
     } else                             /* Never been paused. */
-      sofar = time(0) - q->played;
+      sofar = xtime(0) - q->played;
     q->sofar = sofar;
   }
 }
index 8bd23e74329227ea0bda09779357ab20c0f14727..feaac7e00163deec4afd3777312c1952bba1040a 100644 (file)
@@ -541,13 +541,13 @@ static int c_queue(struct conn *c,
       queue_fix_sofar(playing);
       if((l = trackdb_get(playing->track, "_length"))
         && (length = atol(l))) {
-       time(&when);
+       xtime(&when);
        when += length - playing->sofar + config->gap;
       }
     } else
       /* Nothing is playing but playing is enabled, so whatever is
        * first in the queue can be expected to start immediately. */
-      time(&when);
+      xtime(&when);
   }
   for(q = qhead.next; q != &qhead; q = q->next) {
     /* fill in estimated start time */
@@ -894,7 +894,7 @@ static void logclient(const char *msg, void *user) {
       return;
   }
   sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" %s\n",
-             (uintmax_t)time(0), msg);
+             (uintmax_t)xtime(0), msg);
 }
 
 static int c_log(struct conn *c,
@@ -904,7 +904,7 @@ static int c_log(struct conn *c,
 
   sink_writes(ev_writer_sink(c->w), "254 OK\n");
   /* pump out initial state */
-  time(&now);
+  xtime(&now);
   sink_printf(ev_writer_sink(c->w), "%"PRIxMAX" state %s\n",
              (uintmax_t)now, 
              playing_is_enabled() ? "enable_play" : "disable_play");
@@ -1262,7 +1262,7 @@ static int c_edituser(struct conn *c,
             if(d->lo)
               sink_printf(ev_writer_sink(d->w),
                           "%"PRIxMAX" rights_changed %s\n",
-                          (uintmax_t)time(0),
+                          (uintmax_t)xtime(0),
                           quoteutf8(new_rights));
           }
         }
@@ -1443,7 +1443,7 @@ static int c_reminder(struct conn *c,
   if(!last_reminder)
     last_reminder = hash_new(sizeof (time_t));
   last = hash_find(last_reminder, vec[0]);
-  time(&now);
+  xtime(&now);
   if(last && now < *last + config->reminder_interval) {
     error(0, "sent a password reminder to '%s' too recently", vec[0]);
     sink_writes(ev_writer_sink(c->w), "550 Cannot send a reminder email\n");
index 2206547674134ee3afd5c1b7c026919a98d329c6..892e33c960ceb631578d217d202724af22254dc2 100644 (file)
@@ -370,7 +370,7 @@ static void report(void) {
     strcpy(sm.id, playing->id);
     sm.data = playing->played / (uaudio_rate * uaudio_channels);
     speaker_send(1, &sm);
-    time(&last_report);
+    xtime(&last_report);
   }
 }
 
@@ -684,7 +684,7 @@ static void mainloop(void) {
       }
     }
     /* If we've not reported our state for a second do so now. */
-    if(force_report || time(0) > last_report)
+    if(force_report || xtime(0) > last_report)
       report();
   }
 }