forked from wine-mirror/wine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathuser.c
195 lines (170 loc) · 5.65 KB
/
user.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
/*
* Server-side USER handles
*
* Copyright (C) 2001 Alexandre Julliard
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
#include "thread.h"
#include "user.h"
#include "request.h"
struct user_handle
{
void *ptr; /* pointer to object */
unsigned short type; /* object type (0 if free) */
unsigned short generation; /* generation counter */
};
static struct user_handle *handles;
static struct user_handle *freelist;
static int nb_handles;
static int allocated_handles;
static struct user_handle *handle_to_entry( user_handle_t handle )
{
unsigned short generation;
int index = ((handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
if (index < 0 || index >= nb_handles) return NULL;
if (!handles[index].type) return NULL;
generation = handle >> 16;
if (generation == handles[index].generation || !generation || generation == 0xffff)
return &handles[index];
return NULL;
}
static inline user_handle_t entry_to_handle( struct user_handle *ptr )
{
unsigned int index = ptr - handles;
return (index << 1) + FIRST_USER_HANDLE + (ptr->generation << 16);
}
static inline struct user_handle *alloc_user_entry(void)
{
struct user_handle *handle;
if (freelist)
{
handle = freelist;
freelist = handle->ptr;
return handle;
}
if (nb_handles >= allocated_handles) /* need to grow the array */
{
struct user_handle *new_handles;
/* grow array by 50% (but at minimum 32 entries) */
int growth = max( 32, allocated_handles / 2 );
int new_size = min( allocated_handles + growth, (LAST_USER_HANDLE-FIRST_USER_HANDLE+1) >> 1 );
if (new_size <= allocated_handles) return NULL;
if (!(new_handles = realloc( handles, new_size * sizeof(*handles) )))
return NULL;
handles = new_handles;
allocated_handles = new_size;
}
handle = &handles[nb_handles++];
handle->generation = 0;
return handle;
}
static inline void *free_user_entry( struct user_handle *ptr )
{
void *ret;
ret = ptr->ptr;
ptr->ptr = freelist;
ptr->type = 0;
freelist = ptr;
return ret;
}
/* allocate a user handle for a given object */
user_handle_t alloc_user_handle( void *ptr, enum user_object type )
{
struct user_handle *entry = alloc_user_entry();
if (!entry) return 0;
entry->ptr = ptr;
entry->type = type;
if (++entry->generation >= 0xffff) entry->generation = 1;
return entry_to_handle( entry );
}
/* return a pointer to a user object from its handle */
void *get_user_object( user_handle_t handle, enum user_object type )
{
struct user_handle *entry;
if (!(entry = handle_to_entry( handle )) || entry->type != type) return NULL;
return entry->ptr;
}
/* get the full handle for a possibly truncated handle */
user_handle_t get_user_full_handle( user_handle_t handle )
{
struct user_handle *entry;
if (handle >> 16) return handle;
if (!(entry = handle_to_entry( handle ))) return handle;
return entry_to_handle( entry );
}
/* same as get_user_object plus set the handle to the full 32-bit value */
void *get_user_object_handle( user_handle_t *handle, enum user_object type )
{
struct user_handle *entry;
if (!(entry = handle_to_entry( *handle )) || entry->type != type) return NULL;
*handle = entry_to_handle( entry );
return entry->ptr;
}
/* free a user handle and return a pointer to the object */
void *free_user_handle( user_handle_t handle )
{
struct user_handle *entry;
if (!(entry = handle_to_entry( handle )))
{
set_error( STATUS_INVALID_HANDLE );
return NULL;
}
return free_user_entry( entry );
}
/* return the next user handle after 'handle' that is of a given type */
void *next_user_handle( user_handle_t *handle, enum user_object type )
{
struct user_handle *entry;
if (!*handle) entry = handles;
else
{
int index = ((*handle & 0xffff) - FIRST_USER_HANDLE) >> 1;
if (index < 0 || index >= nb_handles) return NULL;
entry = handles + index + 1; /* start from the next one */
}
while (entry < handles + nb_handles)
{
if (!type || entry->type == type)
{
*handle = entry_to_handle( entry );
return entry->ptr;
}
entry++;
}
return NULL;
}
/* free client-side user handles managed by the process */
void free_process_user_handles( struct process *process )
{
unsigned int i;
for (i = 0; i < nb_handles; i++)
if (handles[i].type == USER_CLIENT && handles[i].ptr == process)
free_user_entry( &handles[i] );
}
/* allocate an arbitrary user handle */
DECL_HANDLER(alloc_user_handle)
{
reply->handle = alloc_user_handle( current->process, USER_CLIENT );
}
/* free an arbitrary user handle */
DECL_HANDLER(free_user_handle)
{
struct user_handle *entry;
if ((entry = handle_to_entry( req->handle )) && entry->type == USER_CLIENT)
free_user_entry( entry );
else
set_error( STATUS_INVALID_HANDLE );
}