1 /* $Id: atom.c,v 1.4 2002/09/08 10:23:41 chorns Exp $
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
;