Removed client-side wait functions; all waiting is now done through
[wine] / scheduler / handle.c
1 /*
2  * Win32 process handles
3  *
4  * Copyright 1998 Alexandre Julliard
5  */
6
7 #include <assert.h>
8 #include <stdio.h>
9 #include "winbase.h"
10 #include "winerror.h"
11 #include "heap.h"
12 #include "process.h"
13 #include "server.h"
14 #include "thread.h"
15 #include "debug.h"
16
17 #define HTABLE_SIZE  0x30  /* Handle table initial size */
18 #define HTABLE_INC   0x10  /* Handle table increment */
19
20 /* Reserved access rights */
21 #define RESERVED_ALL           (0x0007 << RESERVED_SHIFT)
22 #define RESERVED_SHIFT         25
23 #define RESERVED_INHERIT       (HANDLE_FLAG_INHERIT<<RESERVED_SHIFT)
24 #define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE<<RESERVED_SHIFT)
25
26
27 /***********************************************************************
28  *           HANDLE_GrowTable
29  */
30 static BOOL32 HANDLE_GrowTable( PDB32 *process, INT32 incr )
31 {
32     HANDLE_TABLE *table;
33
34     SYSTEM_LOCK();
35     table = process->handle_table;
36     table = HeapReAlloc( process->system_heap,
37                          HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, table,
38                          sizeof(HANDLE_TABLE) +
39                          (table->count + incr - 1) * sizeof(HANDLE_ENTRY) );
40     if (table)
41     {
42         table->count += incr;
43         process->handle_table = table;
44     }
45     SYSTEM_UNLOCK();
46     return (table != NULL);
47 }
48
49
50 /***********************************************************************
51  *           HANDLE_CreateTable
52  *
53  * Create a process handle table, optionally inheriting the parent's handles.
54  */
55 BOOL32 HANDLE_CreateTable( PDB32 *pdb, BOOL32 inherit )
56 {
57     DWORD size;
58
59     /* Process must not already have a handle table */
60     assert( !pdb->handle_table );
61
62     /* If this is the first process, simply allocate a table */
63     if (!pdb->parent) inherit = FALSE;
64
65     SYSTEM_LOCK();
66     size = inherit ? pdb->parent->handle_table->count : HTABLE_SIZE;
67     if ((pdb->handle_table = HeapAlloc( pdb->system_heap,
68                                         HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE,
69                                         sizeof(HANDLE_TABLE) +
70                                         (size-1) * sizeof(HANDLE_ENTRY) )))
71     {
72         pdb->handle_table->count = size;
73         if (inherit)
74         {
75             HANDLE_ENTRY *src = pdb->parent->handle_table->entries;
76             HANDLE_ENTRY *dst = pdb->handle_table->entries;
77             HANDLE32 h;
78
79             for (h = 0; h < size; h++, src++, dst++)
80             {
81                 /* Check if handle is valid and inheritable */
82                 if (src->ptr && (src->access & RESERVED_INHERIT))
83                 {
84                     dst->access = src->access;
85                     dst->ptr    = src->ptr;
86                     dst->server = src->server;
87                     K32OBJ_IncCount( dst->ptr );
88                 }
89             }
90         }
91         /* Handle 1 is the process itself (unless the parent decided otherwise) */
92         if (!pdb->handle_table->entries[1].ptr)
93         {
94             pdb->handle_table->entries[1].ptr    = &pdb->header;
95             pdb->handle_table->entries[1].access = PROCESS_ALL_ACCESS;
96             pdb->handle_table->entries[1].server = -1;  /* FIXME */
97             K32OBJ_IncCount( &pdb->header );
98         }
99     }
100     SYSTEM_UNLOCK();
101     return (pdb->handle_table != NULL);
102 }
103
104
105 /***********************************************************************
106  *           HANDLE_Alloc
107  *
108  * Allocate a handle for a kernel object and increment its refcount.
109  */
110 HANDLE32 HANDLE_Alloc( PDB32 *pdb, K32OBJ *ptr, DWORD access,
111                        BOOL32 inherit, int server_handle )
112 {
113     HANDLE32 h;
114     HANDLE_ENTRY *entry;
115
116     assert( ptr );
117
118     /* Set the inherit reserved flag */
119     access &= ~RESERVED_ALL;
120     if (inherit) access |= RESERVED_INHERIT;
121
122     SYSTEM_LOCK();
123     K32OBJ_IncCount( ptr );
124     /* Don't try to allocate handle 0 */
125     entry = pdb->handle_table->entries + 1;
126     for (h = 1; h < pdb->handle_table->count; h++, entry++)
127         if (!entry->ptr) break;
128     if ((h < pdb->handle_table->count) || HANDLE_GrowTable( pdb, HTABLE_INC ))
129     {
130         entry = &pdb->handle_table->entries[h];
131         entry->access = access;
132         entry->ptr    = ptr;
133         entry->server = server_handle;
134         SYSTEM_UNLOCK();
135         return h;
136     }
137     K32OBJ_DecCount( ptr );
138     SYSTEM_UNLOCK();
139     if (server_handle != -1) CLIENT_CloseHandle( server_handle );
140     SetLastError( ERROR_OUTOFMEMORY );
141     return INVALID_HANDLE_VALUE32;
142 }
143
144
145 /***********************************************************************
146  *           HANDLE_GetObjPtr
147  *
148  * Retrieve a pointer to a kernel object and increments its reference count.
149  * The refcount must be decremented when the pointer is no longer used.
150  */
151 K32OBJ *HANDLE_GetObjPtr( PDB32 *pdb, HANDLE32 handle,
152                           K32OBJ_TYPE type, DWORD access,
153                           int *server_handle )
154 {
155     K32OBJ *ptr = NULL;
156
157     SYSTEM_LOCK();
158     if (HANDLE_IS_GLOBAL( handle ))
159     {
160         handle = HANDLE_GLOBAL_TO_LOCAL( handle );
161         pdb = PROCESS_Initial();
162     }
163     if ((handle > 0) && (handle < pdb->handle_table->count))
164     {
165         HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
166         if ((entry->access & access) != access)
167             WARN(win32, "Handle %08x bad access (acc=%08lx req=%08lx)\n",
168                      handle, entry->access, access );
169         ptr = entry->ptr;
170         if (server_handle) *server_handle = entry->server;
171     }
172     else if (handle == CURRENT_THREAD_PSEUDOHANDLE)
173     {
174        ptr = (K32OBJ *)THREAD_Current();
175        if (server_handle) *server_handle = CURRENT_THREAD_PSEUDOHANDLE;
176     }
177     else if (handle == CURRENT_PROCESS_PSEUDOHANDLE)
178     {
179        ptr = (K32OBJ *)PROCESS_Current();
180        if (server_handle) *server_handle = CURRENT_PROCESS_PSEUDOHANDLE;
181     }
182
183     if (ptr && ((type == K32OBJ_UNKNOWN) || (ptr->type == type)))
184         K32OBJ_IncCount( ptr );
185     else
186         ptr = NULL;
187
188     SYSTEM_UNLOCK();
189     if (!ptr) SetLastError( ERROR_INVALID_HANDLE );
190     return ptr;
191 }
192
193
194 /***********************************************************************
195  *           HANDLE_GetServerHandle
196  *
197  * Retrieve the server handle associated to an object.
198  */
199 int HANDLE_GetServerHandle( PDB32 *pdb, HANDLE32 handle,
200                             K32OBJ_TYPE type, DWORD access )
201 {
202     int server_handle;
203     K32OBJ *obj;
204
205     SYSTEM_LOCK();
206     if ((obj = HANDLE_GetObjPtr( pdb, handle, type, access, &server_handle )))
207         K32OBJ_DecCount( obj );
208     else
209         server_handle = -1;
210     SYSTEM_UNLOCK();
211     return server_handle;
212 }
213
214
215 /***********************************************************************
216  *           HANDLE_SetObjPtr
217  *
218  * Change the object pointer of a handle, and increment the refcount.
219  * Use with caution!
220  */
221 BOOL32 HANDLE_SetObjPtr( PDB32 *pdb, HANDLE32 handle, K32OBJ *ptr,
222                          DWORD access )
223 {
224     BOOL32 ret = FALSE;
225
226     SYSTEM_LOCK();
227     if ((handle > 0) && (handle < pdb->handle_table->count))
228     {
229         HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
230         K32OBJ *old_ptr = entry->ptr;
231         K32OBJ_IncCount( ptr );
232         entry->access = access;
233         entry->ptr    = ptr;
234         if (old_ptr) K32OBJ_DecCount( old_ptr );
235         ret = TRUE;
236     }
237     SYSTEM_UNLOCK();
238     if (!ret) SetLastError( ERROR_INVALID_HANDLE );
239     return ret;
240 }
241
242
243 /*********************************************************************
244  *           HANDLE_GetAccess
245  */
246 static BOOL32 HANDLE_GetAccess( PDB32 *pdb, HANDLE32 handle, LPDWORD access )
247 {
248     BOOL32 ret = FALSE;
249
250     SYSTEM_LOCK();
251     if ((handle > 0) && (handle < pdb->handle_table->count))
252     {
253         HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
254         if (entry->ptr)
255         {
256             *access = entry->access & ~RESERVED_ALL;
257             ret = TRUE;
258         }
259     }
260     SYSTEM_UNLOCK();
261     if (!ret) SetLastError( ERROR_INVALID_HANDLE );
262     return ret;
263 }
264
265
266 /*********************************************************************
267  *           HANDLE_Close
268  */
269 static BOOL32 HANDLE_Close( PDB32 *pdb, HANDLE32 handle )
270 {
271     BOOL32 ret = FALSE;
272     K32OBJ *ptr;
273
274     SYSTEM_LOCK();
275     if ((handle > 0) && (handle < pdb->handle_table->count))
276     {
277         HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
278         if ((ptr = entry->ptr))
279         {
280             if (!(entry->access & RESERVED_CLOSE_PROTECT))
281             {
282                 entry->access = 0;
283                 entry->ptr    = NULL;
284                 if (entry->server != -1)
285                     CLIENT_CloseHandle( entry->server );
286                 K32OBJ_DecCount( ptr );
287                 ret = TRUE;
288             }
289             /* FIXME: else SetLastError */
290         }
291     }
292     SYSTEM_UNLOCK();
293     if (!ret) SetLastError( ERROR_INVALID_HANDLE );
294     return ret;
295 }
296
297
298 /*********************************************************************
299  *           HANDLE_CloseAll
300  *
301  * Close all handles pointing to a given object (or all handles of the
302  * process if the object is NULL)
303  */
304 void HANDLE_CloseAll( PDB32 *pdb, K32OBJ *obj )
305 {
306     HANDLE_ENTRY *entry;
307     K32OBJ *ptr;
308     HANDLE32 handle;
309
310     SYSTEM_LOCK();
311     entry = pdb->handle_table->entries;
312     for (handle = 0; handle < pdb->handle_table->count; handle++, entry++)
313     {
314         if (!(ptr = entry->ptr)) continue;  /* empty slot */
315         if (obj && (ptr != obj)) continue;  /* not the right object */
316         entry->access = 0;
317         entry->ptr    = NULL;
318         if (entry->server != -1) CLIENT_CloseHandle( entry->server );
319         K32OBJ_DecCount( ptr );
320     }
321     SYSTEM_UNLOCK();
322 }
323
324
325 /*********************************************************************
326  *           CloseHandle   (KERNEL32.23)
327  */
328 BOOL32 WINAPI CloseHandle( HANDLE32 handle )
329 {
330     return HANDLE_Close( PROCESS_Current(), handle );
331 }
332
333
334 /*********************************************************************
335  *           GetHandleInformation   (KERNEL32.336)
336  */
337 BOOL32 WINAPI GetHandleInformation( HANDLE32 handle, LPDWORD flags )
338 {
339     BOOL32 ret = FALSE;
340     PDB32 *pdb = PROCESS_Current();
341
342     SYSTEM_LOCK();
343     if ((handle > 0) && (handle < pdb->handle_table->count))
344     {
345         HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
346         if (entry->ptr)
347         {
348             if (flags)
349                 *flags = (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
350             ret = TRUE;
351         }
352     }
353     SYSTEM_UNLOCK();
354     if (!ret) SetLastError( ERROR_INVALID_HANDLE );
355     return ret;
356 }
357
358
359 /*********************************************************************
360  *           SetHandleInformation   (KERNEL32.653)
361  */
362 BOOL32 WINAPI SetHandleInformation( HANDLE32 handle, DWORD mask, DWORD flags )
363 {
364     BOOL32 ret = FALSE;
365     PDB32 *pdb = PROCESS_Current();
366
367     mask  = (mask << RESERVED_SHIFT) & RESERVED_ALL;
368     flags = (flags << RESERVED_SHIFT) & RESERVED_ALL;
369     SYSTEM_LOCK();
370     if ((handle > 0) && (handle < pdb->handle_table->count))
371     {
372         HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
373         if (entry->ptr)
374         {
375             entry->access = (entry->access & ~mask) | flags;
376             ret = TRUE;
377         }
378     }
379     SYSTEM_UNLOCK();
380     if (!ret) SetLastError( ERROR_INVALID_HANDLE );
381     return ret;
382 }
383
384
385 /*********************************************************************
386  *           DuplicateHandle   (KERNEL32.192)
387  */
388 BOOL32 WINAPI DuplicateHandle( HANDLE32 source_process, HANDLE32 source,
389                                HANDLE32 dest_process, HANDLE32 *dest,
390                                DWORD access, BOOL32 inherit, DWORD options )
391 {
392     PDB32 *src_pdb = NULL, *dst_pdb = NULL;
393     K32OBJ *obj = NULL;
394     BOOL32 ret = FALSE;
395     HANDLE32 handle;
396     int src_process, src_handle, dst_process, dst_handle;
397
398     SYSTEM_LOCK();
399
400     if (!(src_pdb = PROCESS_GetPtr( source_process, PROCESS_DUP_HANDLE, &src_process )))
401         goto done;
402     if (!(obj = HANDLE_GetObjPtr( src_pdb, source, K32OBJ_UNKNOWN, 0, &src_handle )))
403         goto done;
404
405     /* Now that we are sure the source is valid, handle the options */
406
407     if (options & DUPLICATE_SAME_ACCESS)
408         HANDLE_GetAccess( src_pdb, source, &access );
409     if (options & DUPLICATE_CLOSE_SOURCE)
410         HANDLE_Close( src_pdb, source );
411
412     /* And duplicate the handle in the dest process */
413
414     if (!(dst_pdb = PROCESS_GetPtr( dest_process, PROCESS_DUP_HANDLE, &dst_process )))
415         goto done;
416
417     if ((src_process != -1) && (src_handle != -1) && (dst_process != -1))
418         dst_handle = CLIENT_DuplicateHandle( src_process, src_handle, dst_process, -1,
419                                              access, inherit, options );
420     else
421         dst_handle = -1;
422
423     if ((handle = HANDLE_Alloc( dst_pdb, obj, access, inherit,
424                                 dst_handle )) != INVALID_HANDLE_VALUE32)
425     {
426         if (dest) *dest = handle;
427         ret = TRUE;
428     }
429
430 done:
431     if (dst_pdb) K32OBJ_DecCount( &dst_pdb->header );
432     if (obj) K32OBJ_DecCount( obj );
433     if (src_pdb) K32OBJ_DecCount( &src_pdb->header );
434     SYSTEM_UNLOCK();
435     return ret;
436 }
437
438
439 /***********************************************************************
440  *           ConvertToGlobalHandle              (KERNEL32)
441  */
442 HANDLE32 WINAPI ConvertToGlobalHandle(HANDLE32 hSrc)
443 {
444     int src_handle, dst_handle;
445     HANDLE32 handle;
446     K32OBJ *obj = NULL;
447     DWORD access;
448
449     if (HANDLE_IS_GLOBAL(hSrc))
450         return hSrc;
451
452     if (!(obj = HANDLE_GetObjPtr( PROCESS_Current(), hSrc, K32OBJ_UNKNOWN, 0, &src_handle )))
453         return 0;
454
455     HANDLE_GetAccess( PROCESS_Current(), hSrc, &access );
456
457     if (src_handle != -1)
458         dst_handle = CLIENT_DuplicateHandle( GetCurrentProcess(), src_handle, -1, -1, 0, FALSE,
459                                              DUP_HANDLE_MAKE_GLOBAL | DUP_HANDLE_SAME_ACCESS );
460     else
461         dst_handle = -1;
462
463     if ((handle = HANDLE_Alloc( PROCESS_Initial(), obj, access, FALSE,
464                                 dst_handle )) != INVALID_HANDLE_VALUE32)
465         handle = HANDLE_LOCAL_TO_GLOBAL(handle);
466     else
467         handle = 0;
468
469     CloseHandle( hSrc );
470     return handle;
471 }