summaryrefslogtreecommitdiffstats
path: root/libuuid/src/gen_uuid.c
diff options
context:
space:
mode:
Diffstat (limited to 'libuuid/src/gen_uuid.c')
-rw-r--r--libuuid/src/gen_uuid.c120
1 files changed, 89 insertions, 31 deletions
diff --git a/libuuid/src/gen_uuid.c b/libuuid/src/gen_uuid.c
index 826cd22..59e8c23 100644
--- a/libuuid/src/gen_uuid.c
+++ b/libuuid/src/gen_uuid.c
@@ -207,6 +207,28 @@ static int get_node_id(unsigned char *node_id)
return 0;
}
+enum { STATE_FD_ERROR = -1, STATE_FD_INIT = -2 };
+
+static int state_fd_init(const char *clock_file, FILE **fp)
+{
+ mode_t save_umask;
+ int state_fd;
+ FILE *state_f;
+
+ save_umask = umask(0);
+ state_fd = open(clock_file, O_RDWR|O_CREAT|O_CLOEXEC, 0660);
+ (void) umask(save_umask);
+ if (state_fd != -1) {
+ state_f = fdopen(state_fd, "r+" UL_CLOEXECSTR);
+ if (!state_f) {
+ close(state_fd);
+ state_fd = STATE_FD_ERROR;
+ } else
+ *fp = state_f;
+ }
+ return state_fd;
+}
+
/* Assume that the gettimeofday() has microsecond granularity */
#define MAX_ADJUSTMENT 10
/* Reserve a clock_seq value for the 'continuous clock' implementation */
@@ -223,32 +245,16 @@ static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
{
THREAD_LOCAL int adjustment = 0;
THREAD_LOCAL struct timeval last = {0, 0};
- THREAD_LOCAL int state_fd = -2;
+ THREAD_LOCAL int state_fd = STATE_FD_INIT;
THREAD_LOCAL FILE *state_f;
THREAD_LOCAL uint16_t clock_seq;
struct timeval tv;
uint64_t clock_reg;
- mode_t save_umask;
int ret = 0;
- if (state_fd == -1)
- ret = -1;
+ if (state_fd == STATE_FD_INIT)
+ state_fd = state_fd_init(LIBUUID_CLOCK_FILE, &state_f);
- if (state_fd == -2) {
- save_umask = umask(0);
- state_fd = open(LIBUUID_CLOCK_FILE, O_RDWR|O_CREAT|O_CLOEXEC, 0660);
- (void) umask(save_umask);
- if (state_fd != -1) {
- state_f = fdopen(state_fd, "r+" UL_CLOEXECSTR);
- if (!state_f) {
- close(state_fd);
- state_fd = -1;
- ret = -1;
- }
- }
- else
- ret = -1;
- }
if (state_fd >= 0) {
rewind(state_f);
while (flock(state_fd, LOCK_EX) < 0) {
@@ -256,11 +262,13 @@ static int get_clock(uint32_t *clock_high, uint32_t *clock_low,
continue;
fclose(state_f);
close(state_fd);
- state_fd = -1;
+ state_fd = STATE_FD_ERROR;
ret = -1;
break;
}
- }
+ } else
+ ret = -1;
+
if (state_fd >= 0) {
unsigned int cl;
unsigned long tv1, tv2;
@@ -355,44 +363,94 @@ static uint64_t get_clock_counter(void)
/*
* Get continuous clock value.
*
- * Return -1 if there is no further clock counter available,
+ * Return -1 if there is no valid clock counter available,
* otherwise return 0.
*
* This implementation doesn't deliver clock counters based on
* the current time because last_clock_reg is only incremented
* by the number of requested UUIDs.
* max_clock_offset is used to limit the offset of last_clock_reg.
+ * used/reserved UUIDs are written to LIBUUID_CLOCK_CONT_FILE.
*/
static int get_clock_cont(uint32_t *clock_high,
uint32_t *clock_low,
int num,
uint32_t max_clock_offset)
{
- /* 100ns based time offset according to RFC 4122. 4.1.4. */
+ /* all 64bit clock_reg values in this function represent '100ns ticks'
+ * due to the combination of tv_usec + MAX_ADJUSTMENT */
+
+ /* time offset according to RFC 4122. 4.1.4. */
const uint64_t reg_offset = (((uint64_t) 0x01B21DD2) << 32) + 0x13814000;
static uint64_t last_clock_reg = 0;
- uint64_t clock_reg;
+ static uint64_t saved_clock_reg = 0;
+ static int state_fd = STATE_FD_INIT;
+ static FILE *state_f = NULL;
+ uint64_t clock_reg, next_clock_reg;
- if (last_clock_reg == 0)
- last_clock_reg = get_clock_counter();
+ if (state_fd == STATE_FD_ERROR)
+ return -1;
clock_reg = get_clock_counter();
+
+ if (state_fd == STATE_FD_INIT) {
+ struct stat st;
+
+ state_fd = state_fd_init(LIBUUID_CLOCK_CONT_FILE, &state_f);
+ if (state_fd == STATE_FD_ERROR)
+ return -1;
+
+ if (fstat(state_fd, &st))
+ goto error;
+
+ if (st.st_size) {
+ rewind(state_f);
+ if (fscanf(state_f, "cont: %"SCNu64"\n", &last_clock_reg) != 1)
+ goto error;
+ } else
+ last_clock_reg = clock_reg;
+
+ saved_clock_reg = last_clock_reg;
+ }
+
if (max_clock_offset) {
- uint64_t clock_offset = max_clock_offset * 10000000ULL;
- if (last_clock_reg < (clock_reg - clock_offset))
- last_clock_reg = clock_reg - clock_offset;
+ uint64_t co = 10000000ULL * (uint64_t)max_clock_offset; // clock_offset in [100ns]
+
+ if ((last_clock_reg + co) < clock_reg)
+ last_clock_reg = clock_reg - co;
}
clock_reg += MAX_ADJUSTMENT;
- if ((last_clock_reg + num) >= clock_reg)
+ next_clock_reg = last_clock_reg + (uint64_t)num;
+ if (next_clock_reg >= clock_reg)
return -1;
+ if (next_clock_reg >= saved_clock_reg) {
+ uint64_t cl = next_clock_reg + 100000000ULL; // 10s interval in [100ns]
+ int l;
+
+ rewind(state_f);
+ l = fprintf(state_f, "cont: %020"PRIu64" \n", cl);
+ if (l < 30 || fflush(state_f))
+ goto error;
+ saved_clock_reg = cl;
+ }
+
*clock_high = (last_clock_reg + reg_offset) >> 32;
*clock_low = last_clock_reg + reg_offset;
- last_clock_reg += num;
+ last_clock_reg = next_clock_reg;
return 0;
+
+error:
+ if (state_fd >= 0)
+ close(state_fd);
+ if (state_f)
+ fclose(state_f);
+ state_fd = STATE_FD_ERROR;
+ state_f = NULL;
+ return -1;
}
#if defined(HAVE_UUIDD) && defined(HAVE_SYS_UN_H)