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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #define WIN32_NO_STATUS
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("(%u, %u, %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 SIZE_T 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 SIZE_T Offset
, CommitSize
= 4096; /* one page */
129 RTL_HANDLE
* FreeHandle
= NULL
;
130 PVOID NextAvailAddr
= HandleTable
->ReservedMemory
;
132 if (HandleTable
->ReservedMemory
>= HandleTable
->MaxHandle
)
133 return STATUS_NO_MEMORY
; /* the handle table is completely full */
135 status
= NtAllocateVirtualMemory(
142 if (status
!= STATUS_SUCCESS
)
145 for (Offset
= 0; Offset
< CommitSize
; Offset
+= HandleTable
->HandleSize
)
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
150 if ((char *)HandleTable
->ReservedMemory
+ Offset
>= (char *)HandleTable
->MaxHandle
)
153 FreeHandle
= (RTL_HANDLE
*)((char *)HandleTable
->ReservedMemory
+ Offset
);
155 FreeHandle
->Next
= (RTL_HANDLE
*)((char *)HandleTable
->ReservedMemory
+
156 Offset
+ HandleTable
->HandleSize
);
159 /* shouldn't happen because we already test for this above, but
160 * handle it just in case */
162 return STATUS_NO_MEMORY
;
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
;
169 HandleTable
->NextFree
= HandleTable
->ReservedMemory
;
171 HandleTable
->ReservedMemory
= (char *)HandleTable
->ReservedMemory
+ CommitSize
;
173 return STATUS_SUCCESS
;
176 /**************************************************************************
177 * RtlAllocateHandle (NTDLL.@)
179 * Allocates a handle from the handle table.
182 * HandleTable [I/O] The handle table.
183 * HandleIndex [O] Index of the handle returned. Optional.
186 * Success: Pointer to allocated handle.
190 * A valid handle must have the bit set as indicated in the code below
191 * otherwise subsequent RtlIsValidHandle() calls will fail.
193 * static inline void RtlpMakeHandleAllocated(RTL_HANDLE * Handle)
195 * ULONG_PTR *AllocatedBit = (ULONG_PTR *)(&Handle->Next);
196 * *AllocatedBit = *AllocatedBit | 1;
202 RTL_HANDLE
* WINAPI
RtlAllocateHandle(RTL_HANDLE_TABLE
* HandleTable
, ULONG
* HandleIndex
)
206 TRACE("(%p, %p)\n", HandleTable
, HandleIndex
);
208 if (!HandleTable
->NextFree
&& RtlpAllocateSomeHandles(HandleTable
) != STATUS_SUCCESS
)
211 ret
= HandleTable
->NextFree
;
212 HandleTable
->NextFree
= ret
->Next
;
215 *HandleIndex
= (ULONG
)(((PCHAR
)ret
- (PCHAR
)HandleTable
->FirstHandle
) / HandleTable
->HandleSize
);
220 /**************************************************************************
221 * RtlFreeHandle (NTDLL.@)
223 * Frees an allocated handle.
226 * HandleTable [I/O] The handle table.
227 * Handle [I] The handle to be freed.
234 * RtlAllocateHandle().
236 BOOLEAN WINAPI
RtlFreeHandle(RTL_HANDLE_TABLE
* HandleTable
, RTL_HANDLE
* Handle
)
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
;
249 /**************************************************************************
250 * RtlIsValidHandle (NTDLL.@)
252 * Determines whether a handle is valid or not.
255 * HandleTable [I] The handle table.
256 * Handle [I] The handle to be tested.
262 BOOLEAN WINAPI
RtlIsValidHandle(const RTL_HANDLE_TABLE
* HandleTable
, const RTL_HANDLE
* Handle
)
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))
277 /**************************************************************************
278 * RtlIsValidIndexHandle (NTDLL.@)
280 * Determines whether a handle index is valid or not.
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.
291 BOOLEAN WINAPI
RtlIsValidIndexHandle(const RTL_HANDLE_TABLE
* HandleTable
, ULONG Index
, RTL_HANDLE
** ValidHandle
)
295 TRACE("(%p, %u, %p)\n", HandleTable
, Index
, ValidHandle
);
296 Handle
= (RTL_HANDLE
*)
297 ((char *)HandleTable
->FirstHandle
+ Index
* HandleTable
->HandleSize
);
299 if (RtlIsValidHandle(HandleTable
, Handle
))
301 *ValidHandle
= Handle
;