Moved win32k
[reactos.git] / reactos / subsystems / win32 / win32k / ntuser / object.c
1 /*
2 * Server-side USER handles
3 *
4 * Copyright (C) 2001 Alexandre Julliard
5 *
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.
10 *
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.
15 *
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
19 */
20
21
22
23 /* INCLUDES ******************************************************************/
24
25 #include <w32k.h>
26
27 #define NDEBUG
28 #include <debug.h>
29
30 int usedHandles=0;
31 USER_HANDLE_TABLE gHandleTable;
32
33
34 PUSER_HANDLE_ENTRY handle_to_entry(PUSER_HANDLE_TABLE ht, HANDLE handle )
35 {
36 unsigned short generation;
37 int index = (((unsigned int)handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
38 if (index < 0 || index >= ht->nb_handles)
39 return NULL;
40 if (!ht->handles[index].type)
41 return NULL;
42 generation = (unsigned int)handle >> 16;
43 if (generation == ht->handles[index].generation || !generation || generation == 0xffff)
44 return &ht->handles[index];
45 return NULL;
46 }
47
48 __inline static HANDLE entry_to_handle(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY ptr )
49 {
50 int index = ptr - ht->handles;
51 return (HANDLE)(((index << 1) + FIRST_USER_HANDLE) + (ptr->generation << 16));
52 }
53
54 __inline static PUSER_HANDLE_ENTRY alloc_user_entry(PUSER_HANDLE_TABLE ht)
55 {
56 PUSER_HANDLE_ENTRY entry;
57
58 // DPRINT1("handles used %i\n",usedHandles);
59
60 if (ht->freelist)
61 {
62 entry = ht->freelist;
63 ht->freelist = entry->ptr;
64
65 usedHandles++;
66 return entry;
67 }
68
69 if (ht->nb_handles >= ht->allocated_handles) /* need to grow the array */
70 {
71 DPRINT1("Out of user handles!\n");
72 return NULL;
73 #if 0
74
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)
80 return NULL;
81 if (!(new_handles = realloc( handles, new_size * sizeof(*handles) )))
82 return NULL;
83 handles = new_handles;
84 allocated_handles = new_size;
85 #endif
86
87 }
88
89 entry = &ht->handles[ht->nb_handles++];
90
91 entry->generation = 1;
92
93 usedHandles++;
94
95 return entry;
96 }
97
98 VOID UserInitHandleTable(PUSER_HANDLE_TABLE ht, PVOID mem, ULONG bytes)
99 {
100 ht->freelist = NULL;
101 ht->handles = mem;
102
103 ht->nb_handles = 0;
104 ht->allocated_handles = bytes / sizeof(USER_HANDLE_ENTRY);
105 }
106
107 __inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY entry)
108 {
109 void *ret;
110 ret = entry->ptr;
111 entry->ptr = ht->freelist;
112 entry->type = 0;
113 ht->freelist = entry;
114
115 usedHandles--;
116
117 return ret;
118 }
119
120 /* allocate a user handle for a given object */
121 HANDLE UserAllocHandle(PUSER_HANDLE_TABLE ht, PVOID object, USER_OBJECT_TYPE type )
122 {
123 PUSER_HANDLE_ENTRY entry = alloc_user_entry(ht);
124 if (!entry)
125 return 0;
126 entry->ptr = object;
127 entry->type = type;
128 if (++entry->generation >= 0xffff)
129 entry->generation = 1;
130 return entry_to_handle(ht, entry );
131 }
132
133 /* return a pointer to a user object from its handle */
134 PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, USER_OBJECT_TYPE type )
135 {
136 PUSER_HANDLE_ENTRY entry;
137
138 ASSERT(ht);
139
140 if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
141 {
142 SetLastWin32Error(ERROR_INVALID_HANDLE);
143 return NULL;
144 }
145 return entry->ptr;
146 }
147
148
149 /* get the full handle (32bit) for a possibly truncated (16bit) handle */
150 HANDLE get_user_full_handle(PUSER_HANDLE_TABLE ht, HANDLE handle )
151 {
152 PUSER_HANDLE_ENTRY entry;
153
154 if ((unsigned int)handle >> 16)
155 return handle;
156 if (!(entry = handle_to_entry(ht, handle )))
157 return handle;
158 return entry_to_handle( ht, entry );
159 }
160
161
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 )
164 {
165 PUSER_HANDLE_ENTRY entry;
166
167 if (!(entry = handle_to_entry(ht, *handle )) || entry->type != type)
168 return NULL;
169 *handle = entry_to_handle( ht, entry );
170 return entry->ptr;
171 }
172
173 /* free a user handle and return a pointer to the object */
174 PVOID UserFreeHandle(PUSER_HANDLE_TABLE ht, HANDLE handle )
175 {
176 PUSER_HANDLE_ENTRY entry;
177
178 if (!(entry = handle_to_entry( ht, handle )))
179 {
180 SetLastNtError( STATUS_INVALID_HANDLE );
181 return NULL;
182 }
183
184 return free_user_entry(ht, entry );
185 }
186
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 )
189 {
190 PUSER_HANDLE_ENTRY entry;
191
192 if (!*handle)
193 entry = ht->handles;
194 else
195 {
196 int index = (((unsigned int)*handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
197 if (index < 0 || index >= ht->nb_handles)
198 return NULL;
199 entry = ht->handles + index + 1; /* start from the next one */
200 }
201 while (entry < ht->handles + ht->nb_handles)
202 {
203 if (!type || entry->type == type)
204 {
205 *handle = entry_to_handle(ht, entry );
206 return entry->ptr;
207 }
208 entry++;
209 }
210 return NULL;
211 }
212
213
214
215 PVOID FASTCALL
216 ObmCreateObject(PUSER_HANDLE_TABLE ht, HANDLE* h,USER_OBJECT_TYPE type , ULONG size)
217 {
218
219 HANDLE hi;
220 PUSER_OBJECT_HEADER hdr = ExAllocatePool(PagedPool, size + sizeof(USER_OBJECT_HEADER));
221 if (!hdr)
222 return NULL;
223
224
225 hi = UserAllocHandle(ht, USER_HEADER_TO_BODY(hdr), type );
226 if (!hi)
227 {
228 ExFreePool(hdr);
229 return NULL;
230 }
231
232 RtlZeroMemory(hdr, size + sizeof(USER_OBJECT_HEADER));
233 hdr->hSelf = hi;
234 hdr->RefCount++; //temp hack!
235
236 if (h)
237 *h = hi;
238 return USER_HEADER_TO_BODY(hdr);
239 }
240
241 BOOL FASTCALL
242 ObmDeleteObject(HANDLE h, USER_OBJECT_TYPE type )
243 {
244 PUSER_OBJECT_HEADER hdr;
245 PVOID body = UserGetObject(&gHandleTable, h, type);
246 if (!body)
247 return FALSE;
248
249 hdr = USER_BODY_TO_HEADER(body);
250 ASSERT(hdr->RefCount >= 0);
251
252 hdr->destroyed = TRUE;
253 if (hdr->RefCount == 0)
254 {
255 UserFreeHandle(&gHandleTable, h);
256
257 memset(hdr, 0x55, sizeof(USER_OBJECT_HEADER));
258
259 ExFreePool(hdr);
260 return TRUE;
261 }
262
263 // DPRINT1("info: something not destroyed bcause refs still left, inuse %i\n",usedHandles);
264 return FALSE;
265 }
266
267
268 VOID FASTCALL ObmReferenceObject(PVOID obj)
269 {
270 PUSER_OBJECT_HEADER hdr = USER_BODY_TO_HEADER(obj);
271
272 ASSERT(hdr->RefCount >= 0);
273
274 hdr->RefCount++;
275 }
276
277
278 BOOL FASTCALL ObmDereferenceObject2(PVOID obj)
279 {
280 PUSER_OBJECT_HEADER hdr = USER_BODY_TO_HEADER(obj);
281
282 ASSERT(hdr->RefCount >= 1);
283
284 hdr->RefCount--;
285
286 if (hdr->RefCount == 0 && hdr->destroyed)
287 {
288 // DPRINT1("info: something destroyed bcaise of deref, in use=%i\n",usedHandles);
289
290 UserFreeHandle(&gHandleTable, hdr->hSelf);
291
292 memset(hdr, 0x55, sizeof(USER_OBJECT_HEADER));
293
294 ExFreePool(hdr);
295
296 return TRUE;
297 }
298
299 return FALSE;
300 }
301
302
303
304 BOOL FASTCALL ObmCreateHandleTable()
305 {
306
307 PVOID mem;
308
309 //FIXME: dont alloc all at once! must be mapped into umode also...
310 mem = ExAllocatePool(PagedPool, sizeof(USER_HANDLE_ENTRY) * 1024*2);
311 if (!mem)
312 {
313 DPRINT1("Failed creating handle table\n");
314 return FALSE;
315 }
316
317 //FIXME: make auto growable
318 UserInitHandleTable(&gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * 1024*2);
319
320 return TRUE;
321 }