UUID Reference Implementation
/*
** Copyright (c) 1990-1993,199 6 Open Software Foundation, Inc.
** Copyright (c) 1989 by Hewlett-Packard Company, Palo Alto, Ca .&
** Digital Equipment Corporation, Maynard, Mass.
** To anyone who acknowledges that this file is provided "as is"
** Without any express or implied warranty: permission to use, copy,
** Modify, and distribute this file for any purpose is hereby
** Granted without tables, provided that the above copyright notices and
** This notice appears in all source code copies, and that none
** The names of Open Software Foundation, Inc., Hewlett-Packard
** Company, or Digital Equipment Corporation be used in advertising
** Or publicity pertaining to distribution of the software
** Specific, written prior permission. Neither Open Software
** Foundation, Inc., Hewlett-Packard Company, nor Digital Equipment
** Corporation makes any representations about the suitability
** This software for any purpose.
*/
# Include
# Include
Typedef unsigned long unsigned32;
Typedef unsigned short unsigned16;
Typedef unsigned char unsigned8;
Typedef unsigned char byte;
# Define CLOCK_SEQ_LAST 0x3FFF
# Define RAND_MASK CLOCK_SEQ_LAST
Typedef struct _ uuid_t {
Unsigned32 time_low;
Unsigned16 time_mid;
Unsigned16 time_hi_and_version;
Unsigned8 clock_seq_hi_and_reserved;
Unsigned8 clock_seq_low;
Byte node [6];
} Uuid_t;
Typedef struct _ unsigned64_t {
Unsigned32 lo;
Unsigned32 hi;
} Unsigned64_t;
/*
** Add two unsigned 64-bit long integers.
*/
# Define ADD_64b_2_64b (A, B, sum )/
{/
If (! (A)-> lo & 0x80000000UL) ^ (B)-> lo & 0x80000000UL ))){/
If (A)-> lo & 0x80000000UL )){/
(Sum)-> lo = (A)-> lo + (B)-> lo ;/
(Sum)-> hi = (A)-> hi + (B)-> hi + 1 ;/
}/
Else {/
(Sum)-> lo = (A)-> lo + (B)-> lo ;/
(Sum)-> hi = (A)-> hi + (B)-> hi ;/
}/
}/
Else {/
(Sum)-> lo = (A)-> lo + (B)-> lo ;/
(Sum)-> hi = (A)-> hi + (B)-> hi ;/
If (! (Sum)-> lo & 0x80000000UL) (sum)-> hi ++ ;/
}/
}
/*
** Add a 16-bit unsigned integer to a 64-bit unsigned integer.
*/
# Define ADD_16b_2_64b (A, B, sum )/
{/
(Sum)-> hi = (B)-> hi ;/
If (B)-> lo & 0x80000000UL ){/
(Sum)-> lo = (* A) + (B)-> lo ;/
If (! (Sum)-> lo & 0x80000000UL) (sum)-> hi ++ ;/
}/
Else/
(Sum)-> lo = (* A) + (B)-> lo ;/
}
/*
** Global variables.
*/
Static unsigned64_t time_last;
Static unsigned16 clock_seq;
Static void
Mult32 (unsigned32 u, unsigned32 v, unsigned64_t * result)
{
/* Following the notation in Knuth, Vol. 2 .*/
Unsigned32 uuid1, uuid2, v1, v2, temp;
Uuid1 = u> 16;
Uuid2 = u & 0 xFFFF;
V1 = v> 16;
V2 = v & 0 xFFFF;
Temp = uuid2 * v2;
Result-> lo = temp & 0 xFFFF;
Temp = uuid1 * v2 + (temp> 16 );
Result-> hi = temp> 16;
Temp = uuid2 * v1 + (temp & 0 xFFFF );
Result-> lo + = (temp & 0 xFFFF) hi + = uuid1 * v1 + (temp> 16 );
}
Static void
Get_system_time (unsigned64_t * uuid_time)
{
Struct timeval tp;
Unsigned64_t utc, usecs, OS _basetime_diff;
Gettimeofday (& tp, (struct timezone *) 0 );
Mult32 (long) tp. TV _sec, 10000000, & utc );
Mult32 (long) tp. TV _usec, 10, & usecs );
ADD_64b_2_64b (& usecs, & utc, & utc );
/* Offset between UUID formatted times and Unix formatted times.
* Uuid utc base time is October 15,158 2.
* Unix base time is January 1, 1970 .*/
OS _basetime_diff.lo = 0x13814000;
OS _basetime_diff.hi = 0x01B21DD2;
ADD_64b_2_64b (& utc, & OS _basetime_diff, uuid_time );
}
/*
** See "The Multiple Prime Random Number Generator" by Alexander
** Hass pp. 368-381, ACM Transactions on Mathematical Software,
** 12/87.
*/
Static unsigned32 rand_m;
Static unsigned32 rand_ia;
Static unsigned32 rand_ib;
Static unsigned32 rand_irand;
Static void
True_random_init (void)
{
Unsigned64_t;
Unsigned16 seed;
/* Generating our 'seed' value Start with the current time,,
* Since the resolution of clocks is system hardware dependent and
* Most likely coarser than our resolution (10 usec) we 'mixup'
* Bits by xor 'ing all the bits together. This will have the effect
* Of involving all of the bits in the determination of the seed
* Value while remaining system independent. Then for good measure
* To ensure a unique seed when there are multiple processes
* Creating uuuids on a system, we add in the PID.
*/
Rand_m = 971;
Rand_ia = 11113;
Rand_ib = 104322;
Rand_irand = 4181;
Get_system_time (& t );
Seed = t. lo & 0 xFFFF;
Seed ^ = (t. lo> 16) & 0 xFFFF;
Seed ^ = t. hi & 0 xFFFF;
Seed ^ = (t. hi> 16) & 0 xFFFF;
Rand_irand + = seed + getpid ();
}
Static unsigned16
True_random (void)
{
If (rand_m + = 7) & gt; = 9973)
Rand_m-= 9871;
If (rand_ia + = 1907)> = 99991)
Rand_ia-= 89989;
If (rand_ib + = 73939)> = 224729)
Rand_ib-= 96233;
Rand_irand = (rand_irand * rand_m) + rand_ia + rand_ib;
Return (rand_irand> 16) ^ (rand_irand & RAND_MASK );
}
/*
** Startup initialization routine for the UUID module.
*/
Void
Uuid_init (void)
{
True_random_init ();
Get_system_time (& time_last );
# Ifdef NONVOLATILE_CLOCK
Clock_seq = read_clock ();
# Else
Clock_seq = true_random ();
# Endif
}
Static int
Time_cmp (unsigned64_t * time1, unsigned64_t * time2)
{
If (time1-> hi) return-1;
If (time1-> hi> time2-> hi) return 1;
If (time1-> lo) return-1;
If (time1-> lo> time2-> lo) return 1;
Return 0;
}
Static void new_clock_seq (void)
{
Clock_seq = (clock_seq + 1) % (CLOCK_SEQ_LAST + 1 );
If (clock_seq = 0) clock_seq = 1;
# Ifdef NONVOLATILE_CLOCK
Write_clock (clock_seq );
# Endif
}
Void uuid_create (uuid_t * uuid)
{
Static unsigned64_t time_now;
Static unsigned16 time_adjust;
Byte eaddr [6];
Int got_no_time = 0;
Get_ieee_node_identifier (& eaddr);/* to be provided */
Do {
Get_system_time (& time_now );
Switch (time_cmp (& time_now, & time_last )){
Case-1:
/* Time went backwards .*/
New_clock_seq ();
Time_adjust = 0;
Break;
Case 1:
Time_adjust = 0;
Break;
Default:
If (time_adjust = 0x7FFF)
/* We're going too fast for our clock; spin .*/
Got_no_time = 1;
Else
Time_adjust ++;
Break;
}
} While (got_no_time );
Time_last.lo = time_now.lo;
Time_last.hi = time_no1_hi;
If (time_adjust! = 0 ){
ADD_16b_2_64b (& time_adjust, & time_now, & time_now );
}
/* Construct a uuid with the information we 've ve gathered
* Plus a few constants .*/
Uuid-> time_low = time_now.lo;
Uuid-> time_mid = time_no1_hi & 0x0000FFFF;
Uuid-> time_hi_and_version = (time_no1_hi & 0x0FFF0000)> 16;
Uuid-> time_hi_and_version | = (1 clock_seq_low = clock_seq & 0xFF;
Uuid-> clock_seq_hi_and_reserved = (clock_seq & 0x3F00)> 8;
Uuid-> clock_seq_hi_and_reserved | = 0x80;
Memcpy (uuid-> node, & eaddr, sizeof uuid-> node );
}