- fixed handle table structures
[reactos.git] / reactos / subsys / win32k / misc / object.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: User object manager
24 * FILE: subsys/win32k/misc/object.c
25 * PROGRAMMERS: David Welch (welch@cwcom.net)
26 * Casper S. Hornstrup (chorns@users.sourceforge.net)
27 * UPDATE HISTORY:
28 * 06-06-2001 CSH Ported kernel object manager
29 */
30 /* INCLUDES ******************************************************************/
31
32 #include <w32k.h>
33
34 #define NDEBUG
35 #include <debug.h>
36
37 #define USER_HEADER_TO_BODY(ObjectHeader) \
38 ((PVOID)(((PUSER_OBJECT_HEADER)ObjectHeader) + 1))
39
40 #define USER_BODY_TO_HEADER(ObjectBody) \
41 ((PUSER_OBJECT_HEADER)(((PUSER_OBJECT_HEADER)ObjectBody) - 1))
42
43 /* FUNCTIONS *****************************************************************/
44
45 VOID FASTCALL
46 ObmpPerformRetentionChecks(PUSER_OBJECT_HEADER ObjectHeader)
47 {
48 if (ObjectHeader->RefCount < 0)
49 {
50 DPRINT1("ObjectHeader 0x%X has invalid reference count (%d)\n",
51 ObjectHeader, ObjectHeader->RefCount);
52 }
53
54 if (ObjectHeader->HandleCount < 0)
55 {
56 DPRINT1("Object 0x%X has invalid handle count (%d)\n",
57 ObjectHeader, ObjectHeader->HandleCount);
58 }
59
60 if ((ObjectHeader->RefCount == 0) && (ObjectHeader->HandleCount == 0))
61 {
62 ExFreePool(ObjectHeader);
63 }
64 }
65
66 PUSER_HANDLE FASTCALL
67 ObmpGetObjectByHandle(PUSER_HANDLE_TABLE HandleTable,
68 HANDLE Handle)
69 /*
70 * FUNCTION: Get the data structure for a handle
71 * ARGUMENTS:
72 * HandleTable = Table to search
73 * Handle = Handle to get data structure for
74 * RETURNS:
75 * Pointer to the data structure identified by the handle on success,
76 * NULL on failure
77 */
78 {
79 ULONG Index = (((ULONG)Handle) >> 2) - 1;
80 ULONG Count = Index / HANDLE_BLOCK_ENTRIES;
81 PUSER_HANDLE_BLOCK Block = NULL;
82 PLIST_ENTRY Current;
83 ULONG i;
84
85 if (NULL == Handle)
86 {
87 return NULL;
88 }
89
90 Current = HandleTable->ListHead.Flink;
91
92 for (i = 0; i < Count; i++)
93 {
94 Current = Current->Flink;
95 if (Current == &(HandleTable->ListHead))
96 {
97 DPRINT1("Invalid handle 0x%x\n", Handle);
98 return NULL;
99 }
100 }
101
102 Block = CONTAINING_RECORD(Current, USER_HANDLE_BLOCK, ListEntry);
103 return &(Block->Handles[Index % HANDLE_BLOCK_ENTRIES]);
104 }
105
106 VOID FASTCALL
107 ObmpCloseAllHandles(PUSER_HANDLE_TABLE HandleTable)
108 {
109 PLIST_ENTRY CurrentEntry;
110 PUSER_HANDLE_BLOCK Current;
111 PVOID ObjectBody;
112 ULONG i;
113
114 ObmpLockHandleTable(HandleTable);
115
116 CurrentEntry = HandleTable->ListHead.Flink;
117
118 while (CurrentEntry != &HandleTable->ListHead)
119 {
120 Current = CONTAINING_RECORD(CurrentEntry, USER_HANDLE_BLOCK, ListEntry);
121
122 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
123 {
124 ObjectBody = Current->Handles[i].ObjectBody;
125
126 if (ObjectBody != NULL)
127 {
128 PUSER_OBJECT_HEADER ObjectHeader = USER_BODY_TO_HEADER(ObjectBody);
129
130 ObmReferenceObjectByPointer(ObjectBody, otUnknown);
131 ObjectHeader->HandleCount--;
132 Current->Handles[i].ObjectBody = NULL;
133
134 ObmpUnlockHandleTable(HandleTable);
135
136 ObmDereferenceObject(ObjectBody);
137
138 ObmpLockHandleTable(HandleTable);
139 CurrentEntry = &HandleTable->ListHead;
140 break;
141 }
142 }
143
144 CurrentEntry = CurrentEntry->Flink;
145 }
146
147 ObmpUnlockHandleTable(HandleTable);
148 }
149
150 VOID FASTCALL
151 ObmpDeleteHandleTable(PUSER_HANDLE_TABLE HandleTable)
152 {
153 PUSER_HANDLE_BLOCK Current;
154 PLIST_ENTRY CurrentEntry;
155
156 ObmpCloseAllHandles(HandleTable);
157
158 CurrentEntry = RemoveHeadList(&HandleTable->ListHead);
159
160 while (CurrentEntry != &HandleTable->ListHead)
161 {
162 Current = CONTAINING_RECORD(CurrentEntry,
163 USER_HANDLE_BLOCK,
164 ListEntry);
165
166 ExFreePool(Current);
167
168 CurrentEntry = RemoveHeadList(&HandleTable->ListHead);
169 }
170 }
171
172 PVOID FASTCALL
173 ObmpDeleteHandle(PUSER_HANDLE_TABLE HandleTable,
174 HANDLE Handle)
175 {
176 PUSER_OBJECT_HEADER ObjectHeader;
177 PUSER_HANDLE Entry;
178 PVOID ObjectBody;
179
180 ObmpLockHandleTable(HandleTable);
181
182 Entry = ObmpGetObjectByHandle(HandleTable, Handle);
183 if (Entry == NULL)
184 {
185 DPRINT1("Invalid handle\n");
186 ObmpUnlockHandleTable(HandleTable);
187 return NULL;
188 }
189
190 ObjectBody = Entry->ObjectBody;
191
192 if (ObjectBody != NULL)
193 {
194 ObjectHeader = USER_BODY_TO_HEADER(ObjectBody);
195 ObjectHeader->HandleCount--;
196 ObmReferenceObjectByPointer(ObjectBody, otUnknown);
197 Entry->ObjectBody = NULL;
198 }
199
200 ObmpUnlockHandleTable(HandleTable);
201
202 return ObjectBody;
203 }
204
205 NTSTATUS FASTCALL
206 ObmpInitializeObject(PUSER_HANDLE_TABLE HandleTable,
207 PUSER_OBJECT_HEADER ObjectHeader,
208 PHANDLE Handle,
209 USER_OBJECT_TYPE ObjectType,
210 ULONG ObjectSize)
211 {
212 DWORD Status = STATUS_SUCCESS;
213
214 ObjectHeader->Type = ObjectType;
215 ObjectHeader->HandleCount = 0;
216 ObjectHeader->RefCount = 1;
217 ObjectHeader->Size = ObjectSize;
218
219 if (Handle != NULL)
220 {
221 Status = ObmCreateHandle(HandleTable,
222 USER_HEADER_TO_BODY(ObjectHeader),
223 Handle);
224 }
225
226 return Status;
227 }
228
229
230 ULONG FASTCALL
231 ObmGetReferenceCount(PVOID ObjectBody)
232 {
233 PUSER_OBJECT_HEADER ObjectHeader = USER_BODY_TO_HEADER(ObjectBody);
234
235 return ObjectHeader->RefCount;
236 }
237
238 ULONG FASTCALL
239 ObmGetHandleCount(PVOID ObjectBody)
240 {
241 PUSER_OBJECT_HEADER ObjectHeader = USER_BODY_TO_HEADER(ObjectBody);
242
243 return ObjectHeader->HandleCount;
244 }
245
246 VOID FASTCALL
247 ObmReferenceObject(PVOID ObjectBody)
248 /*
249 * FUNCTION: Increments a given object's reference count and performs
250 * retention checks
251 * ARGUMENTS:
252 * ObjectBody = Body of the object
253 */
254 {
255 PUSER_OBJECT_HEADER ObjectHeader;
256
257 if (!ObjectBody)
258 {
259 DPRINT1("Cannot Reference NULL!\n");
260 return;
261 }
262
263 ObjectHeader = USER_BODY_TO_HEADER(ObjectBody);
264
265 ObjectHeader->RefCount++;
266
267 ObmpPerformRetentionChecks(ObjectHeader);
268 }
269
270 VOID FASTCALL
271 ObmDereferenceObject(PVOID ObjectBody)
272 /*
273 * FUNCTION: Decrements a given object's reference count and performs
274 * retention checks
275 * ARGUMENTS:
276 * ObjectBody = Body of the object
277 */
278 {
279 PUSER_OBJECT_HEADER ObjectHeader;
280
281 if (!ObjectBody)
282 {
283 DPRINT1("Cannot Dereference NULL!\n");
284 return;
285 }
286
287 ObjectHeader = USER_BODY_TO_HEADER(ObjectBody);
288
289 ObjectHeader->RefCount--;
290 ObmpPerformRetentionChecks(ObjectHeader);
291 }
292
293 NTSTATUS FASTCALL
294 ObmReferenceObjectByPointer(PVOID ObjectBody,
295 USER_OBJECT_TYPE ObjectType)
296 /*
297 * FUNCTION: Increments the pointer reference count for a given object
298 * ARGUMENTS:
299 * ObjectBody = Object's body
300 * ObjectType = Object type
301 * RETURNS: Status
302 */
303 {
304 PUSER_OBJECT_HEADER ObjectHeader;
305
306 ObjectHeader = USER_BODY_TO_HEADER(ObjectBody);
307
308 if ((ObjectType != otUnknown) && (ObjectHeader->Type != ObjectType))
309 {
310 return STATUS_INVALID_PARAMETER;
311 }
312 ObjectHeader->RefCount++;
313
314 return STATUS_SUCCESS;
315 }
316
317 PVOID FASTCALL
318 ObmCreateObject(PUSER_HANDLE_TABLE HandleTable,
319 PHANDLE Handle,
320 USER_OBJECT_TYPE ObjectType,
321 ULONG ObjectSize)
322 {
323 PUSER_OBJECT_HEADER ObjectHeader;
324 PVOID ObjectBody;
325 DWORD Status;
326
327 ObjectHeader = (PUSER_OBJECT_HEADER)ExAllocatePool(PagedPool,
328 ObjectSize + sizeof(USER_OBJECT_HEADER));
329 if (!ObjectHeader)
330 {
331 return NULL;
332 }
333
334 ObjectBody = USER_HEADER_TO_BODY(ObjectHeader);
335
336 RtlZeroMemory(ObjectBody, ObjectSize);
337
338 Status = ObmpInitializeObject(HandleTable,
339 ObjectHeader,
340 Handle,
341 ObjectType,
342 ObjectSize);
343
344 if (!NT_SUCCESS(Status))
345 {
346 ExFreePool(ObjectHeader);
347 return NULL;
348 }
349
350 return ObjectBody;
351 }
352
353 NTSTATUS FASTCALL
354 ObmCreateHandle(PUSER_HANDLE_TABLE HandleTable,
355 PVOID ObjectBody,
356 PHANDLE HandleReturn)
357 /*
358 * FUNCTION: Add a handle referencing an object
359 * ARGUMENTS:
360 * HandleTable = Table to put handle in
361 * ObjectBody = Object body that the handle should refer to
362 * RETURNS: The created handle
363 */
364 {
365 PUSER_HANDLE_BLOCK NewBlock;
366 PLIST_ENTRY Current;
367 ULONG Handle;
368 ULONG i;
369
370 if (ObjectBody != NULL)
371 {
372 USER_BODY_TO_HEADER(ObjectBody)->HandleCount++;
373 }
374
375 ObmpLockHandleTable(HandleTable);
376
377 Handle = 1;
378 Current = HandleTable->ListHead.Flink;
379 /*
380 * Scan through the currently allocated Handle blocks looking for a free
381 * slot
382 */
383 while (Current != &(HandleTable->ListHead))
384 {
385 PUSER_HANDLE_BLOCK Block =
386 CONTAINING_RECORD(Current, USER_HANDLE_BLOCK, ListEntry);
387
388 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
389 {
390 if (!Block->Handles[i].ObjectBody)
391 {
392 Block->Handles[i].ObjectBody = ObjectBody;
393 ObmpUnlockHandleTable(HandleTable);
394 *HandleReturn = (HANDLE)((Handle + i) << 2);
395 return STATUS_SUCCESS;
396 }
397 }
398
399 Handle = Handle + HANDLE_BLOCK_ENTRIES;
400 Current = Current->Flink;
401 }
402
403 /*
404 * Add a new Handle block to the end of the list
405 */
406 NewBlock = (PUSER_HANDLE_BLOCK)ExAllocatePool(PagedPool,
407 sizeof(USER_HANDLE_BLOCK));
408 if (!NewBlock)
409 {
410 DPRINT1("Unable to allocate new handle block\n");
411 *HandleReturn = (PHANDLE)NULL;
412 return STATUS_INSUFFICIENT_RESOURCES;
413 }
414
415 RtlZeroMemory(NewBlock, sizeof(USER_HANDLE_BLOCK));
416 NewBlock->Handles[0].ObjectBody = ObjectBody;
417 InsertTailList(&HandleTable->ListHead, &NewBlock->ListEntry);
418 ObmpUnlockHandleTable(HandleTable);
419 *HandleReturn = (HANDLE)(Handle << 2);
420
421 return STATUS_SUCCESS;
422 }
423
424 NTSTATUS FASTCALL
425 ObmReferenceObjectByHandle(PUSER_HANDLE_TABLE HandleTable,
426 HANDLE Handle,
427 USER_OBJECT_TYPE ObjectType,
428 PVOID* Object)
429 /*
430 * FUNCTION: Increments the reference count for an object and returns a
431 * pointer to its body
432 * ARGUMENTS:
433 * HandleTable = Table to search
434 * Handle = Handle for the object
435 * ObjectType = Type of object
436 * Object (OUT) = Points to the object body on return
437 * RETURNS: Status
438 */
439 {
440 PUSER_OBJECT_HEADER ObjectHeader;
441 PUSER_HANDLE UserHandle;
442 PVOID ObjectBody;
443
444 ObmpLockHandleTable(HandleTable);
445
446 UserHandle = ObmpGetObjectByHandle(HandleTable, Handle);
447
448 if ((UserHandle == NULL) || (UserHandle->ObjectBody == NULL))
449 {
450 ObmpUnlockHandleTable(HandleTable);
451 return STATUS_UNSUCCESSFUL;
452 }
453
454 ObjectBody = UserHandle->ObjectBody;
455 ObmReferenceObjectByPointer(ObjectBody, ObjectType);
456
457 ObmpUnlockHandleTable(HandleTable);
458
459 ObjectHeader = USER_BODY_TO_HEADER(ObjectBody);
460
461 if ((ObjectType != otUnknown) && (ObjectHeader->Type != ObjectType))
462 {
463 DPRINT1("Object type mismatch 0x%x 0x%x\n", ObjectType, ObjectHeader->Type);
464 return STATUS_UNSUCCESSFUL;
465 }
466
467 *Object = ObjectBody;
468
469 return STATUS_SUCCESS;
470 }
471
472 NTSTATUS FASTCALL
473 ObmCloseHandle(PUSER_HANDLE_TABLE HandleTable,
474 HANDLE Handle)
475 {
476 PVOID ObjectBody;
477
478 ObjectBody = ObmpDeleteHandle(HandleTable, Handle);
479 if (ObjectBody == NULL)
480 {
481 return STATUS_UNSUCCESSFUL;
482 }
483
484 ObmDereferenceObject(ObjectBody);
485
486 return STATUS_SUCCESS;
487 }
488
489 VOID FASTCALL
490 ObmInitializeHandleTable(PUSER_HANDLE_TABLE HandleTable)
491 {
492 InitializeListHead(&HandleTable->ListHead);
493 ExInitializeFastMutex(&HandleTable->ListLock);
494 }
495
496 VOID FASTCALL
497 ObmFreeHandleTable(PUSER_HANDLE_TABLE HandleTable)
498 {
499 ObmpDeleteHandleTable(HandleTable);
500 }
501
502 PUSER_HANDLE_TABLE FASTCALL
503 ObmCreateHandleTable(VOID)
504 {
505 PUSER_HANDLE_TABLE HandleTable;
506
507 HandleTable = (PUSER_HANDLE_TABLE)ExAllocatePool(PagedPool,
508 sizeof(USER_HANDLE_TABLE));
509 if (!HandleTable)
510 {
511 DPRINT1("Unable to create handle table\n");
512 return NULL;
513 }
514
515 ObmInitializeHandleTable(HandleTable);
516
517 return HandleTable;
518 }
519
520 VOID FASTCALL
521 ObmDestroyHandleTable(PUSER_HANDLE_TABLE HandleTable)
522 {
523 ObmFreeHandleTable(HandleTable);
524 ExFreePool(HandleTable);
525 }
526
527 /* EOF */