Convert a WARN to a FIXME to make it visible to a user, replace an ERR
[wine/multimedia.git] / dlls / ntdll / handletable.c
blobeb901ffb4aab830c1016544288ab3866df3b8d10
1 /*
2 * Handle Tables
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
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winternl.h"
25 #include "wine/debug.h"
26 #include "ntdll_misc.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(ntdll);
30 /**************************************************************************
31 * RtlInitializeHandleTable (NTDLL.@)
33 * Initializes a handle table.
35 * PARAMS
36 * MaxHandleCount [I] The maximum number of handles the handle table will support.
37 * HandleSize [I] The size of each handle.
38 * HandleTable [I/O] The handle table.
40 * RETURNS
41 * Nothing.
43 * SEE
44 * RtlDestroyHandleTable().
46 void WINAPI RtlInitializeHandleTable(ULONG MaxHandleCount, ULONG HandleSize, RTL_HANDLE_TABLE * HandleTable)
48 TRACE("(%lu, %lu, %p)\n", MaxHandleCount, HandleSize, HandleTable);
50 memset(HandleTable, 0, sizeof(*HandleTable));
51 HandleTable->MaxHandleCount = MaxHandleCount;
52 HandleTable->HandleSize = HandleSize;
55 /**************************************************************************
56 * RtlDestroyHandleTable (NTDLL.@)
58 * Destroys a handle table and frees associated resources.
60 * PARAMS
61 * HandleTable [I] The handle table.
63 * RETURNS
64 * Any status code returned by NtFreeVirtualMemory().
66 * NOTES
67 * The native version of this API doesn't free the virtual memory that has
68 * been previously reserved, only the committed memory. There is no harm
69 * in also freeing the reserved memory because it won't have been handed out
70 * to any callers. I believe it is "more polite" to free everything.
72 * SEE
73 * RtlInitializeHandleTable().
75 NTSTATUS WINAPI RtlDestroyHandleTable(RTL_HANDLE_TABLE * HandleTable)
77 SIZE_T Size = 0;
79 TRACE("(%p)\n", HandleTable);
81 /* native version only releases committed memory, but we also release reserved */
82 return NtFreeVirtualMemory(
83 NtCurrentProcess(),
84 &HandleTable->FirstHandle,
85 &Size,
86 MEM_RELEASE);
89 /**************************************************************************
90 * RtlpAllocateSomeHandles (internal)
92 * Reserves memory for the handles if not previously done and commits memory
93 * for a batch of handles if none are free and adds them to the free list.
95 * PARAMS
96 * HandleTable [I/O] The handle table.
98 * RETURNS
99 * NTSTATUS code.
101 static NTSTATUS RtlpAllocateSomeHandles(RTL_HANDLE_TABLE * HandleTable)
103 NTSTATUS status;
104 if (!HandleTable->FirstHandle)
106 PVOID FirstHandleAddr = NULL;
107 SIZE_T MaxSize = HandleTable->MaxHandleCount * HandleTable->HandleSize;
109 /* reserve memory for the handles, but don't commit it yet because we
110 * probably won't use most of it and it will use up physical memory */
111 status = NtAllocateVirtualMemory(
112 NtCurrentProcess(),
113 &FirstHandleAddr,
115 &MaxSize,
116 MEM_RESERVE,
117 PAGE_READWRITE);
118 if (status != STATUS_SUCCESS)
119 return status;
120 HandleTable->FirstHandle = FirstHandleAddr;
121 HandleTable->ReservedMemory = HandleTable->FirstHandle;
122 HandleTable->MaxHandle = (char *)HandleTable->FirstHandle + MaxSize;
124 if (!HandleTable->NextFree)
126 SIZE_T Offset, CommitSize = 4096; /* one page */
127 RTL_HANDLE * FreeHandle = NULL;
128 PVOID NextAvailAddr = HandleTable->ReservedMemory;
130 if (HandleTable->ReservedMemory >= HandleTable->MaxHandle)
131 return STATUS_NO_MEMORY; /* the handle table is completely full */
133 status = NtAllocateVirtualMemory(
134 NtCurrentProcess(),
135 &NextAvailAddr,
137 &CommitSize,
138 MEM_COMMIT,
139 PAGE_READWRITE);
140 if (status != STATUS_SUCCESS)
141 return status;
143 for (Offset = 0; Offset < CommitSize; Offset += HandleTable->HandleSize)
145 /* make sure we don't go over handle limit, even if we can
146 * because of rounding of the table size up to the next page
147 * boundary */
148 if ((char *)HandleTable->ReservedMemory + Offset >= (char *)HandleTable->MaxHandle)
149 break;
151 FreeHandle = (RTL_HANDLE *)((char *)HandleTable->ReservedMemory + Offset);
153 FreeHandle->Next = (RTL_HANDLE *)((char *)HandleTable->ReservedMemory +
154 Offset + HandleTable->HandleSize);
157 /* shouldn't happen because we already test for this above, but
158 * handle it just in case */
159 if (!FreeHandle)
160 return STATUS_NO_MEMORY;
162 /* set the last handle's Next pointer to NULL so that when we run
163 * out of free handles we trigger another commit of memory and
164 * initialize the free pointers */
165 FreeHandle->Next = NULL;
167 HandleTable->NextFree = HandleTable->ReservedMemory;
169 HandleTable->ReservedMemory = (char *)HandleTable->ReservedMemory + CommitSize;
171 return STATUS_SUCCESS;
174 /**************************************************************************
175 * RtlAllocateHandle (NTDLL.@)
177 * Allocates a handle from the handle table.
179 * PARAMS
180 * HandleTable [I/O] The handle table.
181 * HandleIndex [O] Index of the handle returned. Optional.
183 * RETURNS
184 * Success: Pointer to allocated handle.
185 * Failure: NULL.
187 * SEE
188 * RtlFreeHandle().
190 RTL_HANDLE * WINAPI RtlAllocateHandle(RTL_HANDLE_TABLE * HandleTable, ULONG * HandleIndex)
192 RTL_HANDLE * ret;
194 TRACE("(%p, %p)\n", HandleTable, HandleIndex);
196 if (!HandleTable->NextFree && RtlpAllocateSomeHandles(HandleTable) != STATUS_SUCCESS)
197 return NULL;
199 ret = (RTL_HANDLE *)HandleTable->NextFree;
200 HandleTable->NextFree = ret->Next;
202 if (HandleIndex)
203 *HandleIndex = (ULONG)(((PCHAR)ret - (PCHAR)HandleTable->FirstHandle) / HandleTable->HandleSize);
205 return ret;
208 /**************************************************************************
209 * RtlFreeHandle (NTDLL.@)
211 * Frees an allocated handle.
213 * PARAMS
214 * HandleTable [I/O] The handle table.
215 * Handle [I] The handle to be freed.
217 * RETURNS
218 * Success: TRUE.
219 * Failure: FALSE.
221 * SEE
222 * RtlAllocateHandle().
224 BOOLEAN WINAPI RtlFreeHandle(RTL_HANDLE_TABLE * HandleTable, RTL_HANDLE * Handle)
226 TRACE("(%p, %p)\n", HandleTable, Handle);
227 /* NOTE: we don't validate the handle and we don't make Handle->Next even
228 * again to signal that it is no longer in user - that is done as a side
229 * effect of setting Handle->Next to the previously next free handle in
230 * the handle table */
231 memset(Handle, 0, HandleTable->HandleSize);
232 Handle->Next = (RTL_HANDLE *)HandleTable->NextFree;
233 HandleTable->NextFree = Handle;
234 return TRUE;
237 /**************************************************************************
238 * RtlIsValidHandle (NTDLL.@)
240 * Determines whether a handle is valid or not.
242 * PARAMS
243 * HandleTable [I] The handle table.
244 * Handle [I] The handle to be tested.
246 * RETURNS
247 * Valid: TRUE.
248 * Invalid: FALSE.
250 BOOLEAN WINAPI RtlIsValidHandle(const RTL_HANDLE_TABLE * HandleTable, const RTL_HANDLE * Handle)
252 TRACE("(%p, %p)\n", HandleTable, Handle);
253 /* make sure handle is within used region and that it is aligned on
254 * a HandleTable->HandleSize boundary and that Handle->Next is odd,
255 * indicating that the handle is active */
256 if ((Handle >= (RTL_HANDLE *)HandleTable->FirstHandle) &&
257 (Handle < (RTL_HANDLE *)HandleTable->ReservedMemory) &&
258 !((ULONG_PTR)Handle & (HandleTable->HandleSize - 1)) &&
259 ((ULONG_PTR)Handle->Next & 1))
260 return TRUE;
261 else
262 return FALSE;
265 /**************************************************************************
266 * RtlIsValidIndexHandle (NTDLL.@)
268 * Determines whether a handle index is valid or not.
270 * PARAMS
271 * HandleTable [I] The handle table.
272 * Index [I] The index of the handle to be tested.
273 * ValidHandle [O] The handle Index refers to.
275 * RETURNS
276 * Valid: TRUE.
277 * Invalid: FALSE.
279 BOOLEAN WINAPI RtlIsValidIndexHandle(const RTL_HANDLE_TABLE * HandleTable, ULONG Index, RTL_HANDLE ** ValidHandle)
281 RTL_HANDLE * Handle;
283 TRACE("(%p, %lu, %p)\n", HandleTable, Index, ValidHandle);
284 Handle = (RTL_HANDLE *)
285 ((char *)HandleTable->FirstHandle + Index * HandleTable->HandleSize);
287 if (RtlIsValidHandle(HandleTable, Handle))
289 *ValidHandle = Handle;
290 return TRUE;
292 return FALSE;