Bring back ext2 code from branch
[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 PUSER_HANDLE_TABLE gHandleTable = NULL;
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 DPRINT("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 /**/
72 int i, iFree = 0, iWindow = 0, iMenu = 0, iCursorIcon = 0,
73 iHook = 0, iCallProc = 0, iAccel = 0, iMonitor = 0;
74 /**/
75 DPRINT1("Out of user handles! Used -> %i, NM_Handle -> %d\n", usedHandles, ht->nb_handles);
76 //#if 0
77 for(i = 0; i < ht->nb_handles; i++)
78 {
79 switch (ht->handles[i].type)
80 {
81 case otFree: // Should be zero.
82 iFree++;
83 break;
84 case otWindow:
85 iWindow++;
86 break;
87 case otMenu:
88 iMenu++;
89 break;
90 case otCursorIcon:
91 iCursorIcon++;
92 break;
93 case otHook:
94 iHook++;
95 break;
96 case otCallProc:
97 iCallProc++;
98 break;
99 case otAccel:
100 iAccel++;
101 break;
102 case otMonitor:
103 iMonitor++;
104 break;
105 default:
106 break;
107 }
108 }
109 DPRINT1("Handle Count by Type:\n Free = %d Window = %d Menu = %d CursorIcon = %d Hook = %d\n CallProc = %d Accel = %d Monitor = %d\n",
110 iFree, iWindow, iMenu, iCursorIcon, iHook, iCallProc, iAccel, iMonitor );
111 //#endif
112 return NULL;
113 #if 0
114 PUSER_HANDLE_ENTRY new_handles;
115 /* grow array by 50% (but at minimum 32 entries) */
116 int growth = max( 32, ht->allocated_handles / 2 );
117 int new_size = min( ht->allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 );
118 if (new_size <= ht->allocated_handles)
119 return NULL;
120 if (!(new_handles = UserHeapReAlloc( ht->handles, new_size * sizeof(*ht->handles) )))
121 return NULL;
122 ht->handles = new_handles;
123 ht->allocated_handles = new_size;
124 #endif
125 }
126
127 entry = &ht->handles[ht->nb_handles++];
128
129 entry->generation = 1;
130
131 usedHandles++;
132
133 return entry;
134 }
135
136 VOID UserInitHandleTable(PUSER_HANDLE_TABLE ht, PVOID mem, ULONG bytes)
137 {
138 ht->freelist = NULL;
139 ht->handles = mem;
140
141 ht->nb_handles = 0;
142 ht->allocated_handles = bytes / sizeof(USER_HANDLE_ENTRY);
143 }
144
145 __inline static void *free_user_entry(PUSER_HANDLE_TABLE ht, PUSER_HANDLE_ENTRY entry)
146 {
147 void *ret;
148 ret = entry->ptr;
149 entry->ptr = ht->freelist;
150 entry->type = 0;
151 entry->pi = NULL;
152 ht->freelist = entry;
153
154 usedHandles--;
155
156 return ret;
157 }
158
159 static __inline PVOID
160 UserHandleOwnerByType(USER_OBJECT_TYPE type)
161 {
162 PVOID pi;
163
164 switch (type)
165 {
166 case otWindow:
167 pi = GetW32ThreadInfo();
168 break;
169
170 case otMenu:
171 case otCursorIcon:
172 case otHook:
173 case otCallProc:
174 case otAccel:
175 pi = GetW32ProcessInfo();
176 break;
177
178 case otMonitor:
179 pi = NULL; /* System */
180 break;
181
182 default:
183 pi = NULL;
184 break;
185 }
186
187 return pi;
188 }
189
190 /* allocate a user handle for a given object */
191 HANDLE UserAllocHandle(PUSER_HANDLE_TABLE ht, PVOID object, USER_OBJECT_TYPE type )
192 {
193 PUSER_HANDLE_ENTRY entry = alloc_user_entry(ht);
194 if (!entry)
195 return 0;
196 entry->ptr = object;
197 entry->type = type;
198 entry->pi = UserHandleOwnerByType(type);
199 if (++entry->generation >= 0xffff)
200 entry->generation = 1;
201 return entry_to_handle(ht, entry );
202 }
203
204 /* return a pointer to a user object from its handle */
205 PVOID UserGetObject(PUSER_HANDLE_TABLE ht, HANDLE handle, USER_OBJECT_TYPE type )
206 {
207 PUSER_HANDLE_ENTRY entry;
208
209 ASSERT(ht);
210
211 if (!(entry = handle_to_entry(ht, handle )) || entry->type != type)
212 {
213 SetLastWin32Error(ERROR_INVALID_HANDLE);
214 return NULL;
215 }
216 return entry->ptr;
217 }
218
219
220 /* get the full handle (32bit) for a possibly truncated (16bit) handle */
221 HANDLE get_user_full_handle(PUSER_HANDLE_TABLE ht, HANDLE handle )
222 {
223 PUSER_HANDLE_ENTRY entry;
224
225 if ((unsigned int)handle >> 16)
226 return handle;
227 if (!(entry = handle_to_entry(ht, handle )))
228 return handle;
229 return entry_to_handle( ht, entry );
230 }
231
232
233 /* same as get_user_object plus set the handle to the full 32-bit value */
234 void *get_user_object_handle(PUSER_HANDLE_TABLE ht, HANDLE* handle, USER_OBJECT_TYPE type )
235 {
236 PUSER_HANDLE_ENTRY entry;
237
238 if (!(entry = handle_to_entry(ht, *handle )) || entry->type != type)
239 return NULL;
240 *handle = entry_to_handle( ht, entry );
241 return entry->ptr;
242 }
243
244 /* free a user handle and return a pointer to the object */
245 PVOID UserFreeHandle(PUSER_HANDLE_TABLE ht, HANDLE handle )
246 {
247 PUSER_HANDLE_ENTRY entry;
248
249 if (!(entry = handle_to_entry( ht, handle )))
250 {
251 SetLastNtError( STATUS_INVALID_HANDLE );
252 return NULL;
253 }
254
255 return free_user_entry(ht, entry );
256 }
257
258 /* return the next user handle after 'handle' that is of a given type */
259 PVOID UserGetNextHandle(PUSER_HANDLE_TABLE ht, HANDLE* handle, USER_OBJECT_TYPE type )
260 {
261 PUSER_HANDLE_ENTRY entry;
262
263 if (!*handle)
264 entry = ht->handles;
265 else
266 {
267 int index = (((unsigned int)*handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
268 if (index < 0 || index >= ht->nb_handles)
269 return NULL;
270 entry = ht->handles + index + 1; /* start from the next one */
271 }
272 while (entry < ht->handles + ht->nb_handles)
273 {
274 if (!type || entry->type == type)
275 {
276 *handle = entry_to_handle(ht, entry );
277 return entry->ptr;
278 }
279 entry++;
280 }
281 return NULL;
282 }
283
284
285
286 PVOID FASTCALL
287 ObmCreateObject(PUSER_HANDLE_TABLE ht, HANDLE* h,USER_OBJECT_TYPE type , ULONG size)
288 {
289
290 HANDLE hi;
291 PUSER_OBJECT_HEADER hdr = UserHeapAlloc(size + sizeof(USER_OBJECT_HEADER));//ExAllocatePool(PagedPool, size + sizeof(USER_OBJECT_HEADER));
292 if (!hdr)
293 return NULL;
294
295
296 hi = UserAllocHandle(ht, USER_HEADER_TO_BODY(hdr), type );
297 if (!hi)
298 {
299 //ExFreePool(hdr);
300 UserHeapFree(hdr);
301 return NULL;
302 }
303
304 RtlZeroMemory(hdr, size + sizeof(USER_OBJECT_HEADER));
305 hdr->hSelf = hi;
306 hdr->RefCount++; //temp hack!
307
308 if (h)
309 *h = hi;
310 return USER_HEADER_TO_BODY(hdr);
311 }
312
313 BOOL FASTCALL
314 ObmDeleteObject(HANDLE h, USER_OBJECT_TYPE type )
315 {
316 PUSER_OBJECT_HEADER hdr;
317 PVOID body = UserGetObject(gHandleTable, h, type);
318 if (!body)
319 return FALSE;
320
321 hdr = USER_BODY_TO_HEADER(body);
322 ASSERT(hdr->RefCount >= 0);
323
324 hdr->destroyed = TRUE;
325 if (hdr->RefCount == 0)
326 {
327 UserFreeHandle(gHandleTable, h);
328
329 memset(hdr, 0x55, sizeof(USER_OBJECT_HEADER));
330
331 UserHeapFree(hdr);
332 //ExFreePool(hdr);
333 return TRUE;
334 }
335
336 // DPRINT1("info: something not destroyed bcause refs still left, inuse %i\n",usedHandles);
337 return FALSE;
338 }
339
340
341 VOID FASTCALL ObmReferenceObject(PVOID obj)
342 {
343 PUSER_OBJECT_HEADER hdr = USER_BODY_TO_HEADER(obj);
344
345 ASSERT(hdr->RefCount >= 0);
346
347 hdr->RefCount++;
348 }
349
350 HANDLE FASTCALL ObmObjectToHandle(PVOID obj)
351 {
352 PUSER_OBJECT_HEADER hdr = USER_BODY_TO_HEADER(obj);
353 return hdr->hSelf;
354 }
355
356
357 BOOL FASTCALL ObmDereferenceObject2(PVOID obj)
358 {
359 PUSER_OBJECT_HEADER hdr = USER_BODY_TO_HEADER(obj);
360
361 ASSERT(hdr->RefCount >= 1);
362
363 hdr->RefCount--;
364
365 // You can not have a zero here!
366 if (!hdr->destroyed && hdr->RefCount == 0) hdr->RefCount++; // BOUNCE!!!!!
367
368 if (hdr->RefCount == 0 && hdr->destroyed)
369 {
370 // DPRINT1("info: something destroyed bcaise of deref, in use=%i\n",usedHandles);
371
372 UserFreeHandle(gHandleTable, hdr->hSelf);
373
374 memset(hdr, 0x55, sizeof(USER_OBJECT_HEADER));
375
376 UserHeapFree(hdr);
377 //ExFreePool(hdr);
378
379 return TRUE;
380 }
381
382 return FALSE;
383 }
384
385
386
387 BOOL FASTCALL ObmCreateHandleTable()
388 {
389
390 PVOID mem;
391
392 //FIXME: dont alloc all at once! must be mapped into umode also...
393 //mem = ExAllocatePool(PagedPool, sizeof(USER_HANDLE_ENTRY) * 1024*2);
394 mem = UserHeapAlloc(sizeof(USER_HANDLE_ENTRY) * 1024*2);
395 if (!mem)
396 {
397 DPRINT1("Failed creating handle table\n");
398 return FALSE;
399 }
400
401 gHandleTable = UserHeapAlloc(sizeof(USER_HANDLE_TABLE));
402 if (gHandleTable == NULL)
403 {
404 UserHeapFree(mem);
405 DPRINT1("Failed creating handle table\n");
406 return FALSE;
407 }
408
409 //FIXME: make auto growable
410 UserInitHandleTable(gHandleTable, mem, sizeof(USER_HANDLE_ENTRY) * 1024*2);
411
412 return TRUE;
413 }