2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
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.
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.
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.
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)
28 * 06-06-2001 CSH Ported kernel object manager
30 /* INCLUDES ******************************************************************/
32 #include <ddk/ntddk.h>
33 #include <include/object.h>
38 /* FUNCTIONS *****************************************************************/
41 HEADER_TO_BODY(PUSER_OBJECT_HEADER ObjectHeader)
43 return (((PUSER_OBJECT_HEADER)ObjectHeader) + 1);
46 PUSER_OBJECT_HEADER FASTCALL
47 BODY_TO_HEADER(PVOID ObjectBody)
49 return (((PUSER_OBJECT_HEADER)ObjectBody) - 1);
53 ObmpLockHandleTable(PUSER_HANDLE_TABLE HandleTable)
55 ExAcquireFastMutex(&HandleTable->ListLock);
59 ObmpUnlockHandleTable(PUSER_HANDLE_TABLE HandleTable)
61 ExReleaseFastMutex(&HandleTable->ListLock);
65 ObmpPerformRetentionChecks(PUSER_OBJECT_HEADER ObjectHeader)
67 if (ObjectHeader->RefCount < 0)
69 DbgPrint("ObjectHeader 0x%X has invalid reference count (%d)\n",
70 ObjectHeader, ObjectHeader->RefCount);
73 if (ObjectHeader->HandleCount < 0)
75 DbgPrint("Object 0x%X has invalid handle count (%d)\n",
76 ObjectHeader, ObjectHeader->HandleCount);
79 if ((ObjectHeader->RefCount == 0) && (ObjectHeader->HandleCount == 0))
81 ExFreePool(ObjectHeader);
86 ObmpGetObjectByHandle(PUSER_HANDLE_TABLE HandleTable,
89 * FUNCTION: Get the data structure for a handle
91 * HandleTable = Table to search
92 * Handle = Handle to get data structure for
94 * Pointer to the data structure identified by the handle on success,
98 ULONG Index = (((ULONG)Handle) >> 2) - 1;
99 ULONG Count = Index / HANDLE_BLOCK_ENTRIES;
100 PUSER_HANDLE_BLOCK Block = NULL;
104 Current = HandleTable->ListHead.Flink;
106 for (i = 0; i < Count; i++)
108 Current = Current->Flink;
109 if (Current == &(HandleTable->ListHead))
115 Block = CONTAINING_RECORD(Current, USER_HANDLE_BLOCK, ListEntry);
116 return &(Block->Handles[Index % HANDLE_BLOCK_ENTRIES]);
120 ObmpCloseAllHandles(PUSER_HANDLE_TABLE HandleTable)
122 PLIST_ENTRY CurrentEntry;
123 PUSER_HANDLE_BLOCK Current;
127 ObmpLockHandleTable(HandleTable);
129 CurrentEntry = HandleTable->ListHead.Flink;
131 while (CurrentEntry != &HandleTable->ListHead)
133 Current = CONTAINING_RECORD(CurrentEntry, USER_HANDLE_BLOCK, ListEntry);
135 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
137 ObjectBody = Current->Handles[i].ObjectBody;
139 if (ObjectBody != NULL)
141 PUSER_OBJECT_HEADER ObjectHeader = BODY_TO_HEADER(ObjectBody);
143 ObmReferenceObjectByPointer(ObjectBody, otUnknown);
144 ObjectHeader->HandleCount--;
145 Current->Handles[i].ObjectBody = NULL;
147 ObmpUnlockHandleTable(HandleTable);
149 ObmDereferenceObject(ObjectBody);
151 ObmpLockHandleTable(HandleTable);
152 CurrentEntry = &HandleTable->ListHead;
157 CurrentEntry = CurrentEntry->Flink;
160 ObmpUnlockHandleTable(HandleTable);
164 ObmpDeleteHandleTable(PUSER_HANDLE_TABLE HandleTable)
166 PUSER_HANDLE_BLOCK Current;
167 PLIST_ENTRY CurrentEntry;
169 ObmpCloseAllHandles(HandleTable);
171 CurrentEntry = RemoveHeadList(&HandleTable->ListHead);
173 while (CurrentEntry != &HandleTable->ListHead)
175 Current = CONTAINING_RECORD(CurrentEntry,
181 CurrentEntry = RemoveHeadList(&HandleTable->ListHead);
186 ObmpDeleteHandle(PUSER_HANDLE_TABLE HandleTable,
189 PUSER_OBJECT_HEADER ObjectHeader;
193 ObmpLockHandleTable(HandleTable);
195 Entry = ObmpGetObjectByHandle(HandleTable, Handle);
198 ObmpUnlockHandleTable(HandleTable);
202 ObjectBody = Entry->ObjectBody;
204 if (ObjectBody != NULL)
206 ObjectHeader = BODY_TO_HEADER(ObjectBody);
207 ObjectHeader->HandleCount--;
208 ObmReferenceObjectByPointer(ObjectBody, otUnknown);
209 Entry->ObjectBody = NULL;
212 ObmpUnlockHandleTable(HandleTable);
218 ObmpInitializeObject(PUSER_HANDLE_TABLE HandleTable,
219 PUSER_OBJECT_HEADER ObjectHeader,
221 USER_OBJECT_TYPE ObjectType,
224 DWORD Status = STATUS_SUCCESS;
226 ObjectHeader->Type = ObjectType;
227 ObjectHeader->HandleCount = 0;
228 ObjectHeader->RefCount = 1;
229 ObjectHeader->Size = ObjectSize;
233 Status = ObmCreateHandle(HandleTable,
234 HEADER_TO_BODY(ObjectHeader),
243 ObmGetReferenceCount(PVOID ObjectBody)
245 PUSER_OBJECT_HEADER ObjectHeader = BODY_TO_HEADER(ObjectBody);
247 return ObjectHeader->RefCount;
251 ObmGetHandleCount(PVOID ObjectBody)
253 PUSER_OBJECT_HEADER ObjectHeader = BODY_TO_HEADER(ObjectBody);
255 return ObjectHeader->HandleCount;
259 ObmReferenceObject(PVOID ObjectBody)
261 * FUNCTION: Increments a given object's reference count and performs
264 * ObjectBody = Body of the object
267 PUSER_OBJECT_HEADER ObjectHeader;
274 ObjectHeader = BODY_TO_HEADER(ObjectBody);
276 ObjectHeader->RefCount++;
278 ObmpPerformRetentionChecks(ObjectHeader);
282 ObmDereferenceObject(PVOID ObjectBody)
284 * FUNCTION: Decrements a given object's reference count and performs
287 * ObjectBody = Body of the object
290 PUSER_OBJECT_HEADER ObjectHeader;
297 ObjectHeader = BODY_TO_HEADER(ObjectBody);
299 ObjectHeader->RefCount--;
301 ObmpPerformRetentionChecks(ObjectHeader);
305 ObmReferenceObjectByPointer(PVOID ObjectBody,
306 USER_OBJECT_TYPE ObjectType)
308 * FUNCTION: Increments the pointer reference count for a given object
310 * ObjectBody = Object's body
311 * ObjectType = Object type
315 PUSER_OBJECT_HEADER ObjectHeader;
317 ObjectHeader = BODY_TO_HEADER(ObjectBody);
319 if ((ObjectType != otUnknown) && (ObjectHeader->Type != ObjectType))
321 return STATUS_INVALID_PARAMETER;
324 ObjectHeader->RefCount++;
326 return STATUS_SUCCESS;
330 ObmCreateObject(PUSER_HANDLE_TABLE HandleTable,
332 USER_OBJECT_TYPE ObjectType,
335 PUSER_OBJECT_HEADER ObjectHeader;
339 ObjectHeader = (PUSER_OBJECT_HEADER)ExAllocatePool(NonPagedPool,
340 ObjectSize + sizeof(USER_OBJECT_HEADER));
346 ObjectBody = HEADER_TO_BODY(ObjectHeader);
348 RtlZeroMemory(ObjectBody, ObjectSize);
350 Status = ObmpInitializeObject(HandleTable,
356 if (!NT_SUCCESS(Status))
358 ExFreePool(ObjectHeader);
366 ObmCreateHandle(PUSER_HANDLE_TABLE HandleTable,
368 PHANDLE HandleReturn)
370 * FUNCTION: Add a handle referencing an object
372 * HandleTable = Table to put handle in
373 * ObjectBody = Object body that the handle should refer to
374 * RETURNS: The created handle
377 PUSER_HANDLE_BLOCK NewBlock;
382 if (ObjectBody != NULL)
384 BODY_TO_HEADER(ObjectBody)->HandleCount++;
387 ObmpLockHandleTable(HandleTable);
390 Current = HandleTable->ListHead.Flink;
392 * Scan through the currently allocated Handle blocks looking for a free
395 while (Current != &(HandleTable->ListHead))
397 PUSER_HANDLE_BLOCK Block =
398 CONTAINING_RECORD(Current, USER_HANDLE_BLOCK, ListEntry);
400 for (i = 0; i < HANDLE_BLOCK_ENTRIES; i++)
402 if (!Block->Handles[i].ObjectBody)
404 Block->Handles[i].ObjectBody = ObjectBody;
405 ObmpUnlockHandleTable(HandleTable);
406 *HandleReturn = (HANDLE)((Handle + i) << 2);
407 return ERROR_SUCCESS;
411 Handle = Handle + HANDLE_BLOCK_ENTRIES;
412 Current = Current->Flink;
416 * Add a new Handle block to the end of the list
418 NewBlock = (PUSER_HANDLE_BLOCK)ExAllocatePool(NonPagedPool,
419 sizeof(USER_HANDLE_BLOCK));
422 *HandleReturn = (PHANDLE)NULL;
423 return STATUS_INSUFFICIENT_RESOURCES;
426 RtlZeroMemory(NewBlock, sizeof(USER_HANDLE_BLOCK));
427 NewBlock->Handles[0].ObjectBody = ObjectBody;
428 InsertTailList(&HandleTable->ListHead, &NewBlock->ListEntry);
429 ObmpUnlockHandleTable(HandleTable);
430 *HandleReturn = (HANDLE)(Handle << 2);
432 return STATUS_SUCCESS;
436 ObmReferenceObjectByHandle(PUSER_HANDLE_TABLE HandleTable,
438 USER_OBJECT_TYPE ObjectType,
441 * FUNCTION: Increments the reference count for an object and returns a
442 * pointer to its body
444 * HandleTable = Table to search
445 * Handle = Handle for the object
446 * ObjectType = Type of object
447 * Object (OUT) = Points to the object body on return
451 PUSER_OBJECT_HEADER ObjectHeader;
452 PUSER_HANDLE UserHandle;
455 ObmpLockHandleTable(HandleTable);
457 UserHandle = ObmpGetObjectByHandle(HandleTable, Handle);
459 if ((UserHandle == NULL) || (UserHandle->ObjectBody == NULL))
461 ObmpUnlockHandleTable(HandleTable);
462 return STATUS_UNSUCCESSFUL;
465 ObjectBody = UserHandle->ObjectBody;
466 ObmReferenceObjectByPointer(ObjectBody, ObjectType);
468 ObmpUnlockHandleTable(HandleTable);
470 ObjectHeader = BODY_TO_HEADER(ObjectBody);
472 if ((ObjectType != otUnknown) && (ObjectHeader->Type != ObjectType))
474 return STATUS_UNSUCCESSFUL;
477 *Object = ObjectBody;
479 return STATUS_SUCCESS;
483 ObmCloseHandle(PUSER_HANDLE_TABLE HandleTable,
488 ObjectBody = ObmpDeleteHandle(HandleTable, Handle);
489 if (ObjectBody == NULL)
491 return STATUS_UNSUCCESSFUL;
494 ObmDereferenceObject(ObjectBody);
496 return STATUS_SUCCESS;
500 ObmInitializeHandleTable(PUSER_HANDLE_TABLE HandleTable)
502 InitializeListHead(&HandleTable->ListHead);
503 ExInitializeFastMutex(&HandleTable->ListLock);
507 ObmFreeHandleTable(PUSER_HANDLE_TABLE HandleTable)
509 ObmpDeleteHandleTable(HandleTable);
512 PUSER_HANDLE_TABLE FASTCALL
513 ObmCreateHandleTable(VOID)
515 PUSER_HANDLE_TABLE HandleTable;
517 HandleTable = (PUSER_HANDLE_TABLE)ExAllocatePool(NonPagedPool,
518 sizeof(USER_HANDLE_TABLE));
524 ObmInitializeHandleTable(HandleTable);
530 ObmDestroyHandleTable(PUSER_HANDLE_TABLE HandleTable)
532 ObmFreeHandleTable(HandleTable);
533 ExFreePool(HandleTable);