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 ******************************************************************/
37 #define USER_HEADER_TO_BODY(ObjectHeader) \
38 ((PVOID)(((PUSER_OBJECT_HEADER)ObjectHeader) + 1))
40 #define USER_BODY_TO_HEADER(ObjectBody) \
41 ((PUSER_OBJECT_HEADER)(((PUSER_OBJECT_HEADER)ObjectBody) - 1))
44 PUSER_HANDLE_TABLE gHandleTable
= NULL
;
46 /* FUNCTIONS *****************************************************************/
49 ObmpPerformRetentionChecks(PUSER_OBJECT_HEADER ObjectHeader
)
51 if (ObjectHeader
->RefCount
< 0)
53 DPRINT1("ObjectHeader 0x%X has invalid reference count (%d)\n",
54 ObjectHeader
, ObjectHeader
->RefCount
);
57 if (ObjectHeader
->HandleCount
< 0)
59 DPRINT1("Object 0x%X has invalid handle count (%d)\n",
60 ObjectHeader
, ObjectHeader
->HandleCount
);
63 if ((ObjectHeader
->RefCount
== 0) && (ObjectHeader
->HandleCount
== 0))
65 ExFreePool(ObjectHeader
);
70 ObmpGetObjectByHandle(PUSER_HANDLE_TABLE HandleTable
,
73 * FUNCTION: Get the data structure for a handle
75 * HandleTable = Table to search
76 * Handle = Handle to get data structure for
78 * Pointer to the data structure identified by the handle on success,
82 ULONG Index
= (((ULONG
)Handle
) >> 2) - 1;
83 ULONG Count
= Index
/ HANDLE_BLOCK_ENTRIES
;
84 PUSER_HANDLE_BLOCK Block
= NULL
;
93 Current
= HandleTable
->ListHead
.Flink
;
95 for (i
= 0; i
< Count
; i
++)
97 Current
= Current
->Flink
;
98 if (Current
== &(HandleTable
->ListHead
))
100 DPRINT1("Invalid handle 0x%x\n", Handle
);
105 Block
= CONTAINING_RECORD(Current
, USER_HANDLE_BLOCK
, ListEntry
);
106 return &(Block
->Handles
[Index
% HANDLE_BLOCK_ENTRIES
]);
110 ObmpCloseAllHandles(PUSER_HANDLE_TABLE HandleTable
)
112 PLIST_ENTRY CurrentEntry
;
113 PUSER_HANDLE_BLOCK Current
;
117 CurrentEntry
= HandleTable
->ListHead
.Flink
;
119 while (CurrentEntry
!= &HandleTable
->ListHead
)
121 Current
= CONTAINING_RECORD(CurrentEntry
, USER_HANDLE_BLOCK
, ListEntry
);
123 for (i
= 0; i
< HANDLE_BLOCK_ENTRIES
; i
++)
125 ObjectBody
= Current
->Handles
[i
].ObjectBody
;
127 if (ObjectBody
!= NULL
)
129 PUSER_OBJECT_HEADER ObjectHeader
= USER_BODY_TO_HEADER(ObjectBody
);
131 ObmReferenceObjectByPointer(ObjectBody
, otUnknown
);
132 ObjectHeader
->HandleCount
--;
133 Current
->Handles
[i
].ObjectBody
= NULL
;
135 ObmDereferenceObject(ObjectBody
);
137 CurrentEntry
= &HandleTable
->ListHead
;
142 CurrentEntry
= CurrentEntry
->Flink
;
148 ObmpDeleteHandleTable(PUSER_HANDLE_TABLE HandleTable
)
150 PUSER_HANDLE_BLOCK Current
;
151 PLIST_ENTRY CurrentEntry
;
153 ObmpCloseAllHandles(HandleTable
);
155 CurrentEntry
= RemoveHeadList(&HandleTable
->ListHead
);
157 while (CurrentEntry
!= &HandleTable
->ListHead
)
159 Current
= CONTAINING_RECORD(CurrentEntry
,
165 CurrentEntry
= RemoveHeadList(&HandleTable
->ListHead
);
170 ObmpDeleteHandle(PUSER_HANDLE_TABLE HandleTable
,
173 PUSER_OBJECT_HEADER ObjectHeader
;
177 Entry
= ObmpGetObjectByHandle(HandleTable
, Handle
);
180 DPRINT1("Invalid handle\n");
184 ObjectBody
= Entry
->ObjectBody
;
186 if (ObjectBody
!= NULL
)
188 ObjectHeader
= USER_BODY_TO_HEADER(ObjectBody
);
189 ObjectHeader
->HandleCount
--;
190 ObmReferenceObjectByPointer(ObjectBody
, otUnknown
);
191 Entry
->ObjectBody
= NULL
;
198 ObmpInitializeObject(PUSER_HANDLE_TABLE HandleTable
,
199 PUSER_OBJECT_HEADER ObjectHeader
,
201 USER_OBJECT_TYPE ObjectType
,
204 DWORD Status
= STATUS_SUCCESS
;
206 ObjectHeader
->Type
= ObjectType
;
207 ObjectHeader
->HandleCount
= 0;
208 ObjectHeader
->RefCount
= 1;
209 ObjectHeader
->Size
= ObjectSize
;
213 Status
= ObmCreateHandle(HandleTable
,
214 USER_HEADER_TO_BODY(ObjectHeader
),
223 ObmGetReferenceCount(PVOID ObjectBody
)
225 PUSER_OBJECT_HEADER ObjectHeader
= USER_BODY_TO_HEADER(ObjectBody
);
227 return ObjectHeader
->RefCount
;
231 ObmGetHandleCount(PVOID ObjectBody
)
233 PUSER_OBJECT_HEADER ObjectHeader
= USER_BODY_TO_HEADER(ObjectBody
);
235 return ObjectHeader
->HandleCount
;
239 ObmReferenceObject(PVOID ObjectBody
)
241 * FUNCTION: Increments a given object's reference count and performs
244 * ObjectBody = Body of the object
247 PUSER_OBJECT_HEADER ObjectHeader
;
251 DPRINT1("Cannot Reference NULL!\n");
255 ObjectHeader
= USER_BODY_TO_HEADER(ObjectBody
);
257 ObjectHeader
->RefCount
++;
259 ObmpPerformRetentionChecks(ObjectHeader
);
263 ObmDereferenceObject(PVOID ObjectBody
)
265 * FUNCTION: Decrements a given object's reference count and performs
268 * ObjectBody = Body of the object
271 PUSER_OBJECT_HEADER ObjectHeader
;
275 DPRINT1("Cannot Dereference NULL!\n");
279 ObjectHeader
= USER_BODY_TO_HEADER(ObjectBody
);
281 ObjectHeader
->RefCount
--;
282 ObmpPerformRetentionChecks(ObjectHeader
);
286 ObmReferenceObjectByPointer(PVOID ObjectBody
,
287 USER_OBJECT_TYPE ObjectType
)
289 * FUNCTION: Increments the pointer reference count for a given object
291 * ObjectBody = Object's body
292 * ObjectType = Object type
296 PUSER_OBJECT_HEADER ObjectHeader
;
298 ObjectHeader
= USER_BODY_TO_HEADER(ObjectBody
);
300 if ((ObjectType
!= otUnknown
) && (ObjectHeader
->Type
!= ObjectType
))
302 return STATUS_INVALID_PARAMETER
;
304 ObjectHeader
->RefCount
++;
306 return STATUS_SUCCESS
;
310 ObmCreateObject(PUSER_HANDLE_TABLE HandleTable
,
312 USER_OBJECT_TYPE ObjectType
,
315 PUSER_OBJECT_HEADER ObjectHeader
;
319 ObjectHeader
= (PUSER_OBJECT_HEADER
)ExAllocatePool(PagedPool
,
320 ObjectSize
+ sizeof(USER_OBJECT_HEADER
));
326 ObjectBody
= USER_HEADER_TO_BODY(ObjectHeader
);
328 RtlZeroMemory(ObjectBody
, ObjectSize
);
330 Status
= ObmpInitializeObject(HandleTable
,
336 if (!NT_SUCCESS(Status
))
338 ExFreePool(ObjectHeader
);
346 ObmCreateHandle(PUSER_HANDLE_TABLE HandleTable
,
348 PHANDLE HandleReturn
)
350 * FUNCTION: Add a handle referencing an object
352 * HandleTable = Table to put handle in
353 * ObjectBody = Object body that the handle should refer to
354 * RETURNS: The created handle
357 PUSER_HANDLE_BLOCK NewBlock
;
362 if (ObjectBody
!= NULL
)
364 USER_BODY_TO_HEADER(ObjectBody
)->HandleCount
++;
368 Current
= HandleTable
->ListHead
.Flink
;
370 * Scan through the currently allocated Handle blocks looking for a free
373 while (Current
!= &(HandleTable
->ListHead
))
375 PUSER_HANDLE_BLOCK Block
=
376 CONTAINING_RECORD(Current
, USER_HANDLE_BLOCK
, ListEntry
);
378 for (i
= 0; i
< HANDLE_BLOCK_ENTRIES
; i
++)
380 if (!Block
->Handles
[i
].ObjectBody
)
382 Block
->Handles
[i
].ObjectBody
= ObjectBody
;
383 *HandleReturn
= (HANDLE
)((Handle
+ i
) << 2);
384 return STATUS_SUCCESS
;
388 Handle
= Handle
+ HANDLE_BLOCK_ENTRIES
;
389 Current
= Current
->Flink
;
393 * Add a new Handle block to the end of the list
395 NewBlock
= (PUSER_HANDLE_BLOCK
)ExAllocatePool(PagedPool
,
396 sizeof(USER_HANDLE_BLOCK
));
399 DPRINT1("Unable to allocate new handle block\n");
400 *HandleReturn
= (PHANDLE
)NULL
;
401 return STATUS_INSUFFICIENT_RESOURCES
;
404 RtlZeroMemory(NewBlock
, sizeof(USER_HANDLE_BLOCK
));
405 NewBlock
->Handles
[0].ObjectBody
= ObjectBody
;
406 InsertTailList(&HandleTable
->ListHead
, &NewBlock
->ListEntry
);
407 *HandleReturn
= (HANDLE
)(Handle
<< 2);
409 return STATUS_SUCCESS
;
413 ObmReferenceObjectByHandle(PUSER_HANDLE_TABLE HandleTable
,
415 USER_OBJECT_TYPE ObjectType
,
418 * FUNCTION: Increments the reference count for an object and returns a
419 * pointer to its body
421 * HandleTable = Table to search
422 * Handle = Handle for the object
423 * ObjectType = Type of object
424 * Object (OUT) = Points to the object body on return
428 PUSER_OBJECT_HEADER ObjectHeader
;
429 PUSER_HANDLE UserHandle
;
432 UserHandle
= ObmpGetObjectByHandle(HandleTable
, Handle
);
434 if ((UserHandle
== NULL
) || (UserHandle
->ObjectBody
== NULL
))
436 return STATUS_UNSUCCESSFUL
;
439 ObjectBody
= UserHandle
->ObjectBody
;
440 ObmReferenceObjectByPointer(ObjectBody
, ObjectType
);
442 ObjectHeader
= USER_BODY_TO_HEADER(ObjectBody
);
444 if ((ObjectType
!= otUnknown
) && (ObjectHeader
->Type
!= ObjectType
))
446 DPRINT1("Object type mismatch 0x%x 0x%x\n", ObjectType
, ObjectHeader
->Type
);
447 ObmDereferenceObject(ObjectBody
);
448 return STATUS_UNSUCCESSFUL
;
451 *Object
= ObjectBody
;
453 return STATUS_SUCCESS
;
457 ObmCloseHandle(PUSER_HANDLE_TABLE HandleTable
,
462 ObjectBody
= ObmpDeleteHandle(HandleTable
, Handle
);
463 if (ObjectBody
== NULL
)
465 return STATUS_UNSUCCESSFUL
;
468 ObmDereferenceObject(ObjectBody
);
470 return STATUS_SUCCESS
;
474 ObmInitializeHandleTable(PUSER_HANDLE_TABLE HandleTable
)
476 InitializeListHead(&HandleTable
->ListHead
);
480 ObmFreeHandleTable(PUSER_HANDLE_TABLE HandleTable
)
482 ObmpDeleteHandleTable(HandleTable
);
485 PUSER_HANDLE_TABLE FASTCALL
486 ObmCreateHandleTable(VOID
)
488 PUSER_HANDLE_TABLE HandleTable
;
490 HandleTable
= (PUSER_HANDLE_TABLE
)ExAllocatePool(PagedPool
,
491 sizeof(USER_HANDLE_TABLE
));
494 DPRINT1("Unable to create handle table\n");
498 ObmInitializeHandleTable(HandleTable
);
504 ObmDestroyHandleTable(PUSER_HANDLE_TABLE HandleTable
)
506 ObmFreeHandleTable(HandleTable
);
507 ExFreePool(HandleTable
);