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 *****************************************************************/
59 RtlCreateAtomTable(ULONG TableSize,
60 PRTL_ATOM_TABLE *AtomTable)
62 PRTL_ATOM_TABLE Table;
66 DPRINT("RtlCreateAtomTable(TableSize %lu AtomTable %p)\n",
67 TableSize, AtomTable);
69 if (*AtomTable != NULL)
71 return STATUS_SUCCESS;
74 /* allocate atom table */
75 Table = RtlAllocateHeap(RtlGetProcessHeap(),
77 TableSize * sizeof(LIST_ENTRY) +
78 sizeof(RTL_ATOM_TABLE));
81 return STATUS_NO_MEMORY;
84 /* initialize atom table */
85 Table->TableSize = TableSize;
87 for (i = 0; i < TableSize; i++)
89 InitializeListHead(&Table->Slot[i]);
92 Status = RtlpInitAtomTableLock(Table);
93 if (!NT_SUCCESS(Status))
95 RtlFreeHeap(RtlGetProcessHeap(),
101 if (RtlpCreateAtomHandleTable(Table) == FALSE)
103 RtlpDestroyAtomTableLock(Table);
104 RtlFreeHeap(RtlGetProcessHeap(),
107 return STATUS_NO_MEMORY;
111 return STATUS_SUCCESS;
116 RtlDestroyAtomTable(IN PRTL_ATOM_TABLE AtomTable)
119 PRTL_ATOM_ENTRY AtomEntry;
122 if (RtlpLockAtomTable(AtomTable) == FALSE)
124 return (STATUS_INVALID_PARAMETER);
127 /* delete all atoms */
128 for (i = 0; i < AtomTable->TableSize; i++)
131 Current = AtomTable->Slot[i].Flink;
132 while (Current != &AtomTable->Slot[i])
134 AtomEntry = (PRTL_ATOM_ENTRY)Current;
135 RtlFreeUnicodeString(&AtomEntry->Name);
136 RemoveEntryList(&AtomEntry->List);
137 RtlFreeHeap(RtlGetProcessHeap(),
140 Current = AtomTable->Slot[i].Flink;
145 RtlpDestroyAtomHandleTable(AtomTable);
147 RtlpUnlockAtomTable(AtomTable);
149 RtlpDestroyAtomTableLock(AtomTable);
151 RtlFreeHeap(RtlGetProcessHeap(),
155 return STATUS_SUCCESS;
160 RtlEmptyAtomTable(PRTL_ATOM_TABLE AtomTable,
161 BOOLEAN DeletePinned)
163 PLIST_ENTRY Current, Next;
164 PRTL_ATOM_ENTRY AtomEntry;
167 DPRINT("RtlEmptyAtomTable (AtomTable %p DeletePinned %x)\n",
168 AtomTable, DeletePinned);
170 if (RtlpLockAtomTable(AtomTable) == FALSE)
172 return (STATUS_INVALID_PARAMETER);
175 /* delete all atoms */
176 for (i = 0; i < AtomTable->TableSize; i++)
178 Current = AtomTable->Slot[i].Flink;
179 while (Current != &AtomTable->Slot[i])
181 Next = Current->Flink;
182 AtomEntry = (PRTL_ATOM_ENTRY)Current;
184 if ((AtomEntry->Locked == FALSE) ||
185 ((AtomEntry->Locked == TRUE) && (DeletePinned == TRUE)))
187 RtlFreeUnicodeString(&AtomEntry->Name);
189 RtlFreeHandle(AtomTable->HandleTable,
192 RemoveEntryList(&AtomEntry->List);
193 RtlFreeHeap(RtlGetProcessHeap(),
202 RtlpUnlockAtomTable(AtomTable);
204 return STATUS_SUCCESS;
209 RtlAddAtomToAtomTable(IN PRTL_ATOM_TABLE AtomTable,
215 PRTL_ATOM_ENTRY Entry;
218 PRTL_ATOM_HANDLE AtomHandle;
221 DPRINT("RtlAddAtomToAtomTable (AtomTable %p AtomName %S Atom %p)\n",
222 AtomTable, AtomName, Atom);
224 if (RtlpCheckIntegerAtom (AtomName, &AtomValue))
227 if (AtomValue >= 0xC000)
230 Status = STATUS_INVALID_PARAMETER;
234 Status = STATUS_SUCCESS;
238 *Atom = (RTL_ATOM)AtomValue;
243 RtlpLockAtomTable(AtomTable);
246 Hash = RtlpHashAtomName(AtomTable->TableSize, AtomName);
248 /* search for existing atom */
249 Current = AtomTable->Slot[Hash].Flink;
250 while (Current != &AtomTable->Slot[Hash])
252 Entry = (PRTL_ATOM_ENTRY)Current;
254 DPRINT("Comparing %S and %S\n", Entry->Name.Buffer, AtomName);
255 if (_wcsicmp(Entry->Name.Buffer, AtomName) == 0)
259 *Atom = (RTL_ATOM)(Entry->Index + 0xC000);
260 RtlpUnlockAtomTable(AtomTable);
261 return STATUS_SUCCESS;
263 Current = Current->Flink;
266 /* insert new atom */
267 Entry = RtlAllocateHeap(RtlGetProcessHeap(),
269 sizeof(RTL_ATOM_ENTRY));
272 RtlpUnlockAtomTable(AtomTable);
273 return STATUS_NO_MEMORY;
276 InsertTailList(&AtomTable->Slot[Hash], &Entry->List)
277 RtlCreateUnicodeString (&Entry->Name,
280 Entry->Locked = FALSE;
282 /* FIXME: use general function instead !! */
283 AtomHandle = (PRTL_ATOM_HANDLE)RtlAllocateHandle(AtomTable->HandleTable,
286 DPRINT("AtomHandle %p AtomIndex %x\n", AtomHandle, AtomIndex);
288 AtomHandle->Entry = Entry;
289 Entry->Index = AtomIndex;
290 Entry->Handle = (PRTL_HANDLE)AtomHandle;
293 *Atom = (RTL_ATOM)(AtomIndex + 0xC000);
295 RtlpUnlockAtomTable(AtomTable);
297 return STATUS_SUCCESS;
302 RtlDeleteAtomFromAtomTable(IN PRTL_ATOM_TABLE AtomTable,
305 PRTL_ATOM_HANDLE AtomHandle;
306 PRTL_ATOM_ENTRY AtomEntry;
308 DPRINT("RtlDeleteAtomFromAtomTable (AtomTable %p Atom %x)\n",
313 return STATUS_SUCCESS;
316 RtlpLockAtomTable(AtomTable);
318 /* FIXME: use general function instead !! */
319 if (!RtlIsValidIndexHandle(AtomTable->HandleTable,
320 (PRTL_HANDLE *)&AtomHandle,
321 (ULONG)Atom - 0xC000))
323 RtlpUnlockAtomTable(AtomTable);
324 return STATUS_INVALID_HANDLE;
327 DPRINT("AtomHandle %x\n", AtomHandle);
328 DPRINT("AtomHandle->Entry %x\n", AtomHandle->Entry);
330 AtomEntry = AtomHandle->Entry;
332 DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
334 AtomEntry->RefCount--;
336 if (AtomEntry->RefCount == 0)
338 if (AtomEntry->Locked == TRUE)
340 DPRINT("Atom %wZ is locked!\n", &AtomEntry->Name);
342 RtlpUnlockAtomTable(AtomTable);
343 return STATUS_WAS_LOCKED;
346 DPRINT("Removing atom: %wZ\n", &AtomEntry->Name);
348 RtlFreeUnicodeString(&AtomEntry->Name);
349 RemoveEntryList(&AtomEntry->List);
350 RtlFreeHeap(RtlGetProcessHeap(),
353 RtlFreeHandle(AtomTable->HandleTable,
354 (PRTL_HANDLE)AtomHandle);
357 RtlpUnlockAtomTable(AtomTable);
359 return STATUS_SUCCESS;
364 RtlLookupAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
370 PRTL_ATOM_ENTRY Entry;
374 DPRINT("RtlLookupAtomInAtomTable (AtomTable %p AtomName %S Atom %p)\n",
375 AtomTable, AtomName, Atom);
377 if (RtlpCheckIntegerAtom (AtomName, &AtomValue))
380 if (AtomValue >= 0xC000)
383 Status = STATUS_INVALID_PARAMETER;
387 Status = STATUS_SUCCESS;
391 *Atom = (RTL_ATOM)AtomValue;
396 RtlpLockAtomTable(AtomTable);
399 Hash = RtlpHashAtomName(AtomTable->TableSize, AtomName);
401 /* search for existing atom */
402 Current = AtomTable->Slot[Hash].Flink;
403 while (Current != &AtomTable->Slot[Hash])
405 Entry = (PRTL_ATOM_ENTRY)Current;
407 DPRINT("Comparing %S and %S\n", Entry->Name.Buffer, AtomName);
408 if (_wcsicmp(Entry->Name.Buffer, AtomName) == 0)
411 *Atom = (RTL_ATOM)(Entry->Index + 0xC000);
412 RtlpUnlockAtomTable(AtomTable);
413 return STATUS_SUCCESS;
416 Current = Current->Flink;
419 return STATUS_OBJECT_NAME_NOT_FOUND;
424 RtlPinAtomInAtomTable(IN PRTL_ATOM_TABLE AtomTable,
427 PRTL_ATOM_HANDLE AtomHandle;
428 PRTL_ATOM_ENTRY AtomEntry;
430 DPRINT("RtlPinAtomInAtomTable (AtomTable %p Atom %x)\n",
435 return STATUS_SUCCESS;
438 RtlpLockAtomTable(AtomTable);
440 /* FIXME: use general function instead !! */
441 if (!RtlIsValidIndexHandle(AtomTable->HandleTable,
442 (PRTL_HANDLE *)&AtomHandle,
443 (ULONG)Atom - 0xC000))
445 RtlpUnlockAtomTable(AtomTable);
446 return STATUS_INVALID_HANDLE;
449 DPRINT("AtomHandle %x\n", AtomHandle);
450 DPRINT("AtomHandle->Entry %x\n", AtomHandle->Entry);
452 AtomEntry = AtomHandle->Entry;
454 DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
456 AtomEntry->Locked = TRUE;
458 RtlpUnlockAtomTable(AtomTable);
460 return STATUS_SUCCESS;
465 RtlQueryAtomInAtomTable(PRTL_ATOM_TABLE AtomTable,
473 PRTL_ATOM_HANDLE AtomHandle;
474 PRTL_ATOM_ENTRY AtomEntry;
478 if (RefCount != NULL)
483 if (PinCount != NULL)
488 if ((AtomName != NULL) && (NameLength != NULL) && (NameLength > 0))
490 Length = swprintf(AtomName, L"#%lu", (ULONG)Atom);
491 *NameLength = Length * sizeof(WCHAR);
494 return STATUS_SUCCESS;
497 RtlpLockAtomTable(AtomTable);
499 /* FIXME: use general function instead !! */
500 if (!RtlIsValidIndexHandle(AtomTable->HandleTable,
501 (PRTL_HANDLE *)&AtomHandle,
502 (ULONG)Atom - 0xC000))
504 RtlpUnlockAtomTable(AtomTable);
505 return STATUS_INVALID_HANDLE;
508 DPRINT("AtomHandle %x\n", AtomHandle);
509 DPRINT("AtomHandle->Entry %x\n", AtomHandle->Entry);
511 AtomEntry = AtomHandle->Entry;
513 DPRINT("Atom name: %wZ\n", &AtomEntry->Name);
515 if (RefCount != NULL)
517 *RefCount = AtomEntry->RefCount;
520 if (PinCount != NULL)
522 *PinCount = (ULONG)AtomEntry->Locked;
525 if ((AtomName != NULL) && (NameLength != NULL))
527 if (*NameLength < AtomEntry->Name.Length)
529 *NameLength = AtomEntry->Name.Length;
530 RtlpUnlockAtomTable(AtomTable);
531 return STATUS_BUFFER_TOO_SMALL;
534 Length = swprintf(AtomName, L"%s", AtomEntry->Name.Buffer);
535 *NameLength = Length * sizeof(WCHAR);
538 RtlpUnlockAtomTable(AtomTable);
540 return STATUS_SUCCESS;
544 /* INTERNAL FUNCTIONS ********************************************************/
547 RtlpHashAtomName(ULONG TableSize,
553 DPRINT("RtlpHashAtomName(TableSize %ld AtomName '%S')\n",
554 TableSize, AtomName);
556 /* convert the string to an internal representation */
560 q += (ULONG)towupper(*p);
564 DPRINT("q %lu Hash %lu\n", q, q % TableSize);
566 return (q % TableSize);
571 RtlpCheckIntegerAtom(PWSTR AtomName,
574 UNICODE_STRING AtomString;
579 DPRINT("RtlpCheckIntegerAtom(AtomName '%S' AtomValue %p)\n",
580 AtomName, AtomValue);
582 if (!((ULONG)AtomName & 0xFFFF0000))
584 LoValue = (USHORT)((ULONG)AtomName & 0xFFFF);
586 if (LoValue >= 0xC000)
592 if (AtomValue != NULL)
593 *AtomValue = LoValue;
598 if (*AtomName != L'#')
605 if ((*p < L'0') || (*p > L'9'))
612 RtlInitUnicodeString(&AtomString,
615 RtlUnicodeStringToInteger(&AtomString,10, &LongValue);
617 *AtomValue = (USHORT)(LongValue & 0x0000FFFF);
626 RtlpInitAtomTableLock(PRTL_ATOM_TABLE AtomTable)
628 AtomTable->Lock = RtlAllocateHeap(RtlGetProcessHeap(),
630 sizeof(CRITICAL_SECTION));
631 if (AtomTable->Lock == NULL)
632 return STATUS_NO_MEMORY;
634 RtlInitializeCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
636 return STATUS_SUCCESS;
641 RtlpDestroyAtomTableLock(PRTL_ATOM_TABLE AtomTable)
645 RtlDeleteCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
646 RtlFreeHeap(RtlGetProcessHeap(),
649 AtomTable->Lock = NULL;
655 RtlpLockAtomTable(PRTL_ATOM_TABLE AtomTable)
657 RtlEnterCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
663 RtlpUnlockAtomTable(PRTL_ATOM_TABLE AtomTable)
665 RtlLeaveCriticalSection((PCRITICAL_SECTION)AtomTable->Lock);
669 /* handle functions */
672 RtlpCreateAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
674 AtomTable->HandleTable = RtlAllocateHeap(RtlGetProcessHeap(),
676 sizeof(RTL_HANDLE_TABLE));
677 if (AtomTable->HandleTable == NULL)
680 RtlInitializeHandleTable(0xCFFF,
681 sizeof(RTL_ATOM_HANDLE),
682 (PRTL_HANDLE_TABLE)AtomTable->HandleTable);
688 RtlpDestroyAtomHandleTable(PRTL_ATOM_TABLE AtomTable)
690 if (AtomTable->HandleTable)
692 RtlDestroyHandleTable((PRTL_HANDLE_TABLE)AtomTable->HandleTable);
693 RtlFreeHeap(RtlGetProcessHeap(),
695 AtomTable->HandleTable);
696 AtomTable->HandleTable = NULL;