3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/nt/atom.c
6 * PURPOSE: Atom managment
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <internal/handle.h>
16 #include <internal/pool.h>
19 #include <internal/debug.h>
23 typedef struct _RTL_ATOM_ENTRY
30 } RTL_ATOM_ENTRY, *PRTL_ATOM_ENTRY;
33 /* PROTOTYPES ****************************************************************/
35 static PRTL_ATOM_TABLE RtlpGetGlobalAtomTable(VOID);
37 static ULONG RtlpHashAtomName(ULONG TableSize, PWSTR AtomName);
38 static BOOLEAN RtlpCheckIntegerAtom(PWSTR AtomName, PUSHORT AtomValue);
40 static NTSTATUS RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable);
41 static VOID RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable);
42 static BOOLEAN RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable);
43 static VOID RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable);
45 static BOOLEAN RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable);
46 static VOID RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable);
48 static NTSTATUS RtlpQueryAtomInformation(PRTL_ATOM_TABLE AtomTable,
50 PATOM_BASIC_INFORMATION AtomInformation,
51 ULONG AtomInformationLength,
54 static NTSTATUS RtlpQueryAtomTableInformation(PRTL_ATOM_TABLE AtomTable,
56 PATOM_TABLE_INFORMATION AtomInformation,
57 ULONG AtomInformationLength,
61 /* GLOBALS *******************************************************************/
63 static PRTL_ATOM_TABLE GlobalAtomTable = NULL;
65 /* FUNCTIONS *****************************************************************/
69 NtAddAtom(IN PWSTR AtomName,
72 PRTL_ATOM_TABLE AtomTable;
74 AtomTable = RtlpGetGlobalAtomTable();
75 if (AtomTable == NULL)
76 return STATUS_ACCESS_DENIED;
78 return (RtlAddAtomToAtomTable(AtomTable,
85 NtDeleteAtom(IN RTL_ATOM Atom)
87 PRTL_ATOM_TABLE AtomTable;
89 AtomTable = RtlpGetGlobalAtomTable();
90 if (AtomTable == NULL)
91 return STATUS_ACCESS_DENIED;
93 return (RtlDeleteAtomFromAtomTable(AtomTable,
99 NtFindAtom(IN PWSTR AtomName,
102 PRTL_ATOM_TABLE AtomTable;
104 AtomTable = RtlpGetGlobalAtomTable();
105 if (AtomTable == NULL)
106 return STATUS_ACCESS_DENIED;
108 return (RtlLookupAtomInAtomTable(AtomTable,
115 NtQueryInformationAtom(RTL_ATOM Atom,
116 ATOM_INFORMATION_CLASS AtomInformationClass,
117 PVOID AtomInformation,
118 ULONG AtomInformationLength,
121 PRTL_ATOM_TABLE AtomTable;
124 AtomTable = RtlpGetGlobalAtomTable();
125 if (AtomTable == NULL)
126 return STATUS_ACCESS_DENIED;
128 switch (AtomInformationClass)
130 case AtomBasicInformation:
131 Status = RtlpQueryAtomInformation(AtomTable,
134 AtomInformationLength,
138 case AtomTableInformation:
139 Status = RtlpQueryAtomTableInformation(AtomTable,
142 AtomInformationLength,
147 Status = STATUS_INVALID_INFO_CLASS;
155 RtlCreateAtomTable(ULONG TableSize,
156 PRTL_ATOM_TABLE *AtomTable)
158 PRTL_ATOM_TABLE Table;
162 DPRINT("RtlCreateAtomTable(TableSize %lu AtomTable %p)\n",
163 TableSize, AtomTable);
165 if (*AtomTable != NULL)
167 return STATUS_SUCCESS;
170 /* allocate atom table */
171 Table = ExAllocatePool(NonPagedPool,
172 TableSize * sizeof(RTL_ATOM_ENTRY) +
173 sizeof(RTL_ATOM_TABLE));
175 return STATUS_NO_MEMORY;
177 /* initialize atom table */
178 Table->TableSize = TableSize;
179 Table->NumberOfAtoms = 0;
181 for (i = 0; i < TableSize; i++)
183 InitializeListHead(&Table->Slot[i]);
186 Status = RtlpInitAtomTableLock(Table);
187 if (!NT_SUCCESS(Status))
193 if (RtlpCreateAtomHandleTable(Table) == FALSE)
195 RtlpDestroyAtomTableLock(Table);
197 return STATUS_NO_MEMORY;
201 return STATUS_SUCCESS;
206 RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable)
209 PRTL_ATOM_ENTRY AtomEntry;
212 if (RtlpLockAtomTable(AtomTable) == FALSE)
214 return (STATUS_INVALID_PARAMETER);
217 /* delete all atoms */
218 for (i = 0; i < AtomTable->TableSize; i++)
221 Current = AtomTable->Slot[i].Flink;
222 while (Current != &AtomTable->Slot[i])
224 AtomEntry = (PRTL_ATOM_ENTRY)Current;
225 RtlFreeUnicodeString(&AtomEntry->Name);
226 RemoveEntryList(&AtomEntry->List);
227 ExFreePool(AtomEntry);
228 Current = AtomTable->Slot[i].Flink;
233 RtlpDestroyAtomHandleTable(AtomTable);
235 RtlpUnlockAtomTable(AtomTable);
237 RtlpDestroyAtomTableLock(AtomTable);
239 ExFreePool(AtomTable);
241 return STATUS_SUCCESS;
246 RtlEmptyAtomTable(IN PRTL_ATOM_TABLE AtomTable,
247 IN BOOLEAN DeletePinned)
249 PLIST_ENTRY Current, Next;
250 PRTL_ATOM_ENTRY AtomEntry;
253 DPRINT("RtlEmptyAtomTable (AtomTable %p DeletePinned %x)\n",
254 AtomTable, DeletePinned);
256 if (RtlpLockAtomTable(AtomTable) == FALSE)
258 return (STATUS_INVALID_PARAMETER);
261 /* delete all atoms */
262 for (i = 0; i < AtomTable->TableSize; i++)
264 Current = AtomTable->Slot[i].Flink;
265 while (Current != &AtomTable->Slot[i])
267 Next = Current->Flink;
268 AtomEntry = (PRTL_ATOM_ENTRY)Current;
270 if ((AtomEntry->Locked == FALSE) ||
271 ((AtomEntry->Locked == TRUE) && (DeletePinned == TRUE)))
273 RtlFreeUnicodeString(&AtomEntry->Name);
275 RtlpFreeHandle(AtomTable->HandleTable,
278 RemoveEntryList(&AtomEntry->List);
279 ExFreePool(AtomEntry);
286 AtomTable->NumberOfAtoms = 0;
288 RtlpUnlockAtomTable(AtomTable);
290 return STATUS_SUCCESS;
295 RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable,
301 PRTL_ATOM_ENTRY Entry;
306 DPRINT("RtlAddAtomToAtomTable (AtomTable %p AtomName %S Atom %p)\n",
307 AtomTable, AtomName, Atom);
309 if (RtlpCheckIntegerAtom (AtomName, &AtomValue))
312 if (AtomValue >= 0xC000)
315 Status = STATUS_INVALID_PARAMETER;
319 Status = STATUS_SUCCESS;
323 *Atom = (RTL_ATOM)AtomValue;
328 RtlpLockAtomTable(AtomTable);
331 Hash = RtlpHashAtomName(AtomTable->TableSize, AtomName);
333 /* search for existing atom */
334 Current = AtomTable->Slot[Hash].Flink;
335 while (Current != &AtomTable->Slot[Hash])
337 Entry = (PRTL_ATOM_ENTRY)Current;
339 DPRINT("Comparing %S and %S\n", Entry->Name.Buffer, AtomName);
340 if (_wcsicmp(Entry->Name.Buffer, AtomName) == 0)
344 *Atom = (RTL_ATOM)(Entry->Index + 0xC000);
345 RtlpUnlockAtomTable(AtomTable);
346 return STATUS_SUCCESS;
348 Current = Current->Flink;
351 /* insert new atom */
352 Entry = ExAllocatePool(NonPagedPool,
353 sizeof(RTL_ATOM_ENTRY));
356 RtlpUnlockAtomTable(AtomTable);
357 return STATUS_NO_MEMORY;
360 InsertTailList(&AtomTable->Slot[Hash], &Entry->List)
361 RtlCreateUnicodeString (&Entry->Name,
364 Entry->Locked = FALSE;
366 /* FIXME: use general function instead !! */
367 RtlpAllocateHandle(AtomTable->HandleTable,
371 DPRINT("AtomIndex %x\n", AtomIndex);
373 Entry->Index = AtomIndex;
374 AtomTable->NumberOfAtoms++;
377 *Atom = (RTL_ATOM)(AtomIndex + 0xC000);
379 RtlpUnlockAtomTable(AtomTable);
381 return STATUS_SUCCESS;
386 RtlDeleteAtomFromAtomTable(IN PRTL_ATOM_TABLE AtomTable,
389 PRTL_ATOM_ENTRY AtomEntry;
391 DPRINT("RtlDeleteAtomFromAtomTable (AtomTable %p Atom %x)\n",
396 return STATUS_SUCCESS;
399 RtlpLockAtomTable(AtomTable);
401 /* FIXME: use general function instead !! */
402 AtomEntry = (PRTL_ATOM_ENTRY)RtlpMapHandleToPointer(AtomTable->HandleTable,
403 (ULONG)Atom - 0xC000);
404 if (AtomEntry == NULL)
406 RtlpUnlockAtomTable(AtomTable);
407 return STATUS_INVALID_HANDLE;
410 DPRINT("AtomEntry %x\n", AtomEntry);
411 DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
413 AtomEntry->RefCount--;
415 if (AtomEntry->RefCount == 0)
417 if (AtomEntry->Locked == TRUE)
419 DPRINT("Atom %wZ is locked!\n", &AtomEntry->Name);
421 RtlpUnlockAtomTable(AtomTable);
422 return STATUS_WAS_LOCKED;
425 DPRINT("Removing atom: %wZ\n", &AtomEntry->Name);
427 RtlFreeUnicodeString(&AtomEntry->Name);
428 RemoveEntryList(&AtomEntry->List);
429 ExFreePool(AtomEntry);
430 RtlpFreeHandle(AtomTable->HandleTable,
431 (ULONG)Atom - 0xC000);
432 AtomTable->NumberOfAtoms++;
435 RtlpUnlockAtomTable(AtomTable);
437 return STATUS_SUCCESS;
442 RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
448 PRTL_ATOM_ENTRY Entry;
452 DPRINT("RtlLookupAtomInAtomTable (AtomTable %p AtomName %S Atom %p)\n",
453 AtomTable, AtomName, Atom);
455 if (RtlpCheckIntegerAtom (AtomName, &AtomValue))
458 if (AtomValue >= 0xC000)
461 Status = STATUS_INVALID_PARAMETER;
465 Status = STATUS_SUCCESS;
469 *Atom = (RTL_ATOM)AtomValue;
474 RtlpLockAtomTable(AtomTable);
477 Hash = RtlpHashAtomName(AtomTable->TableSize, AtomName);
479 /* search for existing atom */
480 Current = AtomTable->Slot[Hash].Flink;
481 while (Current != &AtomTable->Slot[Hash])
483 Entry = (PRTL_ATOM_ENTRY)Current;
485 DPRINT("Comparing %S and %S\n", Entry->Name.Buffer, AtomName);
486 if (_wcsicmp(Entry->Name.Buffer, AtomName) == 0)
489 *Atom = (RTL_ATOM)(Entry->Index + 0xC000);
490 RtlpUnlockAtomTable(AtomTable);
491 return STATUS_SUCCESS;
494 Current = Current->Flink;
497 return STATUS_OBJECT_NAME_NOT_FOUND;
502 RtlPinAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
505 PRTL_ATOM_ENTRY AtomEntry;
507 DPRINT("RtlPinAtomInAtomTable (AtomTable %p Atom %x)\n",
512 return STATUS_SUCCESS;
515 RtlpLockAtomTable(AtomTable);
517 /* FIXME: use general function instead !! */
518 AtomEntry = (PRTL_ATOM_ENTRY)RtlpMapHandleToPointer(AtomTable->HandleTable,
519 (ULONG)Atom - 0xC000);
520 if (AtomEntry == NULL)
522 RtlpUnlockAtomTable(AtomTable);
523 return STATUS_INVALID_HANDLE;
526 DPRINT("AtomEntry %x\n", AtomEntry);
527 DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
529 AtomEntry->Locked = TRUE;
531 RtlpUnlockAtomTable(AtomTable);
533 return STATUS_SUCCESS;
538 RtlQueryAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
540 IN OUT PULONG RefCount,
541 IN OUT PULONG PinCount,
542 IN OUT PWSTR AtomName,
543 IN OUT PULONG NameLength)
546 PRTL_ATOM_ENTRY AtomEntry;
550 if (RefCount != NULL)
555 if (PinCount != NULL)
560 if ((AtomName != NULL) && (NameLength != NULL) && (NameLength > 0))
562 Length = swprintf(AtomName, L"#%lu", (ULONG)Atom);
563 *NameLength = Length * sizeof(WCHAR);
566 return STATUS_SUCCESS;
569 RtlpLockAtomTable(AtomTable);
571 /* FIXME: use general function instead !! */
572 AtomEntry = (PRTL_ATOM_ENTRY)RtlpMapHandleToPointer(AtomTable->HandleTable,
573 (ULONG)Atom - 0xC000);
574 if (AtomEntry == NULL)
576 RtlpUnlockAtomTable(AtomTable);
577 return STATUS_INVALID_HANDLE;
580 DPRINT("AtomEntry %x\n", AtomEntry);
581 DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
583 if (RefCount != NULL)
585 *RefCount = AtomEntry->RefCount;
588 if (PinCount != NULL)
590 *PinCount = (ULONG)AtomEntry->Locked;
593 if ((AtomName != NULL) && (NameLength != NULL))
595 if (*NameLength < AtomEntry->Name.Length)
597 *NameLength = AtomEntry->Name.Length;
598 RtlpUnlockAtomTable(AtomTable);
599 return STATUS_BUFFER_TOO_SMALL;
602 Length = swprintf(AtomName, L"%s", AtomEntry->Name.Buffer);
603 *NameLength = Length * sizeof(WCHAR);
606 RtlpUnlockAtomTable(AtomTable);
608 return STATUS_SUCCESS;
612 /* INTERNAL FUNCTIONS ********************************************************/
614 static PRTL_ATOM_TABLE
615 RtlpGetGlobalAtomTable(VOID)
619 if (GlobalAtomTable != NULL)
620 return GlobalAtomTable;
622 Status = RtlCreateAtomTable(37, &GlobalAtomTable);
623 if (!NT_SUCCESS(Status))
626 return GlobalAtomTable;
631 RtlpHashAtomName(ULONG TableSize,
637 DPRINT("RtlpHashAtomName(TableSize %ld AtomName '%S')\n",
638 TableSize, AtomName);
640 /* convert the string to an internal representation */
644 q += (ULONG)towupper(*p);
648 DPRINT("q %lu Hash %lu\n", q, q % TableSize);
650 return (q % TableSize);
655 RtlpCheckIntegerAtom(PWSTR AtomName,
658 UNICODE_STRING AtomString;
663 DPRINT("RtlpCheckIntegerAtom(AtomName '%S' AtomValue %p)\n",
664 AtomName, AtomValue);
666 if (!((ULONG)AtomName & 0xFFFF0000))
668 LoValue = (USHORT)((ULONG)AtomName & 0xFFFF);
670 if (LoValue >= 0xC000)
676 if (AtomValue != NULL)
677 *AtomValue = LoValue;
682 if (*AtomName != L'#')
689 if ((*p < L'0') || (*p > L'9'))
696 RtlInitUnicodeString(&AtomString,
699 DPRINT1("AtomString: %wZ\n", &AtomString);
701 RtlUnicodeStringToInteger(&AtomString,10, &LongValue);
703 DPRINT1("LongValue: %lu\n", LongValue);
705 *AtomValue = (USHORT)(LongValue & 0x0000FFFF);
714 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
716 AtomTable->Lock = ExAllocatePool(NonPagedPool,
718 if (AtomTable->Lock == NULL)
719 return STATUS_NO_MEMORY;
721 ExInitializeFastMutex((PFAST_MUTEX)AtomTable->Lock);
723 return STATUS_SUCCESS;
728 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
731 ExFreePool(AtomTable->Lock);
736 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
738 // ExAcquireFastMutex((PFAST_MUTEX)AtomTable->Lock);
743 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
745 // ExReleaseFastMutex((PFAST_MUTEX)AtomTable->Lock);
750 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
752 AtomTable->Lock = RtlAllocateHeap(RtlGetProcessHeap(),
754 sizeof(CRITICAL_SECTION));
755 if (AtomTable->Lock == NULL)
756 return STATUS_NO_MEMORY;
758 RtlInitializeCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
760 return STATUS_SUCCESS;
765 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
769 RtlDeleteCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
770 RtlFreeHeap(RtlGetProcessHeap(),
773 AtomTable->Lock = NULL;
779 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
781 RtlEnterCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
787 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
789 RtlLeaveCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
793 /* handle functions */
796 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
798 AtomTable->HandleTable = ExAllocatePool(NonPagedPool,
799 sizeof(RTL_HANDLE_TABLE));
800 if (AtomTable->HandleTable == NULL)
803 RtlpInitializeHandleTable(0xCFFF,
804 (PRTL_HANDLE_TABLE)AtomTable->HandleTable);
811 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
813 if (AtomTable->HandleTable)
815 RtlpDestroyHandleTable((PRTL_HANDLE_TABLE)AtomTable->HandleTable);
816 ExFreePool(AtomTable->HandleTable);
817 AtomTable->HandleTable = NULL;
823 RtlpQueryAtomInformation(PRTL_ATOM_TABLE AtomTable,
825 PATOM_BASIC_INFORMATION AtomInformation,
826 ULONG AtomInformationLength,
834 NameLength = AtomInformationLength - sizeof(ATOM_BASIC_INFORMATION) + sizeof(WCHAR);
835 Status = RtlQueryAtomInAtomTable(AtomTable,
839 AtomInformation->Name,
841 if (!NT_SUCCESS(Status))
846 DPRINT1("NameLength: %lu\n", NameLength);
848 if (ReturnLength != NULL)
850 *ReturnLength = NameLength + sizeof(ATOM_BASIC_INFORMATION);
853 if (NameLength + sizeof(ATOM_BASIC_INFORMATION) > AtomInformationLength)
855 return STATUS_BUFFER_TOO_SMALL;
858 AtomInformation->UsageCount = (USHORT)UsageCount;
859 AtomInformation->Flags = (USHORT)Flags;
860 AtomInformation->NameLength = (USHORT)NameLength;
862 return STATUS_SUCCESS;
867 RtlpQueryAtomTableInformation(PRTL_ATOM_TABLE AtomTable,
869 PATOM_TABLE_INFORMATION AtomInformation,
870 ULONG AtomInformationLength,
873 PLIST_ENTRY Current, Next;
874 PRTL_ATOM_ENTRY AtomEntry;
878 Length = sizeof(ATOM_TABLE_INFORMATION);
879 if (AtomTable->NumberOfAtoms > 1)
881 Length += ((AtomTable->NumberOfAtoms - 1)* sizeof(RTL_ATOM));
884 DPRINT1("RequiredLength: %lu\n", Length);
886 if (ReturnLength != NULL)
888 *ReturnLength = Length;
891 if (Length > AtomInformationLength)
893 return STATUS_BUFFER_TOO_SMALL;
896 AtomInformation->NumberOfAtoms = AtomTable->NumberOfAtoms;
899 for (i = 0; i < AtomTable->TableSize; i++)
901 Current = AtomTable->Slot[i].Flink;
902 while (Current != &AtomTable->Slot[i])
904 Next = Current->Flink;
905 AtomEntry = (PRTL_ATOM_ENTRY)Current;
907 AtomInformation->Atoms[j] = AtomEntry->Index + 0xC000;
914 return STATUS_SUCCESS;