Release 980822
[wine/multimedia.git] / scheduler / handle.c
blob4d5957dc3d9a4e23b4abc0fe321687ec193373ab
1 /*
2 * Win32 process handles
4 * Copyright 1998 Alexandre Julliard
5 */
7 #include <assert.h>
8 #include <stdio.h>
9 #include "debug.h"
10 #include "winbase.h"
11 #include "winerror.h"
12 #include "heap.h"
13 #include "process.h"
14 #include "server.h"
16 #define HTABLE_SIZE 0x30 /* Handle table initial size */
17 #define HTABLE_INC 0x10 /* Handle table increment */
19 /* Reserved access rights */
20 #define RESERVED_ALL (0x0007 << RESERVED_SHIFT)
21 #define RESERVED_SHIFT 25
22 #define RESERVED_INHERIT (HANDLE_FLAG_INHERIT<<RESERVED_SHIFT)
23 #define RESERVED_CLOSE_PROTECT (HANDLE_FLAG_PROTECT_FROM_CLOSE<<RESERVED_SHIFT)
26 /***********************************************************************
27 * HANDLE_GrowTable
29 static BOOL32 HANDLE_GrowTable( PDB32 *process, INT32 incr )
31 HANDLE_TABLE *table;
33 SYSTEM_LOCK();
34 table = process->handle_table;
35 table = HeapReAlloc( process->system_heap,
36 HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE, table,
37 sizeof(HANDLE_TABLE) +
38 (table->count + incr - 1) * sizeof(HANDLE_ENTRY) );
39 if (table)
41 table->count += incr;
42 process->handle_table = table;
44 SYSTEM_UNLOCK();
45 return (table != NULL);
49 /***********************************************************************
50 * HANDLE_CreateTable
52 * Create a process handle table, optionally inheriting the parent's handles.
54 BOOL32 HANDLE_CreateTable( PDB32 *pdb, BOOL32 inherit )
56 DWORD size;
58 /* Process must not already have a handle table */
59 assert( !pdb->handle_table );
61 /* If this is the first process, simply allocate a table */
62 if (!pdb->parent) inherit = FALSE;
64 SYSTEM_LOCK();
65 size = inherit ? pdb->parent->handle_table->count : HTABLE_SIZE;
66 if ((pdb->handle_table = HeapAlloc( pdb->system_heap,
67 HEAP_ZERO_MEMORY | HEAP_NO_SERIALIZE,
68 sizeof(HANDLE_TABLE) +
69 (size-1) * sizeof(HANDLE_ENTRY) )))
71 pdb->handle_table->count = size;
72 if (inherit)
74 HANDLE_ENTRY *src = pdb->parent->handle_table->entries;
75 HANDLE_ENTRY *dst = pdb->handle_table->entries;
76 HANDLE32 h;
78 for (h = 0; h < size; h++, src++, dst++)
80 /* Check if handle is valid and inheritable */
81 if (src->ptr && (src->access & RESERVED_INHERIT))
83 dst->access = src->access;
84 dst->ptr = src->ptr;
85 dst->server = src->server;
86 K32OBJ_IncCount( dst->ptr );
90 /* Handle 1 is the process itself (unless the parent decided otherwise) */
91 if (!pdb->handle_table->entries[1].ptr)
93 pdb->handle_table->entries[1].ptr = &pdb->header;
94 pdb->handle_table->entries[1].access = PROCESS_ALL_ACCESS;
95 pdb->handle_table->entries[1].server = -1; /* FIXME */
96 K32OBJ_IncCount( &pdb->header );
99 SYSTEM_UNLOCK();
100 return (pdb->handle_table != NULL);
104 /***********************************************************************
105 * HANDLE_Alloc
107 * Allocate a handle for a kernel object and increment its refcount.
109 HANDLE32 HANDLE_Alloc( PDB32 *pdb, K32OBJ *ptr, DWORD access,
110 BOOL32 inherit, int server_handle )
112 HANDLE32 h;
113 HANDLE_ENTRY *entry;
115 assert( ptr );
117 /* Set the inherit reserved flag */
118 access &= ~RESERVED_ALL;
119 if (inherit) access |= RESERVED_INHERIT;
121 SYSTEM_LOCK();
122 K32OBJ_IncCount( ptr );
123 /* Don't try to allocate handle 0 */
124 entry = pdb->handle_table->entries + 1;
125 for (h = 1; h < pdb->handle_table->count; h++, entry++)
126 if (!entry->ptr) break;
127 if ((h < pdb->handle_table->count) || HANDLE_GrowTable( pdb, HTABLE_INC ))
129 entry = &pdb->handle_table->entries[h];
130 entry->access = access;
131 entry->ptr = ptr;
132 entry->server = server_handle;
133 SYSTEM_UNLOCK();
134 return h;
136 K32OBJ_DecCount( ptr );
137 SYSTEM_UNLOCK();
138 if (server_handle != -1) CLIENT_CloseHandle( server_handle );
139 SetLastError( ERROR_OUTOFMEMORY );
140 return INVALID_HANDLE_VALUE32;
144 /***********************************************************************
145 * HANDLE_GetObjPtr
147 * Retrieve a pointer to a kernel object and increments its reference count.
148 * The refcount must be decremented when the pointer is no longer used.
150 K32OBJ *HANDLE_GetObjPtr( PDB32 *pdb, HANDLE32 handle,
151 K32OBJ_TYPE type, DWORD access,
152 int *server_handle )
154 K32OBJ *ptr = NULL;
156 SYSTEM_LOCK();
157 if ((handle > 0) && (handle <= pdb->handle_table->count))
159 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
160 if ((entry->access & access) != access)
161 WARN(win32, "Handle %08x bad access (acc=%08lx req=%08lx)\n",
162 handle, entry->access, access );
163 ptr = entry->ptr;
164 if (server_handle) *server_handle = entry->server;
165 if (ptr && ((type == K32OBJ_UNKNOWN) || (ptr->type == type)))
166 K32OBJ_IncCount( ptr );
167 else
168 ptr = NULL;
170 SYSTEM_UNLOCK();
171 if (!ptr) SetLastError( ERROR_INVALID_HANDLE );
172 return ptr;
176 /***********************************************************************
177 * HANDLE_SetObjPtr
179 * Change the object pointer of a handle, and increment the refcount.
180 * Use with caution!
182 BOOL32 HANDLE_SetObjPtr( PDB32 *pdb, HANDLE32 handle, K32OBJ *ptr,
183 DWORD access )
185 BOOL32 ret = FALSE;
187 SYSTEM_LOCK();
188 if ((handle > 0) && (handle <= pdb->handle_table->count))
190 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
191 K32OBJ *old_ptr = entry->ptr;
192 K32OBJ_IncCount( ptr );
193 entry->access = access;
194 entry->ptr = ptr;
195 if (old_ptr) K32OBJ_DecCount( old_ptr );
196 ret = TRUE;
198 SYSTEM_UNLOCK();
199 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
200 return ret;
204 /*********************************************************************
205 * HANDLE_GetAccess
207 static BOOL32 HANDLE_GetAccess( PDB32 *pdb, HANDLE32 handle, LPDWORD access )
209 BOOL32 ret = FALSE;
211 SYSTEM_LOCK();
212 if ((handle > 0) && (handle <= pdb->handle_table->count))
214 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
215 if (entry->ptr)
217 *access = entry->access & ~RESERVED_ALL;
218 ret = TRUE;
221 SYSTEM_UNLOCK();
222 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
223 return ret;
227 /*********************************************************************
228 * HANDLE_Close
230 static BOOL32 HANDLE_Close( PDB32 *pdb, HANDLE32 handle )
232 BOOL32 ret = FALSE;
233 K32OBJ *ptr;
235 SYSTEM_LOCK();
236 if ((handle > 0) && (handle <= pdb->handle_table->count))
238 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
239 if ((ptr = entry->ptr))
241 if (!(entry->access & RESERVED_CLOSE_PROTECT))
243 entry->access = 0;
244 entry->ptr = NULL;
245 if (entry->server != -1)
246 CLIENT_CloseHandle( entry->server );
247 K32OBJ_DecCount( ptr );
248 ret = TRUE;
250 /* FIXME: else SetLastError */
253 SYSTEM_UNLOCK();
254 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
255 return ret;
259 /*********************************************************************
260 * HANDLE_CloseAll
262 * Close all handles pointing to a given object (or all handles of the
263 * process if the object is NULL)
265 void HANDLE_CloseAll( PDB32 *pdb, K32OBJ *obj )
267 HANDLE_ENTRY *entry;
268 K32OBJ *ptr;
269 HANDLE32 handle;
271 SYSTEM_LOCK();
272 entry = pdb->handle_table->entries;
273 for (handle = 0; handle < pdb->handle_table->count; handle++, entry++)
275 if (!(ptr = entry->ptr)) continue; /* empty slot */
276 if (obj && (ptr != obj)) continue; /* not the right object */
277 entry->access = 0;
278 entry->ptr = NULL;
279 if (entry->server != -1) CLIENT_CloseHandle( entry->server );
280 K32OBJ_DecCount( ptr );
282 SYSTEM_UNLOCK();
286 /*********************************************************************
287 * CloseHandle (KERNEL32.23)
289 BOOL32 WINAPI CloseHandle( HANDLE32 handle )
291 return HANDLE_Close( PROCESS_Current(), handle );
295 /*********************************************************************
296 * GetHandleInformation (KERNEL32.336)
298 BOOL32 WINAPI GetHandleInformation( HANDLE32 handle, LPDWORD flags )
300 BOOL32 ret = FALSE;
301 PDB32 *pdb = PROCESS_Current();
303 SYSTEM_LOCK();
304 if ((handle > 0) && (handle <= pdb->handle_table->count))
306 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
307 if (entry->ptr)
309 if (flags)
310 *flags = (entry->access & RESERVED_ALL) >> RESERVED_SHIFT;
311 ret = TRUE;
314 SYSTEM_UNLOCK();
315 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
316 return ret;
320 /*********************************************************************
321 * SetHandleInformation (KERNEL32.653)
323 BOOL32 WINAPI SetHandleInformation( HANDLE32 handle, DWORD mask, DWORD flags )
325 BOOL32 ret = FALSE;
326 PDB32 *pdb = PROCESS_Current();
328 mask = (mask << RESERVED_SHIFT) & RESERVED_ALL;
329 flags = (flags << RESERVED_SHIFT) & RESERVED_ALL;
330 SYSTEM_LOCK();
331 if ((handle > 0) && (handle <= pdb->handle_table->count))
333 HANDLE_ENTRY *entry = &pdb->handle_table->entries[handle];
334 if (entry->ptr)
336 entry->access = (entry->access & ~mask) | flags;
337 ret = TRUE;
340 SYSTEM_UNLOCK();
341 if (!ret) SetLastError( ERROR_INVALID_HANDLE );
342 return ret;
346 /*********************************************************************
347 * DuplicateHandle (KERNEL32.192)
349 BOOL32 WINAPI DuplicateHandle( HANDLE32 source_process, HANDLE32 source,
350 HANDLE32 dest_process, HANDLE32 *dest,
351 DWORD access, BOOL32 inherit, DWORD options )
353 PDB32 *src_pdb = NULL, *dst_pdb = NULL;
354 K32OBJ *obj = NULL;
355 BOOL32 ret = FALSE;
356 HANDLE32 handle;
357 int src_process, src_handle, dst_process, dst_handle;
359 SYSTEM_LOCK();
361 if (!(src_pdb = PROCESS_GetPtr( source_process, PROCESS_DUP_HANDLE, &src_process )))
362 goto done;
363 if (!(obj = HANDLE_GetObjPtr( src_pdb, source, K32OBJ_UNKNOWN, 0, &src_handle )))
364 goto done;
366 /* Now that we are sure the source is valid, handle the options */
368 if (options & DUPLICATE_SAME_ACCESS)
369 HANDLE_GetAccess( src_pdb, source, &access );
370 if (options & DUPLICATE_CLOSE_SOURCE)
371 HANDLE_Close( src_pdb, source );
373 /* And duplicate the handle in the dest process */
375 if (!(dst_pdb = PROCESS_GetPtr( dest_process, PROCESS_DUP_HANDLE, &dst_process )))
376 goto done;
378 if ((src_process != -1) && (src_handle != -1) && (dst_process != -1))
379 dst_handle = CLIENT_DuplicateHandle( src_process, src_handle, dst_process, -1,
380 access, inherit, options );
381 else
382 dst_handle = -1;
384 if ((handle = HANDLE_Alloc( dst_pdb, obj, access, inherit,
385 dst_handle )) != INVALID_HANDLE_VALUE32)
387 if (dest) *dest = handle;
388 ret = TRUE;
391 done:
392 if (dst_pdb) K32OBJ_DecCount( &dst_pdb->header );
393 if (obj) K32OBJ_DecCount( obj );
394 if (src_pdb) K32OBJ_DecCount( &src_pdb->header );
395 SYSTEM_UNLOCK();
396 return ret;