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 *****************************************************************/
72 NtAddAtom(IN PWSTR AtomName,
75 PRTL_ATOM_TABLE AtomTable;
77 AtomTable = RtlpGetGlobalAtomTable();
78 if (AtomTable == NULL)
79 return STATUS_ACCESS_DENIED;
81 return (RtlAddAtomToAtomTable(AtomTable,
91 NtDeleteAtom(IN RTL_ATOM Atom)
93 PRTL_ATOM_TABLE AtomTable;
95 AtomTable = RtlpGetGlobalAtomTable();
96 if (AtomTable == NULL)
97 return STATUS_ACCESS_DENIED;
99 return (RtlDeleteAtomFromAtomTable(AtomTable,
108 NtFindAtom(IN PWSTR AtomName,
111 PRTL_ATOM_TABLE AtomTable;
113 AtomTable = RtlpGetGlobalAtomTable();
114 if (AtomTable == NULL)
115 return STATUS_ACCESS_DENIED;
117 return (RtlLookupAtomInAtomTable(AtomTable,
127 NtQueryInformationAtom(RTL_ATOM Atom,
128 ATOM_INFORMATION_CLASS AtomInformationClass,
129 PVOID AtomInformation,
130 ULONG AtomInformationLength,
133 PRTL_ATOM_TABLE AtomTable;
136 AtomTable = RtlpGetGlobalAtomTable();
137 if (AtomTable == NULL)
138 return STATUS_ACCESS_DENIED;
140 switch (AtomInformationClass)
142 case AtomBasicInformation:
143 Status = RtlpQueryAtomInformation(AtomTable,
146 AtomInformationLength,
150 case AtomTableInformation:
151 Status = RtlpQueryAtomTableInformation(AtomTable,
154 AtomInformationLength,
159 Status = STATUS_INVALID_INFO_CLASS;
170 RtlCreateAtomTable(ULONG TableSize,
171 PRTL_ATOM_TABLE *AtomTable)
173 PRTL_ATOM_TABLE Table;
177 DPRINT("RtlCreateAtomTable(TableSize %lu AtomTable %p)\n",
178 TableSize, AtomTable);
180 if (*AtomTable != NULL)
182 return STATUS_SUCCESS;
185 /* allocate atom table */
186 Table = ExAllocatePool(NonPagedPool,
187 TableSize * sizeof(RTL_ATOM_ENTRY) +
188 sizeof(RTL_ATOM_TABLE));
190 return STATUS_NO_MEMORY;
192 /* initialize atom table */
193 Table->TableSize = TableSize;
194 Table->NumberOfAtoms = 0;
196 for (i = 0; i < TableSize; i++)
198 InitializeListHead(&Table->Slot[i]);
201 Status = RtlpInitAtomTableLock(Table);
202 if (!NT_SUCCESS(Status))
208 if (RtlpCreateAtomHandleTable(Table) == FALSE)
210 RtlpDestroyAtomTableLock(Table);
212 return STATUS_NO_MEMORY;
216 return STATUS_SUCCESS;
224 RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable)
227 PRTL_ATOM_ENTRY AtomEntry;
230 if (RtlpLockAtomTable(AtomTable) == FALSE)
232 return (STATUS_INVALID_PARAMETER);
235 /* delete all atoms */
236 for (i = 0; i < AtomTable->TableSize; i++)
239 Current = AtomTable->Slot[i].Flink;
240 while (Current != &AtomTable->Slot[i])
242 AtomEntry = (PRTL_ATOM_ENTRY)Current;
243 RtlFreeUnicodeString(&AtomEntry->Name);
244 RemoveEntryList(&AtomEntry->List);
245 ExFreePool(AtomEntry);
246 Current = AtomTable->Slot[i].Flink;
251 RtlpDestroyAtomHandleTable(AtomTable);
253 RtlpUnlockAtomTable(AtomTable);
255 RtlpDestroyAtomTableLock(AtomTable);
257 ExFreePool(AtomTable);
259 return STATUS_SUCCESS;
267 RtlEmptyAtomTable(IN PRTL_ATOM_TABLE AtomTable,
268 IN BOOLEAN DeletePinned)
270 PLIST_ENTRY Current, Next;
271 PRTL_ATOM_ENTRY AtomEntry;
274 DPRINT("RtlEmptyAtomTable (AtomTable %p DeletePinned %x)\n",
275 AtomTable, DeletePinned);
277 if (RtlpLockAtomTable(AtomTable) == FALSE)
279 return (STATUS_INVALID_PARAMETER);
282 /* delete all atoms */
283 for (i = 0; i < AtomTable->TableSize; i++)
285 Current = AtomTable->Slot[i].Flink;
286 while (Current != &AtomTable->Slot[i])
288 Next = Current->Flink;
289 AtomEntry = (PRTL_ATOM_ENTRY)Current;
291 if ((AtomEntry->Locked == FALSE) ||
292 ((AtomEntry->Locked == TRUE) && (DeletePinned == TRUE)))
294 RtlFreeUnicodeString(&AtomEntry->Name);
296 RtlpFreeHandle(AtomTable->HandleTable,
299 RemoveEntryList(&AtomEntry->List);
300 ExFreePool(AtomEntry);
307 AtomTable->NumberOfAtoms = 0;
309 RtlpUnlockAtomTable(AtomTable);
311 return STATUS_SUCCESS;
319 RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable,
325 PRTL_ATOM_ENTRY Entry;
330 DPRINT("RtlAddAtomToAtomTable (AtomTable %p AtomName %S Atom %p)\n",
331 AtomTable, AtomName, Atom);
333 if (RtlpCheckIntegerAtom (AtomName, &AtomValue))
336 if (AtomValue >= 0xC000)
339 Status = STATUS_INVALID_PARAMETER;
343 Status = STATUS_SUCCESS;
347 *Atom = (RTL_ATOM)AtomValue;
352 RtlpLockAtomTable(AtomTable);
355 Hash = RtlpHashAtomName(AtomTable->TableSize, AtomName);
357 /* search for existing atom */
358 Current = AtomTable->Slot[Hash].Flink;
359 while (Current != &AtomTable->Slot[Hash])
361 Entry = (PRTL_ATOM_ENTRY)Current;
363 DPRINT("Comparing %S and %S\n", Entry->Name.Buffer, AtomName);
364 if (_wcsicmp(Entry->Name.Buffer, AtomName) == 0)
368 *Atom = (RTL_ATOM)(Entry->Index + 0xC000);
369 RtlpUnlockAtomTable(AtomTable);
370 return STATUS_SUCCESS;
372 Current = Current->Flink;
375 /* insert new atom */
376 Entry = ExAllocatePool(NonPagedPool,
377 sizeof(RTL_ATOM_ENTRY));
380 RtlpUnlockAtomTable(AtomTable);
381 return STATUS_NO_MEMORY;
384 InsertTailList(&AtomTable->Slot[Hash], &Entry->List)
385 RtlCreateUnicodeString (&Entry->Name,
388 Entry->Locked = FALSE;
390 /* FIXME: use general function instead !! */
391 RtlpAllocateHandle(AtomTable->HandleTable,
395 DPRINT("AtomIndex %x\n", AtomIndex);
397 Entry->Index = AtomIndex;
398 AtomTable->NumberOfAtoms++;
401 *Atom = (RTL_ATOM)(AtomIndex + 0xC000);
403 RtlpUnlockAtomTable(AtomTable);
405 return STATUS_SUCCESS;
413 RtlDeleteAtomFromAtomTable(IN PRTL_ATOM_TABLE AtomTable,
416 PRTL_ATOM_ENTRY AtomEntry;
418 DPRINT("RtlDeleteAtomFromAtomTable (AtomTable %p Atom %x)\n",
423 return STATUS_SUCCESS;
426 RtlpLockAtomTable(AtomTable);
428 /* FIXME: use general function instead !! */
429 AtomEntry = (PRTL_ATOM_ENTRY)RtlpMapHandleToPointer(AtomTable->HandleTable,
430 (ULONG)Atom - 0xC000);
431 if (AtomEntry == NULL)
433 RtlpUnlockAtomTable(AtomTable);
434 return STATUS_INVALID_HANDLE;
437 DPRINT("AtomEntry %x\n", AtomEntry);
438 DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
440 AtomEntry->RefCount--;
442 if (AtomEntry->RefCount == 0)
444 if (AtomEntry->Locked == TRUE)
446 DPRINT("Atom %wZ is locked!\n", &AtomEntry->Name);
448 RtlpUnlockAtomTable(AtomTable);
449 return STATUS_WAS_LOCKED;
452 DPRINT("Removing atom: %wZ\n", &AtomEntry->Name);
454 RtlFreeUnicodeString(&AtomEntry->Name);
455 RemoveEntryList(&AtomEntry->List);
456 ExFreePool(AtomEntry);
457 RtlpFreeHandle(AtomTable->HandleTable,
458 (ULONG)Atom - 0xC000);
459 AtomTable->NumberOfAtoms++;
462 RtlpUnlockAtomTable(AtomTable);
464 return STATUS_SUCCESS;
472 RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
478 PRTL_ATOM_ENTRY Entry;
482 DPRINT("RtlLookupAtomInAtomTable (AtomTable %p AtomName %S Atom %p)\n",
483 AtomTable, AtomName, Atom);
485 if (RtlpCheckIntegerAtom (AtomName, &AtomValue))
488 if (AtomValue >= 0xC000)
491 Status = STATUS_INVALID_PARAMETER;
495 Status = STATUS_SUCCESS;
499 *Atom = (RTL_ATOM)AtomValue;
504 RtlpLockAtomTable(AtomTable);
507 Hash = RtlpHashAtomName(AtomTable->TableSize, AtomName);
509 /* search for existing atom */
510 Current = AtomTable->Slot[Hash].Flink;
511 while (Current != &AtomTable->Slot[Hash])
513 Entry = (PRTL_ATOM_ENTRY)Current;
515 DPRINT("Comparing %S and %S\n", Entry->Name.Buffer, AtomName);
516 if (_wcsicmp(Entry->Name.Buffer, AtomName) == 0)
519 *Atom = (RTL_ATOM)(Entry->Index + 0xC000);
520 RtlpUnlockAtomTable(AtomTable);
521 return STATUS_SUCCESS;
524 Current = Current->Flink;
527 return STATUS_OBJECT_NAME_NOT_FOUND;
535 RtlPinAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
538 PRTL_ATOM_ENTRY AtomEntry;
540 DPRINT("RtlPinAtomInAtomTable (AtomTable %p Atom %x)\n",
545 return STATUS_SUCCESS;
548 RtlpLockAtomTable(AtomTable);
550 /* FIXME: use general function instead !! */
551 AtomEntry = (PRTL_ATOM_ENTRY)RtlpMapHandleToPointer(AtomTable->HandleTable,
552 (ULONG)Atom - 0xC000);
553 if (AtomEntry == NULL)
555 RtlpUnlockAtomTable(AtomTable);
556 return STATUS_INVALID_HANDLE;
559 DPRINT("AtomEntry %x\n", AtomEntry);
560 DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
562 AtomEntry->Locked = TRUE;
564 RtlpUnlockAtomTable(AtomTable);
566 return STATUS_SUCCESS;
574 RtlQueryAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
576 IN OUT PULONG RefCount,
577 IN OUT PULONG PinCount,
578 IN OUT PWSTR AtomName,
579 IN OUT PULONG NameLength)
582 PRTL_ATOM_ENTRY AtomEntry;
586 if (RefCount != NULL)
591 if (PinCount != NULL)
596 if ((AtomName != NULL) && (NameLength != NULL) && (NameLength > 0))
598 Length = swprintf(AtomName, L"#%lu", (ULONG)Atom);
599 *NameLength = Length * sizeof(WCHAR);
602 return STATUS_SUCCESS;
605 RtlpLockAtomTable(AtomTable);
607 /* FIXME: use general function instead !! */
608 AtomEntry = (PRTL_ATOM_ENTRY)RtlpMapHandleToPointer(AtomTable->HandleTable,
609 (ULONG)Atom - 0xC000);
610 if (AtomEntry == NULL)
612 RtlpUnlockAtomTable(AtomTable);
613 return STATUS_INVALID_HANDLE;
616 DPRINT("AtomEntry %x\n", AtomEntry);
617 DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
619 if (RefCount != NULL)
621 *RefCount = AtomEntry->RefCount;
624 if (PinCount != NULL)
626 *PinCount = (ULONG)AtomEntry->Locked;
629 if ((AtomName != NULL) && (NameLength != NULL))
631 if (*NameLength < AtomEntry->Name.Length)
633 *NameLength = AtomEntry->Name.Length;
634 RtlpUnlockAtomTable(AtomTable);
635 return STATUS_BUFFER_TOO_SMALL;
638 Length = swprintf(AtomName, L"%s", AtomEntry->Name.Buffer);
639 *NameLength = Length * sizeof(WCHAR);
642 RtlpUnlockAtomTable(AtomTable);
644 return STATUS_SUCCESS;
648 /* INTERNAL FUNCTIONS ********************************************************/
650 static PRTL_ATOM_TABLE
651 RtlpGetGlobalAtomTable(VOID)
655 if (GlobalAtomTable != NULL)
656 return GlobalAtomTable;
658 Status = RtlCreateAtomTable(37, &GlobalAtomTable);
659 if (!NT_SUCCESS(Status))
662 return GlobalAtomTable;
667 RtlpHashAtomName(ULONG TableSize,
673 DPRINT("RtlpHashAtomName(TableSize %ld AtomName '%S')\n",
674 TableSize, AtomName);
676 /* convert the string to an internal representation */
680 q += (ULONG)towupper(*p);
684 DPRINT("q %lu Hash %lu\n", q, q % TableSize);
686 return (q % TableSize);
691 RtlpCheckIntegerAtom(PWSTR AtomName,
694 UNICODE_STRING AtomString;
699 DPRINT("RtlpCheckIntegerAtom(AtomName '%S' AtomValue %p)\n",
700 AtomName, AtomValue);
702 if (!((ULONG)AtomName & 0xFFFF0000))
704 LoValue = (USHORT)((ULONG)AtomName & 0xFFFF);
706 if (LoValue >= 0xC000)
712 if (AtomValue != NULL)
713 *AtomValue = LoValue;
718 if (*AtomName != L'#')
725 if ((*p < L'0') || (*p > L'9'))
732 RtlInitUnicodeString(&AtomString,
735 DPRINT1("AtomString: %wZ\n", &AtomString);
737 RtlUnicodeStringToInteger(&AtomString,10, &LongValue);
739 DPRINT1("LongValue: %lu\n", LongValue);
741 *AtomValue = (USHORT)(LongValue & 0x0000FFFF);
750 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
752 AtomTable->Lock = ExAllocatePool(NonPagedPool,
754 if (AtomTable->Lock == NULL)
755 return STATUS_NO_MEMORY;
757 ExInitializeFastMutex((PFAST_MUTEX)AtomTable->Lock);
759 return STATUS_SUCCESS;
764 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
767 ExFreePool(AtomTable->Lock);
772 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
774 // ExAcquireFastMutex((PFAST_MUTEX)AtomTable->Lock);
779 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
781 // ExReleaseFastMutex((PFAST_MUTEX)AtomTable->Lock);
786 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
788 AtomTable->Lock = RtlAllocateHeap(RtlGetProcessHeap(),
790 sizeof(CRITICAL_SECTION));
791 if (AtomTable->Lock == NULL)
792 return STATUS_NO_MEMORY;
794 RtlInitializeCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
796 return STATUS_SUCCESS;
801 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
805 RtlDeleteCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
806 RtlFreeHeap(RtlGetProcessHeap(),
809 AtomTable->Lock = NULL;
815 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
817 RtlEnterCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
823 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
825 RtlLeaveCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
829 /* handle functions */
832 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
834 AtomTable->HandleTable = ExAllocatePool(NonPagedPool,
835 sizeof(RTL_HANDLE_TABLE));
836 if (AtomTable->HandleTable == NULL)
839 RtlpInitializeHandleTable(0xCFFF,
840 (PRTL_HANDLE_TABLE)AtomTable->HandleTable);
847 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
849 if (AtomTable->HandleTable)
851 RtlpDestroyHandleTable((PRTL_HANDLE_TABLE)AtomTable->HandleTable);
852 ExFreePool(AtomTable->HandleTable);
853 AtomTable->HandleTable = NULL;
859 RtlpQueryAtomInformation(PRTL_ATOM_TABLE AtomTable,
861 PATOM_BASIC_INFORMATION AtomInformation,
862 ULONG AtomInformationLength,
870 NameLength = AtomInformationLength - sizeof(ATOM_BASIC_INFORMATION) + sizeof(WCHAR);
871 Status = RtlQueryAtomInAtomTable(AtomTable,
875 AtomInformation->Name,
877 if (!NT_SUCCESS(Status))
882 DPRINT1("NameLength: %lu\n", NameLength);
884 if (ReturnLength != NULL)
886 *ReturnLength = NameLength + sizeof(ATOM_BASIC_INFORMATION);
889 if (NameLength + sizeof(ATOM_BASIC_INFORMATION) > AtomInformationLength)
891 return STATUS_BUFFER_TOO_SMALL;
894 AtomInformation->UsageCount = (USHORT)UsageCount;
895 AtomInformation->Flags = (USHORT)Flags;
896 AtomInformation->NameLength = (USHORT)NameLength;
898 return STATUS_SUCCESS;
903 RtlpQueryAtomTableInformation(PRTL_ATOM_TABLE AtomTable,
905 PATOM_TABLE_INFORMATION AtomInformation,
906 ULONG AtomInformationLength,
909 PLIST_ENTRY Current, Next;
910 PRTL_ATOM_ENTRY AtomEntry;
914 Length = sizeof(ATOM_TABLE_INFORMATION);
915 if (AtomTable->NumberOfAtoms > 1)
917 Length += ((AtomTable->NumberOfAtoms - 1)* sizeof(RTL_ATOM));
920 DPRINT1("RequiredLength: %lu\n", Length);
922 if (ReturnLength != NULL)
924 *ReturnLength = Length;
927 if (Length > AtomInformationLength)
929 return STATUS_BUFFER_TOO_SMALL;
932 AtomInformation->NumberOfAtoms = AtomTable->NumberOfAtoms;
935 for (i = 0; i < AtomTable->TableSize; i++)
937 Current = AtomTable->Slot[i].Flink;
938 while (Current != &AtomTable->Slot[i])
940 Next = Current->Flink;
941 AtomEntry = (PRTL_ATOM_ENTRY)Current;
943 AtomInformation->Atoms[j] = AtomEntry->Index + 0xC000;
950 return STATUS_SUCCESS;