2 * Server-side USER handles
4 * Copyright (C) 2001 Alexandre Julliard
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
23 /* INCLUDES ******************************************************************/
31 USER_HANDLE_TABLE gHandleTable
;
34 PUSER_HANDLE_ENTRY
handle_to_entry(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
36 unsigned short generation
;
37 int index
= (((unsigned int)handle
& 0xffff) - FIRST_USER_HANDLE
) >> 1;
38 if (index
< 0 || index
>= ht
->nb_handles
)
40 if (!ht
->handles
[index
].type
)
42 generation
= (unsigned int)handle
>> 16;
43 if (generation
== ht
->handles
[index
].generation
|| !generation
|| generation
== 0xffff)
44 return &ht
->handles
[index
];
48 __inline
static HANDLE
entry_to_handle(PUSER_HANDLE_TABLE ht
, PUSER_HANDLE_ENTRY ptr
)
50 int index
= ptr
- ht
->handles
;
51 return (HANDLE
)(((index
<< 1) + FIRST_USER_HANDLE
) + (ptr
->generation
<< 16));
54 __inline
static PUSER_HANDLE_ENTRY
alloc_user_entry(PUSER_HANDLE_TABLE ht
)
56 PUSER_HANDLE_ENTRY entry
;
58 // DPRINT1("handles used %i\n",usedHandles);
63 ht
->freelist
= entry
->ptr
;
69 if (ht
->nb_handles
>= ht
->allocated_handles
) /* need to grow the array */
71 DPRINT1("Out of user handles!\n");
75 struct user_handle
*new_handles
;
76 /* grow array by 50% (but at minimum 32 entries) */
77 int growth
= max( 32, allocated_handles
/ 2 );
78 int new_size
= min( allocated_handles
+ growth
, (LAST_USER_HANDLE
-FIRST_USER_HANDLE
+1) >> 1 );
79 if (new_size
<= allocated_handles
)
81 if (!(new_handles
= realloc( handles
, new_size
* sizeof(*handles
) )))
83 handles
= new_handles
;
84 allocated_handles
= new_size
;
89 entry
= &ht
->handles
[ht
->nb_handles
++];
91 entry
->generation
= 1;
98 VOID
UserInitHandleTable(PUSER_HANDLE_TABLE ht
, PVOID mem
, ULONG bytes
)
104 ht
->allocated_handles
= bytes
/ sizeof(USER_HANDLE_ENTRY
);
107 __inline
static void *free_user_entry(PUSER_HANDLE_TABLE ht
, PUSER_HANDLE_ENTRY entry
)
111 entry
->ptr
= ht
->freelist
;
113 ht
->freelist
= entry
;
120 /* allocate a user handle for a given object */
121 HANDLE
UserAllocHandle(PUSER_HANDLE_TABLE ht
, PVOID object
, USER_OBJECT_TYPE type
)
123 PUSER_HANDLE_ENTRY entry
= alloc_user_entry(ht
);
128 if (++entry
->generation
>= 0xffff)
129 entry
->generation
= 1;
130 return entry_to_handle(ht
, entry
);
133 /* return a pointer to a user object from its handle */
134 PVOID
UserGetObject(PUSER_HANDLE_TABLE ht
, HANDLE handle
, USER_OBJECT_TYPE type
)
136 PUSER_HANDLE_ENTRY entry
;
140 if (!(entry
= handle_to_entry(ht
, handle
)) || entry
->type
!= type
)
142 SetLastWin32Error(ERROR_INVALID_HANDLE
);
149 /* get the full handle (32bit) for a possibly truncated (16bit) handle */
150 HANDLE
get_user_full_handle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
152 PUSER_HANDLE_ENTRY entry
;
154 if ((unsigned int)handle
>> 16)
156 if (!(entry
= handle_to_entry(ht
, handle
)))
158 return entry_to_handle( ht
, entry
);
162 /* same as get_user_object plus set the handle to the full 32-bit value */
163 void *get_user_object_handle(PUSER_HANDLE_TABLE ht
, HANDLE
* handle
, USER_OBJECT_TYPE type
)
165 PUSER_HANDLE_ENTRY entry
;
167 if (!(entry
= handle_to_entry(ht
, *handle
)) || entry
->type
!= type
)
169 *handle
= entry_to_handle( ht
, entry
);
173 /* free a user handle and return a pointer to the object */
174 PVOID
UserFreeHandle(PUSER_HANDLE_TABLE ht
, HANDLE handle
)
176 PUSER_HANDLE_ENTRY entry
;
178 if (!(entry
= handle_to_entry( ht
, handle
)))
180 SetLastNtError( STATUS_INVALID_HANDLE
);
184 return free_user_entry(ht
, entry
);
187 /* return the next user handle after 'handle' that is of a given type */
188 PVOID
UserGetNextHandle(PUSER_HANDLE_TABLE ht
, HANDLE
* handle
, USER_OBJECT_TYPE type
)
190 PUSER_HANDLE_ENTRY entry
;
196 int index
= (((unsigned int)*handle
& 0xffff) - FIRST_USER_HANDLE
) >> 1;
197 if (index
< 0 || index
>= ht
->nb_handles
)
199 entry
= ht
->handles
+ index
+ 1; /* start from the next one */
201 while (entry
< ht
->handles
+ ht
->nb_handles
)
203 if (!type
|| entry
->type
== type
)
205 *handle
= entry_to_handle(ht
, entry
);
216 ObmCreateObject(PUSER_HANDLE_TABLE ht
, HANDLE
* h
,USER_OBJECT_TYPE type
, ULONG size
)
220 PUSER_OBJECT_HEADER hdr
= ExAllocatePool(PagedPool
, size
+ sizeof(USER_OBJECT_HEADER
));
225 hi
= UserAllocHandle(ht
, USER_HEADER_TO_BODY(hdr
), type
);
232 RtlZeroMemory(hdr
, size
+ sizeof(USER_OBJECT_HEADER
));
234 hdr
->RefCount
++; //temp hack!
238 return USER_HEADER_TO_BODY(hdr
);
242 ObmDeleteObject(HANDLE h
, USER_OBJECT_TYPE type
)
244 PUSER_OBJECT_HEADER hdr
;
245 PVOID body
= UserGetObject(&gHandleTable
, h
, type
);
249 hdr
= USER_BODY_TO_HEADER(body
);
250 ASSERT(hdr
->RefCount
>= 0);
252 hdr
->destroyed
= TRUE
;
253 if (hdr
->RefCount
== 0)
255 UserFreeHandle(&gHandleTable
, h
);
257 memset(hdr
, 0x55, sizeof(USER_OBJECT_HEADER
));
263 // DPRINT1("info: something not destroyed bcause refs still left, inuse %i\n",usedHandles);
268 VOID FASTCALL
ObmReferenceObject(PVOID obj
)
270 PUSER_OBJECT_HEADER hdr
= USER_BODY_TO_HEADER(obj
);
272 ASSERT(hdr
->RefCount
>= 0);
278 BOOL FASTCALL
ObmDereferenceObject2(PVOID obj
)
280 PUSER_OBJECT_HEADER hdr
= USER_BODY_TO_HEADER(obj
);
282 ASSERT(hdr
->RefCount
>= 1);
286 if (hdr
->RefCount
== 0 && hdr
->destroyed
)
288 // DPRINT1("info: something destroyed bcaise of deref, in use=%i\n",usedHandles);
290 UserFreeHandle(&gHandleTable
, hdr
->hSelf
);
292 memset(hdr
, 0x55, sizeof(USER_OBJECT_HEADER
));
304 BOOL FASTCALL
ObmCreateHandleTable()
309 //FIXME: dont alloc all at once! must be mapped into umode also...
310 mem
= ExAllocatePool(PagedPool
, sizeof(USER_HANDLE_ENTRY
) * 1024*2);
313 DPRINT1("Failed creating handle table\n");
317 //FIXME: make auto growable
318 UserInitHandleTable(&gHandleTable
, mem
, sizeof(USER_HANDLE_ENTRY
) * 1024*2);