3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: lib/ntdll/rtl/atom.c
6 * PURPOSE: Atom managment
12 /* INCLUDES *****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <ntdll/rtl.h>
16 #include <ntos/heap.h>
19 #include <ntdll/ntdll.h>
22 /* LOCAL TYPES ***************************************************************/
24 typedef struct _RTL_ATOM_ENTRY
32 } RTL_ATOM_ENTRY
, *PRTL_ATOM_ENTRY
;
34 typedef struct _RTL_ATOM_HANDLE
37 PRTL_ATOM_ENTRY Entry
;
38 } RTL_ATOM_HANDLE
, *PRTL_ATOM_HANDLE
;
41 /* PROTOTYPES ****************************************************************/
43 static ULONG
RtlpHashAtomName(ULONG TableSize
, PWSTR AtomName
);
44 static BOOLEAN
RtlpCheckIntegerAtom(PWSTR AtomName
, PUSHORT AtomValue
);
46 static NTSTATUS
RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable
);
47 static VOID
RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable
);
48 static BOOLEAN
RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable
);
49 static VOID
RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable
);
51 static BOOLEAN
RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable
);
52 static VOID
RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable
);
55 /* FUNCTIONS *****************************************************************/
62 RtlCreateAtomTable(ULONG TableSize
,
63 PRTL_ATOM_TABLE
*AtomTable
)
65 PRTL_ATOM_TABLE Table
;
69 DPRINT("RtlCreateAtomTable(TableSize %lu AtomTable %p)\n",
70 TableSize
, AtomTable
);
72 if (*AtomTable
!= NULL
)
74 return STATUS_SUCCESS
;
77 /* allocate atom table */
78 Table
= RtlAllocateHeap(RtlGetProcessHeap(),
80 TableSize
* sizeof(LIST_ENTRY
) +
81 sizeof(RTL_ATOM_TABLE
));
84 return STATUS_NO_MEMORY
;
87 /* initialize atom table */
88 Table
->TableSize
= TableSize
;
90 for (i
= 0; i
< TableSize
; i
++)
92 InitializeListHead(&Table
->Slot
[i
]);
95 Status
= RtlpInitAtomTableLock(Table
);
96 if (!NT_SUCCESS(Status
))
98 RtlFreeHeap(RtlGetProcessHeap(),
104 if (RtlpCreateAtomHandleTable(Table
) == FALSE
)
106 RtlpDestroyAtomTableLock(Table
);
107 RtlFreeHeap(RtlGetProcessHeap(),
110 return STATUS_NO_MEMORY
;
114 return STATUS_SUCCESS
;
122 RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable
)
125 PRTL_ATOM_ENTRY AtomEntry
;
128 if (RtlpLockAtomTable(AtomTable
) == FALSE
)
130 return (STATUS_INVALID_PARAMETER
);
133 /* delete all atoms */
134 for (i
= 0; i
< AtomTable
->TableSize
; i
++)
137 Current
= AtomTable
->Slot
[i
].Flink
;
138 while (Current
!= &AtomTable
->Slot
[i
])
140 AtomEntry
= (PRTL_ATOM_ENTRY
)Current
;
141 RtlFreeUnicodeString(&AtomEntry
->Name
);
142 RemoveEntryList(&AtomEntry
->List
);
143 RtlFreeHeap(RtlGetProcessHeap(),
146 Current
= AtomTable
->Slot
[i
].Flink
;
151 RtlpDestroyAtomHandleTable(AtomTable
);
153 RtlpUnlockAtomTable(AtomTable
);
155 RtlpDestroyAtomTableLock(AtomTable
);
157 RtlFreeHeap(RtlGetProcessHeap(),
161 return STATUS_SUCCESS
;
169 RtlEmptyAtomTable(PRTL_ATOM_TABLE AtomTable
,
170 BOOLEAN DeletePinned
)
172 PLIST_ENTRY Current
, Next
;
173 PRTL_ATOM_ENTRY AtomEntry
;
176 DPRINT("RtlEmptyAtomTable (AtomTable %p DeletePinned %x)\n",
177 AtomTable
, DeletePinned
);
179 if (RtlpLockAtomTable(AtomTable
) == FALSE
)
181 return (STATUS_INVALID_PARAMETER
);
184 /* delete all atoms */
185 for (i
= 0; i
< AtomTable
->TableSize
; i
++)
187 Current
= AtomTable
->Slot
[i
].Flink
;
188 while (Current
!= &AtomTable
->Slot
[i
])
190 Next
= Current
->Flink
;
191 AtomEntry
= (PRTL_ATOM_ENTRY
)Current
;
193 if ((AtomEntry
->Locked
== FALSE
) ||
194 ((AtomEntry
->Locked
== TRUE
) && (DeletePinned
== TRUE
)))
196 RtlFreeUnicodeString(&AtomEntry
->Name
);
198 RtlFreeHandle(AtomTable
->HandleTable
,
201 RemoveEntryList(&AtomEntry
->List
);
202 RtlFreeHeap(RtlGetProcessHeap(),
211 RtlpUnlockAtomTable(AtomTable
);
213 return STATUS_SUCCESS
;
221 RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
227 PRTL_ATOM_ENTRY Entry
;
230 PRTL_ATOM_HANDLE AtomHandle
;
233 DPRINT("RtlAddAtomToAtomTable (AtomTable %p AtomName %S Atom %p)\n",
234 AtomTable
, AtomName
, Atom
);
236 if (RtlpCheckIntegerAtom (AtomName
, &AtomValue
))
239 if (AtomValue
>= 0xC000)
242 Status
= STATUS_INVALID_PARAMETER
;
246 Status
= STATUS_SUCCESS
;
250 *Atom
= (RTL_ATOM
)AtomValue
;
255 RtlpLockAtomTable(AtomTable
);
258 Hash
= RtlpHashAtomName(AtomTable
->TableSize
, AtomName
);
260 /* search for existing atom */
261 Current
= AtomTable
->Slot
[Hash
].Flink
;
262 while (Current
!= &AtomTable
->Slot
[Hash
])
264 Entry
= (PRTL_ATOM_ENTRY
)Current
;
266 DPRINT("Comparing %S and %S\n", Entry
->Name
.Buffer
, AtomName
);
267 if (_wcsicmp(Entry
->Name
.Buffer
, AtomName
) == 0)
271 *Atom
= (RTL_ATOM
)(Entry
->Index
+ 0xC000);
272 RtlpUnlockAtomTable(AtomTable
);
273 return STATUS_SUCCESS
;
275 Current
= Current
->Flink
;
278 /* insert new atom */
279 Entry
= RtlAllocateHeap(RtlGetProcessHeap(),
281 sizeof(RTL_ATOM_ENTRY
));
284 RtlpUnlockAtomTable(AtomTable
);
285 return STATUS_NO_MEMORY
;
288 InsertTailList(&AtomTable
->Slot
[Hash
], &Entry
->List
);
289 RtlCreateUnicodeString (&Entry
->Name
,
292 Entry
->Locked
= FALSE
;
294 /* FIXME: use general function instead !! */
295 AtomHandle
= (PRTL_ATOM_HANDLE
)RtlAllocateHandle(AtomTable
->HandleTable
,
298 DPRINT("AtomHandle %p AtomIndex %x\n", AtomHandle
, AtomIndex
);
300 AtomHandle
->Entry
= Entry
;
301 Entry
->Index
= AtomIndex
;
302 Entry
->Handle
= (PRTL_HANDLE
)AtomHandle
;
305 *Atom
= (RTL_ATOM
)(AtomIndex
+ 0xC000);
307 RtlpUnlockAtomTable(AtomTable
);
309 return STATUS_SUCCESS
;
317 RtlDeleteAtomFromAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
320 PRTL_ATOM_HANDLE AtomHandle
;
321 PRTL_ATOM_ENTRY AtomEntry
;
323 DPRINT("RtlDeleteAtomFromAtomTable (AtomTable %p Atom %x)\n",
328 return STATUS_SUCCESS
;
331 RtlpLockAtomTable(AtomTable
);
333 /* FIXME: use general function instead !! */
334 if (!RtlIsValidIndexHandle(AtomTable
->HandleTable
,
335 (PRTL_HANDLE
*)&AtomHandle
,
336 (ULONG
)Atom
- 0xC000))
338 RtlpUnlockAtomTable(AtomTable
);
339 return STATUS_INVALID_HANDLE
;
342 DPRINT("AtomHandle %x\n", AtomHandle
);
343 DPRINT("AtomHandle->Entry %x\n", AtomHandle
->Entry
);
345 AtomEntry
= AtomHandle
->Entry
;
347 DPRINT("Atom name: %wZ\n", &AtomEntry
->Name
);
349 AtomEntry
->RefCount
--;
351 if (AtomEntry
->RefCount
== 0)
353 if (AtomEntry
->Locked
== TRUE
)
355 DPRINT("Atom %wZ is locked!\n", &AtomEntry
->Name
);
357 RtlpUnlockAtomTable(AtomTable
);
358 return STATUS_WAS_LOCKED
;
361 DPRINT("Removing atom: %wZ\n", &AtomEntry
->Name
);
363 RtlFreeUnicodeString(&AtomEntry
->Name
);
364 RemoveEntryList(&AtomEntry
->List
);
365 RtlFreeHeap(RtlGetProcessHeap(),
368 RtlFreeHandle(AtomTable
->HandleTable
,
369 (PRTL_HANDLE
)AtomHandle
);
372 RtlpUnlockAtomTable(AtomTable
);
374 return STATUS_SUCCESS
;
382 RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
388 PRTL_ATOM_ENTRY Entry
;
392 DPRINT("RtlLookupAtomInAtomTable (AtomTable %p AtomName %S Atom %p)\n",
393 AtomTable
, AtomName
, Atom
);
395 if (RtlpCheckIntegerAtom (AtomName
, &AtomValue
))
398 if (AtomValue
>= 0xC000)
401 Status
= STATUS_INVALID_PARAMETER
;
405 Status
= STATUS_SUCCESS
;
409 *Atom
= (RTL_ATOM
)AtomValue
;
414 RtlpLockAtomTable(AtomTable
);
417 Hash
= RtlpHashAtomName(AtomTable
->TableSize
, AtomName
);
419 /* search for existing atom */
420 Current
= AtomTable
->Slot
[Hash
].Flink
;
421 while (Current
!= &AtomTable
->Slot
[Hash
])
423 Entry
= (PRTL_ATOM_ENTRY
)Current
;
425 DPRINT("Comparing %S and %S\n", Entry
->Name
.Buffer
, AtomName
);
426 if (_wcsicmp(Entry
->Name
.Buffer
, AtomName
) == 0)
429 *Atom
= (RTL_ATOM
)(Entry
->Index
+ 0xC000);
430 RtlpUnlockAtomTable(AtomTable
);
431 return STATUS_SUCCESS
;
434 Current
= Current
->Flink
;
437 RtlpUnlockAtomTable(AtomTable
);
439 return STATUS_OBJECT_NAME_NOT_FOUND
;
447 RtlPinAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable
,
450 PRTL_ATOM_HANDLE AtomHandle
;
451 PRTL_ATOM_ENTRY AtomEntry
;
453 DPRINT("RtlPinAtomInAtomTable (AtomTable %p Atom %x)\n",
458 return STATUS_SUCCESS
;
461 RtlpLockAtomTable(AtomTable
);
463 /* FIXME: use general function instead !! */
464 if (!RtlIsValidIndexHandle(AtomTable
->HandleTable
,
465 (PRTL_HANDLE
*)&AtomHandle
,
466 (ULONG
)Atom
- 0xC000))
468 RtlpUnlockAtomTable(AtomTable
);
469 return STATUS_INVALID_HANDLE
;
472 DPRINT("AtomHandle %x\n", AtomHandle
);
473 DPRINT("AtomHandle->Entry %x\n", AtomHandle
->Entry
);
475 AtomEntry
= AtomHandle
->Entry
;
477 DPRINT("Atom name: %wZ\n", &AtomEntry
->Name
);
479 AtomEntry
->Locked
= TRUE
;
481 RtlpUnlockAtomTable(AtomTable
);
483 return STATUS_SUCCESS
;
491 RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable
,
499 PRTL_ATOM_HANDLE AtomHandle
;
500 PRTL_ATOM_ENTRY AtomEntry
;
504 if (RefCount
!= NULL
)
509 if (PinCount
!= NULL
)
514 if ((AtomName
!= NULL
) && (NameLength
!= NULL
) && (NameLength
> 0))
516 Length
= swprintf(AtomName
, L
"#%lu", (ULONG
)Atom
);
517 *NameLength
= Length
* sizeof(WCHAR
);
520 return STATUS_SUCCESS
;
523 RtlpLockAtomTable(AtomTable
);
525 /* FIXME: use general function instead !! */
526 if (!RtlIsValidIndexHandle(AtomTable
->HandleTable
,
527 (PRTL_HANDLE
*)&AtomHandle
,
528 (ULONG
)Atom
- 0xC000))
530 RtlpUnlockAtomTable(AtomTable
);
531 return STATUS_INVALID_HANDLE
;
534 DPRINT("AtomHandle %x\n", AtomHandle
);
535 DPRINT("AtomHandle->Entry %x\n", AtomHandle
->Entry
);
537 AtomEntry
= AtomHandle
->Entry
;
539 DPRINT("Atom name: %wZ\n", &AtomEntry
->Name
);
541 if (RefCount
!= NULL
)
543 *RefCount
= AtomEntry
->RefCount
;
546 if (PinCount
!= NULL
)
548 *PinCount
= (ULONG
)AtomEntry
->Locked
;
551 if ((AtomName
!= NULL
) && (NameLength
!= NULL
))
553 if (*NameLength
< AtomEntry
->Name
.Length
)
555 *NameLength
= AtomEntry
->Name
.Length
;
556 RtlpUnlockAtomTable(AtomTable
);
557 return STATUS_BUFFER_TOO_SMALL
;
560 Length
= swprintf(AtomName
, L
"%s", AtomEntry
->Name
.Buffer
);
561 *NameLength
= Length
* sizeof(WCHAR
);
564 RtlpUnlockAtomTable(AtomTable
);
566 return STATUS_SUCCESS
;
570 /* INTERNAL FUNCTIONS ********************************************************/
573 RtlpHashAtomName(ULONG TableSize
,
579 DPRINT("RtlpHashAtomName(TableSize %ld AtomName '%S')\n",
580 TableSize
, AtomName
);
582 /* convert the string to an internal representation */
586 q
+= (ULONG
)towupper(*p
);
590 DPRINT("q %lu Hash %lu\n", q
, q
% TableSize
);
592 return (q
% TableSize
);
597 RtlpCheckIntegerAtom(PWSTR AtomName
,
600 UNICODE_STRING AtomString
;
605 DPRINT("RtlpCheckIntegerAtom(AtomName '%S' AtomValue %p)\n",
606 AtomName
, AtomValue
);
608 if (!((ULONG
)AtomName
& 0xFFFF0000))
610 LoValue
= (USHORT
)((ULONG
)AtomName
& 0xFFFF);
612 if (LoValue
>= 0xC000)
618 if (AtomValue
!= NULL
)
619 *AtomValue
= LoValue
;
624 if (*AtomName
!= L
'#')
631 if ((*p
< L
'0') || (*p
> L
'9'))
638 RtlInitUnicodeString(&AtomString
,
641 RtlUnicodeStringToInteger(&AtomString
,10, &LongValue
);
643 *AtomValue
= (USHORT
)(LongValue
& 0x0000FFFF);
652 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
654 AtomTable
->Lock
= RtlAllocateHeap(RtlGetProcessHeap(),
656 sizeof(CRITICAL_SECTION
));
657 if (AtomTable
->Lock
== NULL
)
658 return STATUS_NO_MEMORY
;
660 RtlInitializeCriticalSection((PCRITICAL_SECTION
)AtomTable
->Lock
);
662 return STATUS_SUCCESS
;
667 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable
)
671 RtlDeleteCriticalSection((PCRITICAL_SECTION
)AtomTable
->Lock
);
672 RtlFreeHeap(RtlGetProcessHeap(),
675 AtomTable
->Lock
= NULL
;
681 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable
)
683 RtlEnterCriticalSection((PCRITICAL_SECTION
)AtomTable
->Lock
);
689 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable
)
691 RtlLeaveCriticalSection((PCRITICAL_SECTION
)AtomTable
->Lock
);
695 /* handle functions */
698 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
700 AtomTable
->HandleTable
= RtlAllocateHeap(RtlGetProcessHeap(),
702 sizeof(RTL_HANDLE_TABLE
));
703 if (AtomTable
->HandleTable
== NULL
)
706 RtlInitializeHandleTable(0xCFFF,
707 sizeof(RTL_ATOM_HANDLE
),
708 (PRTL_HANDLE_TABLE
)AtomTable
->HandleTable
);
714 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable
)
716 if (AtomTable
->HandleTable
)
718 RtlDestroyHandleTable((PRTL_HANDLE_TABLE
)AtomTable
->HandleTable
);
719 RtlFreeHeap(RtlGetProcessHeap(),
721 AtomTable
->HandleTable
);
722 AtomTable
->HandleTable
= NULL
;