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