4 * Copyright (C) 2004 Robert Shearman
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 #include "wine/debug.h"
28 #include "ntdll_misc.h"
30 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
32 /**************************************************************************
33 * RtlInitializeHandleTable (NTDLL.@)
35 * Initializes a handle table.
38 * MaxHandleCount [I] The maximum number of handles the handle table will support.
39 * HandleSize [I] The size of each handle.
40 * HandleTable [I/O] The handle table.
46 * RtlDestroyHandleTable().
48 void WINAPI RtlInitializeHandleTable(ULONG MaxHandleCount, ULONG HandleSize, RTL_HANDLE_TABLE * HandleTable)
50 TRACE("(%lu, %lu, %p)\n", MaxHandleCount, HandleSize, HandleTable);
52 memset(HandleTable, 0, sizeof(*HandleTable));
53 HandleTable->MaxHandleCount = MaxHandleCount;
54 HandleTable->HandleSize = HandleSize;
57 /**************************************************************************
58 * RtlDestroyHandleTable (NTDLL.@)
60 * Destroys a handle table and frees associated resources.
63 * HandleTable [I] The handle table.
66 * Any status code returned by NtFreeVirtualMemory().
69 * The native version of this API doesn't free the virtual memory that has
70 * been previously reserved, only the committed memory. There is no harm
71 * in also freeing the reserved memory because it won't have been handed out
72 * to any callers. I believe it is "more polite" to free everything.
75 * RtlInitializeHandleTable().
77 NTSTATUS WINAPI RtlDestroyHandleTable(RTL_HANDLE_TABLE * HandleTable)
81 TRACE("(%p)\n", HandleTable);
83 /* native version only releases committed memory, but we also release reserved */
84 return NtFreeVirtualMemory(
86 &HandleTable->FirstHandle,
91 /**************************************************************************
92 * RtlpAllocateSomeHandles (internal)
94 * Reserves memory for the handles if not previously done and commits memory
95 * for a batch of handles if none are free and adds them to the free list.
98 * HandleTable [I/O] The handle table.
103 static NTSTATUS RtlpAllocateSomeHandles(RTL_HANDLE_TABLE * HandleTable)
106 if (!HandleTable->FirstHandle)
108 PVOID FirstHandleAddr = NULL;
109 ULONG MaxSize = HandleTable->MaxHandleCount * HandleTable->HandleSize;
111 /* reserve memory for the handles, but don't commit it yet because we
112 * probably won't use most of it and it will use up physical memory */
113 status = NtAllocateVirtualMemory(
120 if (status != STATUS_SUCCESS)
122 HandleTable->FirstHandle = FirstHandleAddr;
123 HandleTable->ReservedMemory = HandleTable->FirstHandle;
124 HandleTable->MaxHandle = (char *)HandleTable->FirstHandle + MaxSize;
126 if (!HandleTable->NextFree)
128 ULONG CommitSize = 4096; /* one page */
130 RTL_HANDLE * FreeHandle = NULL;
131 PVOID NextAvailAddr = HandleTable->ReservedMemory;
133 if (HandleTable->ReservedMemory >= HandleTable->MaxHandle)
134 return STATUS_NO_MEMORY; /* the handle table is completely full */
136 status = NtAllocateVirtualMemory(
143 if (status != STATUS_SUCCESS)
146 for (Offset = 0; Offset < CommitSize; Offset += HandleTable->HandleSize)
148 /* make sure we don't go over handle limit, even if we can
149 * because of rounding of the table size up to the next page
151 if ((char *)HandleTable->ReservedMemory + Offset >= (char *)HandleTable->MaxHandle)
154 FreeHandle = (RTL_HANDLE *)((char *)HandleTable->ReservedMemory + Offset);
156 FreeHandle->Next = (RTL_HANDLE *)((char *)HandleTable->ReservedMemory +
157 Offset + HandleTable->HandleSize);
160 /* shouldn't happen because we already test for this above, but
161 * handle it just in case */
163 return STATUS_NO_MEMORY;
165 /* set the last handle's Next pointer to NULL so that when we run
166 * out of free handles we trigger another commit of memory and
167 * initialize the free pointers */
168 FreeHandle->Next = NULL;
170 HandleTable->NextFree = HandleTable->ReservedMemory;
172 HandleTable->ReservedMemory = (char *)HandleTable->ReservedMemory + CommitSize;
174 return STATUS_SUCCESS;
177 /**************************************************************************
178 * RtlAllocateHandle (NTDLL.@)
180 * Allocates a handle from the handle table.
183 * HandleTable [I/O] The handle table.
184 * HandleIndex [O] Index of the handle returned. Optional.
187 * Success: Pointer to allocated handle.
193 RTL_HANDLE * WINAPI RtlAllocateHandle(RTL_HANDLE_TABLE * HandleTable, ULONG * HandleIndex)
197 TRACE("(%p, %p)\n", HandleTable, HandleIndex);
199 if (!HandleTable->NextFree && RtlpAllocateSomeHandles(HandleTable) != STATUS_SUCCESS)
202 ret = (RTL_HANDLE *)HandleTable->NextFree;
203 HandleTable->NextFree = ret->Next;
206 *HandleIndex = (ULONG)(((PCHAR)ret - (PCHAR)HandleTable->FirstHandle) / HandleTable->HandleSize);
211 /**************************************************************************
212 * RtlFreeHandle (NTDLL.@)
214 * Frees an allocated handle.
217 * HandleTable [I/O] The handle table.
218 * Handle [I] The handle to be freed.
225 * RtlAllocateHandle().
227 BOOLEAN WINAPI RtlFreeHandle(RTL_HANDLE_TABLE * HandleTable, RTL_HANDLE * Handle)
229 TRACE("(%p, %p)\n", HandleTable, Handle);
230 /* NOTE: we don't validate the handle and we don't make Handle->Next even
231 * again to signal that it is no longer in user - that is done as a side
232 * effect of setting Handle->Next to the previously next free handle in
233 * the handle table */
234 memset(Handle, 0, HandleTable->HandleSize);
235 Handle->Next = (RTL_HANDLE *)HandleTable->NextFree;
236 HandleTable->NextFree = Handle;
240 /**************************************************************************
241 * RtlIsValidHandle (NTDLL.@)
243 * Determines whether a handle is valid or not.
246 * HandleTable [I] The handle table.
247 * Handle [I] The handle to be tested.
253 BOOLEAN WINAPI RtlIsValidHandle(const RTL_HANDLE_TABLE * HandleTable, const RTL_HANDLE * Handle)
255 TRACE("(%p, %p)\n", HandleTable, Handle);
256 /* make sure handle is within used region and that it is aligned on
257 * a HandleTable->HandleSize boundary and that Handle->Next is odd,
258 * indicating that the handle is active */
259 if ((Handle >= (RTL_HANDLE *)HandleTable->FirstHandle) &&
260 (Handle < (RTL_HANDLE *)HandleTable->ReservedMemory) &&
261 !((ULONG_PTR)Handle & (HandleTable->HandleSize - 1)) &&
262 ((ULONG_PTR)Handle->Next & 1))
268 /**************************************************************************
269 * RtlIsValidIndexHandle (NTDLL.@)
271 * Determines whether a handle index is valid or not.
274 * HandleTable [I] The handle table.
275 * Index [I] The index of the handle to be tested.
276 * ValidHandle [O] The handle Index refers to.
282 BOOLEAN WINAPI RtlIsValidIndexHandle(const RTL_HANDLE_TABLE * HandleTable, ULONG Index, RTL_HANDLE ** ValidHandle)
286 TRACE("(%p, %lu, %p)\n", HandleTable, Index, ValidHandle);
287 Handle = (RTL_HANDLE *)
288 ((char *)HandleTable->FirstHandle + Index * HandleTable->HandleSize);
290 if (RtlIsValidHandle(HandleTable, Handle))
292 *ValidHandle = Handle;