--- uuid.c 2004/01/10 19:17:39 1.17
+++ uuid.c 2004/01/10 21:47:45 1.18
@@ -121,10 +121,12 @@
/* abstract data type (ADT) of API */
struct uuid_st {
- uuid_obj_t obj; /* inlined UUID object */
- prng_t *prng; /* RPNG sub-object */
- md5_t *md5; /* MD5 sub-object */
- uuid_uint8_t mac[6]; /* pre-determined MAC address */
+ uuid_obj_t obj; /* inlined UUID object */
+ prng_t *prng; /* RPNG sub-object */
+ md5_t *md5; /* MD5 sub-object */
+ uuid_uint8_t mac[6]; /* pre-determined MAC address */
+ struct timeval time_last; /* last retrieved timestamp */
+ unsigned long time_seq; /* last timestamp sequence counter */
};
/* create UUID object */
@@ -153,6 +155,11 @@
(*uuid)->mac[0] = 0x80;
}
+ /* initialize time attributes */
+ (*uuid)->time_last.tv_sec = 0;
+ (*uuid)->time_last.tv_usec = 0;
+ (*uuid)->time_seq = 0;
+
return UUID_RC_OK;
}
@@ -467,22 +474,62 @@
return;
}
+/* maximum number of 100ns ticks of the actual resolution of system clock
+ (which in our case is 1us (= 1000ns) because we use gettimeofday(2) */
+#define UUIDS_PER_TICK 10
+
/* INTERNAL: generate UUID version 1, time part */
static uuid_rc_t uuid_generate_v1_time(uuid_t *uuid, unsigned int mode, va_list ap)
{
+ struct timeval time_now;
struct timeval tv;
ui64_t t;
ui64_t offset;
ui64_t ov;
- /* determine current system time */
- if (gettimeofday(&tv, NULL) == -1)
- return UUID_RC_SYS;
+ /* determine current system time and sequence counter */
+ while (1) {
+ /* determine current system time */
+ if (gettimeofday(&time_now, NULL) == -1)
+ return UUID_RC_SYS;
+
+ /* check whether system time changed since last retrieve */
+ if (!( time_now.tv_sec == uuid->time_last.tv_sec
+ && time_now.tv_usec == uuid->time_last.tv_usec)) {
+ /* reset time sequence counter */
+ uuid->time_seq = 0;
+
+ /* remember system time for next iteration */
+ uuid->time_last.tv_sec = time_now.tv_sec;
+ uuid->time_last.tv_usec = time_now.tv_usec;
+ }
+
+ /* until we are out of UUIDs per tick, increment
+ the time/tick sequence counter and continue */
+ if (uuid->time_seq < UUIDS_PER_TICK) {
+ uuid->time_seq++;
+ break;
+ }
+
+ /* else sleep a little bit until the system clock (which has
+ a gettimeofday(2) resolution of 1us) has changed. */
+#ifdef HAVE_NANOSLEEP
+ /* sleep for 500ns (1/2us) */
+ ts.tv_sec = 0;
+ ts.tv_nsec = 500;
+ nanosleep(&ts, NULL);
+#else
+ /* sleep for 1000ns (1us) */
+ tv.tv_sec = 0;
+ tv.tv_usec = 1;
+ select(0, NULL, NULL, NULL, &tv);
+#endif
+ }
/* convert from timeval (sec,usec) to OSSP ui64 (100*nsec) format */
- t = ui64_n2i(tv.tv_sec);
+ t = ui64_n2i(time_now.tv_sec);
t = ui64_muln(t, 1000000, NULL);
- t = ui64_addn(t, tv.tv_usec, NULL);
+ t = ui64_addn(t, time_now.tv_usec, NULL);
t = ui64_muln(t, 10, NULL);
/* adjust for offset between UUID and Unix Epoch time through adding
@@ -492,6 +539,11 @@
offset = ui64_s2i("01B21DD213814000", NULL, 16);
t = ui64_add(t, offset, NULL);
+ /* compensate for low resolution system clock by adding
+ the time/tick sequence counter */
+ if (uuid->time_seq > 0)
+ t = ui64_addn(t, uuid->time_seq, NULL);
+
/* store the 60 LSB of the time in the UUID */
t = ui64_rol(t, 16, &ov);
uuid->obj.time_hi_and_version =
|