Localize the OS-specific bits of retrieving the current time a bit more.
authorKen Raeburn <raeburn@mit.edu>
Tue, 15 Jun 2004 19:06:13 +0000 (19:06 +0000)
committerKen Raeburn <raeburn@mit.edu>
Tue, 15 Jun 2004 19:06:13 +0000 (19:06 +0000)
** not yet tested on Windows **

* c_ustime.c: Include k5-thread.h.
(get_time_now): New function, holds system-dependent code.
(krb5int_us_time_mutex): New mutex.
(struct time_now): New type.
(last_time): New variable, replaces old last_tv, last_sec, last_usec.
(krb5_crypto_us_timeofday): Rewrite.  Do locking around access to previously
returned value, and ensure that we don't return duplicate values.
* os-proto.h: Include k5-thread.h.
(krb5int_us_time_mutex): Declare.

git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@16454 dc483132-0cff-0310-8789-dd5450dbe970

src/lib/krb5/os/ChangeLog
src/lib/krb5/os/c_ustime.c
src/lib/krb5/os/os-proto.h

index 07ab6ee095a06d1f59eaa7a4ead20c41a4ef40ec..606b1a44f30f60018897d12707752a639880d7f5 100644 (file)
@@ -1,3 +1,17 @@
+2004-06-15  Ken Raeburn  <raeburn@mit.edu>
+
+       * c_ustime.c: Include k5-thread.h.
+       (get_time_now): New function, holds system-dependent code.
+       (krb5int_us_time_mutex): New mutex.
+       (struct time_now): New type.
+       (last_time): New variable, replaces old last_tv, last_sec,
+       last_usec.
+       (krb5_crypto_us_timeofday): Rewrite.  Do locking around access to
+       previously returned value, and ensure that we don't return
+       duplicate values.
+       * os-proto.h: Include k5-thread.h.
+       (krb5int_us_time_mutex): Declare.
+
 2004-06-04  Ken Raeburn  <raeburn@mit.edu>
 
        * kuserok.c (krb5_kuserok): Handle draft POSIX versions of
index 4a049649f781771ae174ca277d86aee00f929e6f..81998daab7fe1d841102854bf1ffbb55c7fe4844 100644 (file)
  
 #define        NEED_SOCKETS
 #include "k5-int.h"
+#include "k5-thread.h"
+
+k5_mutex_t krb5int_us_time_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
+
+struct time_now { krb5_int32 sec, usec; };
 
 #if defined(_WIN32)
 
 #include <sys/timeb.h>
 #include <string.h>
 
-krb5_error_code
-krb5_crypto_us_timeofday(seconds, microseconds)
-register krb5_int32 *seconds, *microseconds;
+static krb5_error_code
+get_time_now(struct time_now *n)
 {
     struct _timeb timeptr;
-    krb5_int32 sec, usec;
-    static krb5_int32 last_sec = 0;
-    static krb5_int32 last_usec = 0;
-
-    _ftime(&timeptr);                           /* Get the current time */
-    sec  = timeptr.time;
-    usec = timeptr.millitm * 1000;
-
-    if ((sec == last_sec) && (usec <= last_usec)) { /* Same as last time??? */
-        usec = ++last_usec;
-        if (usec >= 1000000) {
-            ++sec;
-            usec = 0;
-        }
-    }
-    last_sec = sec;                             /* Remember for next time */
-    last_usec = usec;
-
-    *seconds = sec;                             /* Return the values */
-    *microseconds = usec;
-
+    _ftime(&timeptr);
+    n->sec = timeptr.time;
+    n->usec = timeptr.millitm * 1000;
     return 0;
 }
 
 #else
 
+/* Everybody else is UNIX, right?  POSIX 1996 doesn't give us
+   gettimeofday, but what real OS doesn't?  */
+
+static krb5_error_code
+get_time_now(struct time_now *n)
+{
+    struct timeval tv;
+
+    if (gettimeofday(&tv, (struct timezone *)0) == -1)
+       return errno;
 
-/* We're a Unix machine -- do Unix time things.  */
+    n->sec = tv.tv_sec;
+    n->usec = tv.tv_usec;
+    return 0;
+}
 
-static struct timeval last_tv = {0, 0};
+#endif
+
+static struct time_now last_time;
 
 krb5_error_code
-krb5_crypto_us_timeofday(register krb5_int32 *seconds, register krb5_int32 *microseconds)
+krb5_crypto_us_timeofday(krb5_int32 *seconds, krb5_int32 *microseconds)
 {
-    struct timeval tv;
+    struct time_now now;
+    krb5_error_code err;
 
-    if (gettimeofday(&tv, (struct timezone *)0) == -1) {
-       /* failed, return errno */
-       return (krb5_error_code) errno;
+    err = get_time_now(&now);
+    if (err)
+       return err;
+
+    err = k5_mutex_lock(&krb5int_us_time_mutex);
+    if (err)
+       return err;
+    /* Just guessing: If the number of seconds hasn't changed, yet the
+       microseconds are moving backwards, we probably just got a third
+       instance of returning the same clock value from the system, so
+       the saved value was artificially incremented.
+
+       On Windows, where we get millisecond accuracy currently, that's
+       quite likely.  On UNIX, it appears that we always get new
+       microsecond values, so this case should never trigger.  */
+    if ((now.sec == last_time.sec) && (now.usec <= last_time.usec)) {
+       /* Same as last time??? */
+       now.usec = ++last_time.usec;
+       if (now.usec >= 1000000) {
+           ++now.sec;
+           now.usec = 0;
+       }
+       /* For now, we're not worrying about the case of enough
+          returns of the same value that we roll over now.sec, and
+          the next call still gets the previous now.sec value.  */
     }
-    if ((tv.tv_sec == last_tv.tv_sec) && (tv.tv_usec == last_tv.tv_usec)) {
-           if (++last_tv.tv_usec >= 1000000) {
-                   last_tv.tv_usec = 0;
-                   last_tv.tv_sec++;
-           }
-           tv = last_tv;
-    } else 
-           last_tv = tv;
-           
-    *seconds = tv.tv_sec;
-    *microseconds = tv.tv_usec;
+    last_time.sec = now.sec;   /* Remember for next time */
+    last_time.usec = now.usec;
+    k5_mutex_unlock(&krb5int_us_time_mutex);
+
+    *seconds = now.sec;
+    *microseconds = now.usec;
     return 0;
 }
-
-#endif
index bc26a1dd953ad274d3cf7272a6e7ee1978779c2c..2e270d5c570d298d551606697f49f3799b01a40d 100644 (file)
@@ -60,6 +60,9 @@ int _krb5_use_dns_realm (krb5_context);
 int _krb5_use_dns_kdc (krb5_context);
 int _krb5_conf_boolean (const char *);
 
+#include "k5-thread.h"
+extern k5_mutex_t krb5int_us_time_mutex;
+
 extern unsigned int krb5_max_skdc_timeout;
 extern unsigned int krb5_skdc_timeout_shift;
 extern unsigned int krb5_skdc_timeout_1;