2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ex/uuid.c
5 * PURPOSE: UUID generator
7 * PROGRAMMERS: Eric Kohl
11 /* INCLUDES *****************************************************************/
17 #define SEED_BUFFER_SIZE 6
19 /* Number of 100ns ticks per clock tick. To be safe, assume that the clock
20 resolution is at least 1000 * 100 * (1/1000000) = 1/10 of a second */
21 #define TICKS_PER_CLOCK_TICK 1000
22 #define SECSPERDAY 86400
23 #define TICKSPERSEC 10000000
25 /* UUID system time starts at October 15, 1582 */
26 #define SECS_15_OCT_1582_TO_1601 ((17 + 30 + 31 + 365 * 18 + 5) * SECSPERDAY)
27 #define TICKS_15_OCT_1582_TO_1601 ((ULONGLONG)SECS_15_OCT_1582_TO_1601 * TICKSPERSEC)
29 #if defined (ALLOC_PRAGMA)
30 #pragma alloc_text(INIT, ExpInitUuids)
34 /* GLOBALS ****************************************************************/
36 static FAST_MUTEX UuidMutex
;
37 static ULARGE_INTEGER UuidLastTime
;
38 static ULONG UuidSequence
;
39 static BOOLEAN UuidSequenceInitialized
= FALSE
;
40 static BOOLEAN UuidSequenceChanged
= FALSE
;
41 static UCHAR UuidSeed
[SEED_BUFFER_SIZE
];
42 static ULONG UuidCount
;
43 static LARGE_INTEGER LuidIncrement
;
44 static LARGE_INTEGER LuidValue
;
46 /* FUNCTIONS ****************************************************************/
53 ExInitializeFastMutex(&UuidMutex
);
55 KeQuerySystemTime((PLARGE_INTEGER
)&UuidLastTime
);
56 UuidLastTime
.QuadPart
+= TICKS_15_OCT_1582_TO_1601
;
58 UuidCount
= TICKS_PER_CLOCK_TICK
;
59 RtlZeroMemory(UuidSeed
, SEED_BUFFER_SIZE
);
63 #define VALUE_BUFFER_SIZE 256
66 ExpLoadUuidSequence(PULONG Sequence
)
68 UCHAR ValueBuffer
[VALUE_BUFFER_SIZE
];
69 PKEY_VALUE_PARTIAL_INFORMATION ValueInfo
;
70 OBJECT_ATTRIBUTES ObjectAttributes
;
76 RtlInitUnicodeString(&Name
,
77 L
"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
78 InitializeObjectAttributes(&ObjectAttributes
,
83 Status
= ZwOpenKey(&KeyHandle
,
86 if (!NT_SUCCESS(Status
))
88 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status
);
92 RtlInitUnicodeString(&Name
, L
"UuidSequenceNumber");
94 ValueInfo
= (PKEY_VALUE_PARTIAL_INFORMATION
)ValueBuffer
;
95 Status
= ZwQueryValueKey(KeyHandle
,
97 KeyValuePartialInformation
,
102 if (!NT_SUCCESS(Status
))
104 DPRINT("ZwQueryValueKey() failed (Status %lx)\n", Status
);
108 *Sequence
= *((PULONG
)ValueInfo
->Data
);
110 DPRINT("Loaded sequence %lx\n", *Sequence
);
112 return STATUS_SUCCESS
;
114 #undef VALUE_BUFFER_SIZE
118 ExpSaveUuidSequence(PULONG Sequence
)
120 OBJECT_ATTRIBUTES ObjectAttributes
;
125 RtlInitUnicodeString(&Name
,
126 L
"\\Registry\\Machine\\Software\\Microsoft\\Rpc");
127 InitializeObjectAttributes(&ObjectAttributes
,
129 OBJ_CASE_INSENSITIVE
,
132 Status
= ZwOpenKey(&KeyHandle
,
135 if (!NT_SUCCESS(Status
))
137 DPRINT("ZwOpenKey() failed (Status %lx)\n", Status
);
141 RtlInitUnicodeString(&Name
, L
"UuidSequenceNumber");
142 Status
= ZwSetValueKey(KeyHandle
,
149 if (!NT_SUCCESS(Status
))
151 DPRINT("ZwSetValueKey() failed (Status %lx)\n", Status
);
159 ExpGetRandomUuidSequence(PULONG Sequence
)
161 LARGE_INTEGER Counter
;
162 LARGE_INTEGER Frequency
;
165 Counter
= KeQueryPerformanceCounter(&Frequency
);
166 Value
= Counter
.u
.LowPart
^ Counter
.u
.HighPart
;
168 *Sequence
= *Sequence
^ Value
;
170 DPRINT("Sequence %lx\n", *Sequence
);
175 ExpCreateUuids(PULARGE_INTEGER Time
,
180 * Generate time element of the UUID. Account for going faster
181 * than our clock as well as the clock going backwards.
185 KeQuerySystemTime((PLARGE_INTEGER
)Time
);
186 Time
->QuadPart
+= TICKS_15_OCT_1582_TO_1601
;
188 if (Time
->QuadPart
> UuidLastTime
.QuadPart
)
194 if (Time
->QuadPart
< UuidLastTime
.QuadPart
)
197 UuidSequenceChanged
= TRUE
;
202 if (UuidCount
< TICKS_PER_CLOCK_TICK
)
209 UuidLastTime
.QuadPart
= Time
->QuadPart
;
210 Time
->QuadPart
+= UuidCount
;
212 *Range
= 10000; /* What does this mean? Ticks per millisecond?*/
214 return STATUS_SUCCESS
;
222 LUID DummyLuidValue
= SYSTEM_LUID
;
224 LuidValue
.u
.HighPart
= DummyLuidValue
.HighPart
;
225 LuidValue
.u
.LowPart
= DummyLuidValue
.LowPart
;
226 LuidIncrement
.QuadPart
= 1;
232 ExpAllocateLocallyUniqueId(OUT LUID
*LocallyUniqueId
)
234 LARGE_INTEGER NewLuid
, PrevLuid
;
236 /* atomically increment the luid */
239 PrevLuid
= LuidValue
;
240 NewLuid
= RtlLargeIntegerAdd(PrevLuid
,
242 } while(ExInterlockedCompareExchange64(&LuidValue
.QuadPart
,
245 NULL
) != PrevLuid
.QuadPart
);
247 LocallyUniqueId
->LowPart
= NewLuid
.u
.LowPart
;
248 LocallyUniqueId
->HighPart
= NewLuid
.u
.HighPart
;
250 return STATUS_SUCCESS
;
258 NtAllocateLocallyUniqueId(OUT LUID
*LocallyUniqueId
)
261 KPROCESSOR_MODE PreviousMode
;
266 PreviousMode
= ExGetPreviousMode();
268 if(PreviousMode
!= KernelMode
)
272 ProbeForWrite(LocallyUniqueId
,
276 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
278 _SEH2_YIELD(return _SEH2_GetExceptionCode());
283 Status
= ExpAllocateLocallyUniqueId(&NewLuid
);
287 *LocallyUniqueId
= NewLuid
;
289 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
291 Status
= _SEH2_GetExceptionCode();
303 ExUuidCreate(OUT UUID
*Uuid
)
314 NtAllocateUuids(OUT PULARGE_INTEGER Time
,
319 ULARGE_INTEGER IntTime
;
325 ExAcquireFastMutex(&UuidMutex
);
327 if (!UuidSequenceInitialized
)
329 Status
= ExpLoadUuidSequence(&UuidSequence
);
330 if (NT_SUCCESS(Status
))
336 ExpGetRandomUuidSequence(&UuidSequence
);
339 UuidSequenceInitialized
= TRUE
;
340 UuidSequenceChanged
= TRUE
;
343 Status
= ExpCreateUuids(&IntTime
,
346 if (!NT_SUCCESS(Status
))
348 ExReleaseFastMutex(&UuidMutex
);
352 if (UuidSequenceChanged
)
354 Status
= ExpSaveUuidSequence(&UuidSequence
);
355 if (NT_SUCCESS(Status
))
356 UuidSequenceChanged
= FALSE
;
359 ExReleaseFastMutex(&UuidMutex
);
361 Time
->QuadPart
= IntTime
.QuadPart
;
363 *Sequence
= UuidSequence
;
369 return STATUS_SUCCESS
;
378 NtSetUuidSeed(IN PUCHAR Seed
)
382 RtlCopyMemory(UuidSeed
,
385 return STATUS_SUCCESS
;