1 /*
2 * Handle Tables
3 *
4 * Copyright (C) 2004 Robert Shearman
5 *
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.
10 *
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.
15 *
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 */
20
21 #include <stdarg.h>
22
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winternl.h"
27 #include "wine/debug.h"
28 #include "ntdll_misc.h"
29
30 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
31
32 /**************************************************************************
33 * RtlInitializeHandleTable (NTDLL.@)
34 *
35 * Initializes a handle table.
36 *
37 * PARAMS
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.
41 *
42 * RETURNS
43 * Nothing.
44 *
45 * SEE
46 * RtlDestroyHandleTable().
47 */
48 void WINAPI RtlInitializeHandleTable(ULONG MaxHandleCount, ULONG HandleSize, RTL_HANDLE_TABLE * HandleTable)
49 {
50 TRACE("(%u, %u, %p)\n", MaxHandleCount, HandleSize, HandleTable);
51
52 memset(HandleTable, 0, sizeof(*HandleTable));
53 HandleTable->MaxHandleCount = MaxHandleCount;
54 HandleTable->HandleSize = HandleSize;
55 }
56
57 /**************************************************************************
58 * RtlDestroyHandleTable (NTDLL.@)
59 *
60 * Destroys a handle table and frees associated resources.
61 *
62 * PARAMS
63 * HandleTable [I] The handle table.
64 *
65 * RETURNS
66 * Any status code returned by NtFreeVirtualMemory().
67 *
68 * NOTES
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.
73 *
74 * SEE
75 * RtlInitializeHandleTable().
76 */
77 NTSTATUS WINAPI RtlDestroyHandleTable(RTL_HANDLE_TABLE * HandleTable)
78 {
79 SIZE_T Size = 0;
80
81 TRACE("(%p)\n", HandleTable);
82
83 /* native version only releases committed memory, but we also release reserved */
84 return NtFreeVirtualMemory(
85 NtCurrentProcess(),
86 &HandleTable->FirstHandle,
87 &Size,
88 MEM_RELEASE);
89 }
90
91 /**************************************************************************
92 * RtlpAllocateSomeHandles (internal)
93 *
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.
96 *
97 * PARAMS
98 * HandleTable [I/O] The handle table.
99 *
100 * RETURNS
101 * NTSTATUS code.
102 */
103 static NTSTATUS RtlpAllocateSomeHandles(RTL_HANDLE_TABLE * HandleTable)
104 {
105 NTSTATUS status;
106 if (!HandleTable->FirstHandle)
107 {
108 PVOID FirstHandleAddr = NULL;
109 SIZE_T MaxSize = HandleTable->MaxHandleCount * HandleTable->HandleSize;
110
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(
114 NtCurrentProcess(),
115 &FirstHandleAddr,
116 0,
117 &MaxSize,
118 MEM_RESERVE,
119 PAGE_READWRITE);
120 if (status != STATUS_SUCCESS)
121 return status;
122 HandleTable->FirstHandle = FirstHandleAddr;
123 HandleTable->ReservedMemory = HandleTable->FirstHandle;
124 HandleTable->MaxHandle = (char *)HandleTable->FirstHandle + MaxSize;
125 }
126 if (!HandleTable->NextFree)
127 {
128 SIZE_T Offset, CommitSize = 4096; /* one page */
129 RTL_HANDLE * FreeHandle = NULL;
130 PVOID NextAvailAddr = HandleTable->ReservedMemory;
131
132 if (HandleTable->ReservedMemory >= HandleTable->MaxHandle)
133 return STATUS_NO_MEMORY; /* the handle table is completely full */
134
135 status = NtAllocateVirtualMemory(
136 NtCurrentProcess(),
137 &NextAvailAddr,
138 0,
139 &CommitSize,
140 MEM_COMMIT,
141 PAGE_READWRITE);
142 if (status != STATUS_SUCCESS)
143 return status;
144
145 for (Offset = 0; Offset < CommitSize; Offset += HandleTable->HandleSize)
146 {
147 /* make sure we don't go over handle limit, even if we can
148 * because of rounding of the table size up to the next page
149 * boundary */
150 if ((char *)HandleTable->ReservedMemory + Offset >= (char *)HandleTable->MaxHandle)
151 break;
152
153 FreeHandle = (RTL_HANDLE *)((char *)HandleTable->ReservedMemory + Offset);
154
155 FreeHandle->Next = (RTL_HANDLE *)((char *)HandleTable->ReservedMemory +
156 Offset + HandleTable->HandleSize);
157 }
158
159 /* shouldn't happen because we already test for this above, but
160 * handle it just in case */
161 if (!FreeHandle)
162 return STATUS_NO_MEMORY;
163
164 /* set the last handle's Next pointer to NULL so that when we run
165 * out of free handles we trigger another commit of memory and
166 * initialize the free pointers */
167 FreeHandle->Next = NULL;
168
169 HandleTable->NextFree = HandleTable->ReservedMemory;
170
171 HandleTable->ReservedMemory = (char *)HandleTable->ReservedMemory + CommitSize;
172 }
173 return STATUS_SUCCESS;
174 }
175
176 /**************************************************************************
177 * RtlAllocateHandle (NTDLL.@)
178 *
179 * Allocates a handle from the handle table.
180 *
181 * PARAMS
182 * HandleTable [I/O] The handle table.
183 * HandleIndex [O] Index of the handle returned. Optional.
184 *
185 * RETURNS
186 * Success: Pointer to allocated handle.
187 * Failure: NULL.
188 *
189 * NOTES
190 * A valid handle must have the bit set as indicated in the code below
191 * otherwise subsequent RtlIsValidHandle() calls will fail.
192 *
193 * static inline void RtlpMakeHandleAllocated(RTL_HANDLE * Handle)
194 * {
195 * ULONG_PTR *AllocatedBit = (ULONG_PTR *)(&Handle->Next);
196 * *AllocatedBit = *AllocatedBit | 1;
197 * }
198 *
199 * SEE
200 * RtlFreeHandle().
201 */
202 RTL_HANDLE * WINAPI RtlAllocateHandle(RTL_HANDLE_TABLE * HandleTable, ULONG * HandleIndex)
203 {
204 RTL_HANDLE * ret;
205
206 TRACE("(%p, %p)\n", HandleTable, HandleIndex);
207
208 if (!HandleTable->NextFree && RtlpAllocateSomeHandles(HandleTable) != STATUS_SUCCESS)
209 return NULL;
210
211 ret = HandleTable->NextFree;
212 HandleTable->NextFree = ret->Next;
213
214 if (HandleIndex)
215 *HandleIndex = (ULONG)(((PCHAR)ret - (PCHAR)HandleTable->FirstHandle) / HandleTable->HandleSize);
216
217 return ret;
218 }
219
220 /**************************************************************************
221 * RtlFreeHandle (NTDLL.@)
222 *
223 * Frees an allocated handle.
224 *
225 * PARAMS
226 * HandleTable [I/O] The handle table.
227 * Handle [I] The handle to be freed.
228 *
229 * RETURNS
230 * Success: TRUE.
231 * Failure: FALSE.
232 *
233 * SEE
234 * RtlAllocateHandle().
235 */
236 BOOLEAN WINAPI RtlFreeHandle(RTL_HANDLE_TABLE * HandleTable, RTL_HANDLE * Handle)
237 {
238 TRACE("(%p, %p)\n", HandleTable, Handle);
239 /* NOTE: we don't validate the handle and we don't make Handle->Next even
240 * again to signal that it is no longer in user - that is done as a side
241 * effect of setting Handle->Next to the previously next free handle in
242 * the handle table */
243 memset(Handle, 0, HandleTable->HandleSize);
244 Handle->Next = HandleTable->NextFree;
245 HandleTable->NextFree = Handle;
246 return TRUE;
247 }
248
249 /**************************************************************************
250 * RtlIsValidHandle (NTDLL.@)
251 *
252 * Determines whether a handle is valid or not.
253 *
254 * PARAMS
255 * HandleTable [I] The handle table.
256 * Handle [I] The handle to be tested.
257 *
258 * RETURNS
259 * Valid: TRUE.
260 * Invalid: FALSE.
261 */
262 BOOLEAN WINAPI RtlIsValidHandle(const RTL_HANDLE_TABLE * HandleTable, const RTL_HANDLE * Handle)
263 {
264 TRACE("(%p, %p)\n", HandleTable, Handle);
265 /* make sure handle is within used region and that it is aligned on
266 * a HandleTable->HandleSize boundary and that Handle->Next is odd,
267 * indicating that the handle is active */
268 if ((Handle >= (RTL_HANDLE *)HandleTable->FirstHandle) &&
269 (Handle < (RTL_HANDLE *)HandleTable->ReservedMemory) &&
270 !((ULONG_PTR)Handle & (HandleTable->HandleSize - 1)) &&
271 ((ULONG_PTR)Handle->Next & 1))
272 return TRUE;
273 else
274 return FALSE;
275 }
276
277 /**************************************************************************
278 * RtlIsValidIndexHandle (NTDLL.@)
279 *
280 * Determines whether a handle index is valid or not.
281 *
282 * PARAMS
283 * HandleTable [I] The handle table.
284 * Index [I] The index of the handle to be tested.
285 * ValidHandle [O] The handle Index refers to.
286 *
287 * RETURNS
288 * Valid: TRUE.
289 * Invalid: FALSE.
290 */
291 BOOLEAN WINAPI RtlIsValidIndexHandle(const RTL_HANDLE_TABLE * HandleTable, ULONG Index, RTL_HANDLE ** ValidHandle)
292 {
293 RTL_HANDLE * Handle;
294
295 TRACE("(%p, %u, %p)\n", HandleTable, Index, ValidHandle);
296 Handle = (RTL_HANDLE *)
297 ((char *)HandleTable->FirstHandle + Index * HandleTable->HandleSize);
298
299 if (RtlIsValidHandle(HandleTable, Handle))
300 {
301 *ValidHandle = Handle;
302 return TRUE;
303 }
304 return FALSE;
305 }
306
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.