Added global management of user handles in the server.
[wine/multimedia.git] / server / user.c
blobec0584c4191fad6b661d09c35f92d55dc6a42f10
1 /*
2 * Server-side USER handles
4 * Copyright (C) 2001 Alexandre Julliard
5 */
7 #include "thread.h"
8 #include "user.h"
10 struct user_handle
12 void *ptr; /* pointer to object */
13 unsigned short type; /* object type (0 if free) */
14 unsigned short generation; /* generation counter */
17 static struct user_handle *handles;
18 static struct user_handle *freelist;
19 static int nb_handles;
20 static int allocated_handles;
22 #define FIRST_HANDLE 32 /* handle value for first table entry */
23 #define MAX_HANDLES (65536-FIRST_HANDLE)
25 static struct user_handle *handle_to_entry( user_handle_t handle )
27 int index = (handle & 0xffff) - FIRST_HANDLE;
28 if (index < 0 || index >= nb_handles) return NULL;
29 if (!handles[index].type) return NULL;
30 if ((handle >> 16) && (handle >> 16 != handles[index].generation)) return NULL;
31 return &handles[index];
34 inline static user_handle_t entry_to_handle( struct user_handle *ptr )
36 int index = ptr - handles;
37 return (index + FIRST_HANDLE) + (ptr->generation << 16);
40 inline static struct user_handle *alloc_user_entry(void)
42 struct user_handle *handle;
44 if (freelist)
46 handle = freelist;
47 freelist = handle->ptr;
48 return handle;
50 if (nb_handles >= allocated_handles) /* need to grow the array */
52 struct user_handle *new_handles;
53 /* grow array by 50% (but at minimum 32 entries) */
54 int growth = max( 32, allocated_handles / 2 );
55 int new_size = min( allocated_handles + growth, MAX_HANDLES );
56 if (new_size <= allocated_handles) return NULL;
57 if (!(new_handles = realloc( handles, new_size * sizeof(*handles) )))
58 return NULL;
59 handles = new_handles;
60 allocated_handles = new_size;
62 handle = &handles[nb_handles++];
63 handle->generation = 0;
64 return handle;
67 inline static void *free_user_entry( struct user_handle *ptr )
69 void *ret;
70 ret = ptr->ptr;
71 ptr->ptr = freelist;
72 ptr->type = 0;
73 freelist = ptr;
74 return ret;
77 /* allocate a user handle for a given object */
78 user_handle_t alloc_user_handle( void *ptr, enum user_object type )
80 struct user_handle *entry = alloc_user_entry();
81 if (!entry) return 0;
82 entry->ptr = ptr;
83 entry->type = type;
84 if (++entry->generation >= 0xffff) entry->generation = 1;
85 return entry_to_handle( entry );
88 /* return a pointer to a user object from its handle */
89 void *get_user_object( user_handle_t handle, enum user_object type )
91 struct user_handle *entry;
93 if (!(entry = handle_to_entry( handle )) || entry->type != type)
95 set_error( STATUS_INVALID_HANDLE );
96 return NULL;
98 return entry->ptr;
101 /* same as get_user_object plus set the handle to the full 32-bit value */
102 void *get_user_object_handle( user_handle_t *handle, enum user_object type )
104 struct user_handle *entry;
106 if (!(entry = handle_to_entry( *handle )) || entry->type != type)
108 set_error( STATUS_INVALID_HANDLE );
109 return NULL;
111 *handle = entry_to_handle( entry );
112 return entry->ptr;
115 /* free a user handle and return a pointer to the object */
116 void *free_user_handle( user_handle_t handle )
118 struct user_handle *entry;
120 if (!(entry = handle_to_entry( handle )))
122 set_error( STATUS_INVALID_HANDLE );
123 return NULL;
125 return free_user_entry( entry );
128 /* return the next user handle after 'handle' that is of a given type */
129 void *next_user_handle( user_handle_t *handle, enum user_object type )
131 struct user_handle *entry;
133 if (!*handle) entry = handles;
134 else
136 if (!(entry = handle_to_entry( *handle ))) return NULL;
137 entry++; /* start from the next one */
139 while (entry < handles + nb_handles)
141 if (!type || entry->type == type)
143 *handle = entry_to_handle( entry );
144 return entry->ptr;
146 entry++;
148 return NULL;