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 | #include "config.h" |
67 | |
68 | #include <X11/fonts/FS.h> |
69 | #include "misc.h" |
70 | #include "os.h" |
71 | #include "fsresource.h" |
72 | #include "clientstr.h" |
73 | #include "dispatch.h" |
74 | #include "globals.h" |
75 | #include "difs.h" |
76 | |
77 | static void rebuild_table(int client); |
78 | |
79 | #define INITBUCKETS64 64 |
80 | #define INITHASHSIZE6 6 |
81 | #define MAXHASHSIZE11 11 |
82 | |
83 | typedef struct _Resource { |
84 | struct _Resource *next; |
85 | FSID id; |
86 | RESTYPE type; |
87 | pointer value; |
88 | } ResourceRec, *ResourcePtr; |
89 | |
90 | #define NullResource((ResourcePtr)((void *)0)) ((ResourcePtr)NULL((void *)0)) |
91 | |
92 | typedef struct _ClientResource { |
93 | ResourcePtr *resources; |
94 | int elements; |
95 | int buckets; |
96 | int hashsize; |
97 | FSID fakeID; |
98 | FSID endFakeID; |
99 | FSID expectID; |
100 | } ClientResourceRec; |
101 | |
102 | static RESTYPE lastResourceType; |
103 | static RESTYPE TypeMask; |
104 | |
105 | typedef int (*DeleteType) (void *, FSID); |
106 | |
107 | static DeleteType *DeleteFuncs = (DeleteType *) NULL((void *)0); |
108 | |
109 | |
110 | static ClientResourceRec clientTable[MAXCLIENTS128]; |
111 | |
112 | |
113 | |
114 | |
115 | |
116 | |
117 | |
118 | int |
119 | NoneDeleteFunc (void *ptr, FSID id) |
120 | { |
121 | return FSSuccess-1; |
122 | } |
123 | |
124 | Bool |
125 | InitClientResources(ClientPtr client) |
126 | { |
127 | register int i, |
128 | j; |
129 | |
130 | if (client == serverClient) { |
131 | lastResourceType = RT_LASTPREDEF((RESTYPE)2); |
132 | TypeMask = RC_LASTPREDEF((RESTYPE)1<<31) - 1; |
133 | if (DeleteFuncs) |
134 | fsfree(DeleteFuncs)FSfree((pointer)DeleteFuncs); |
135 | DeleteFuncs = (DeleteType *) fsalloc((lastResourceType + 1) *FSalloc((unsigned long)(lastResourceType + 1) * sizeof(DeleteType )) |
136 | sizeof(DeleteType))FSalloc((unsigned long)(lastResourceType + 1) * sizeof(DeleteType )); |
137 | if (!DeleteFuncs) |
138 | return FALSE0; |
139 | DeleteFuncs[RT_NONE((RESTYPE)0) & TypeMask] = NoneDeleteFunc; |
140 | DeleteFuncs[RT_FONT((RESTYPE)1) & TypeMask] = (DeleteType)CloseClientFont; |
141 | DeleteFuncs[RT_AUTHCONT((RESTYPE)2) & TypeMask] = (DeleteType)DeleteAuthCont; |
142 | } |
143 | clientTable[i = client->index].resources = |
144 | (ResourcePtr *) fsalloc(INITBUCKETS * sizeof(ResourcePtr))FSalloc((unsigned long)64 * sizeof(ResourcePtr)); |
145 | if (!clientTable[i].resources) |
146 | return FALSE0; |
147 | clientTable[i].buckets = INITBUCKETS64; |
148 | clientTable[i].elements = 0; |
149 | clientTable[i].hashsize = INITHASHSIZE6; |
150 | clientTable[i].fakeID = SERVER_BIT0x20000000; |
151 | clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK0x3FFFFF) + 1; |
152 | for (j = 0; j < INITBUCKETS64; j++) { |
153 | clientTable[i].resources[j] = NullResource((ResourcePtr)((void *)0)); |
154 | } |
155 | return TRUE1; |
156 | } |
157 | |
158 | static int |
159 | hash(int client, FSID id) |
160 | { |
161 | id &= RESOURCE_ID_MASK0x3FFFFF; |
162 | switch (clientTable[client].hashsize) { |
163 | case 6: |
164 | return ((int) (0x03F & (id ^ (id >> 6) ^ (id >> 12)))); |
165 | case 7: |
166 | return ((int) (0x07F & (id ^ (id >> 7) ^ (id >> 13)))); |
167 | case 8: |
168 | return ((int) (0x0FF & (id ^ (id >> 8) ^ (id >> 16)))); |
169 | case 9: |
170 | return ((int) (0x1FF & (id ^ (id >> 9)))); |
171 | case 10: |
172 | return ((int) (0x3FF & (id ^ (id >> 10)))); |
173 | case 11: |
174 | return ((int) (0x7FF & (id ^ (id >> 11)))); |
175 | } |
176 | return -1; |
177 | } |
178 | |
179 | |
180 | static Font |
181 | AvailableID( |
182 | register int client, |
183 | register FSID id, |
184 | register FSID maxid, |
185 | register FSID goodid) |
186 | { |
187 | register ResourcePtr res; |
188 | |
189 | if ((goodid >= id) && (goodid <= maxid)) |
190 | return goodid; |
191 | for (; id <= maxid; id++) |
192 | { |
193 | res = clientTable[client].resources[hash(client, id)]; |
194 | while (res && (res->id != id)) |
195 | res = res->next; |
196 | if (!res) |
197 | return id; |
198 | } |
199 | return 0; |
200 | } |
201 | |
202 | |
203 | |
204 | |
205 | |
206 | |
207 | |
208 | |
209 | |
210 | FSID |
211 | FakeClientID(int client) |
212 | { |
213 | register FSID id, maxid; |
214 | register ResourcePtr *resp; |
215 | register ResourcePtr res; |
216 | register int i; |
217 | FSID goodid; |
218 | |
219 | id = clientTable[client].fakeID++; |
220 | if (id != clientTable[client].endFakeID) |
221 | return id; |
222 | id = ((Mask)client << CLIENTOFFSET22) | SERVER_BIT0x20000000; |
223 | maxid = id | RESOURCE_ID_MASK0x3FFFFF; |
224 | goodid = 0; |
225 | for (resp = clientTable[client].resources, i = clientTable[client].buckets; |
226 | --i >= 0;) |
227 | { |
228 | for (res = *resp++; res; res = res->next) |
229 | { |
230 | if ((res->id < id) || (res->id > maxid)) |
231 | continue; |
232 | if (((res->id - id) >= (maxid - res->id)) ? |
233 | (goodid = AvailableID(client, id, res->id - 1, goodid)) : |
234 | !(goodid = AvailableID(client, res->id + 1, maxid, goodid))) |
235 | maxid = res->id - 1; |
236 | else |
237 | id = res->id + 1; |
238 | } |
239 | } |
240 | if (id > maxid) { |
241 | if (!client) |
242 | FatalError("FakeClientID: server internal ids exhausted\n"); |
243 | MarkClientException(clients[client]); |
244 | id = ((Mask)client << CLIENTOFFSET22) | (SERVER_BIT0x20000000 * 3); |
245 | maxid = id | RESOURCE_ID_MASK0x3FFFFF; |
246 | } |
247 | clientTable[client].fakeID = id + 1; |
248 | clientTable[client].endFakeID = maxid + 1; |
249 | return id; |
250 | } |
251 | |
252 | Bool |
253 | AddResource( |
254 | int cid, |
255 | FSID id, |
256 | RESTYPE type, |
257 | pointer value) |
258 | { |
259 | register ClientResourceRec *rrec; |
260 | register ResourcePtr res, |
261 | *head; |
262 | |
263 | rrec = &clientTable[cid]; |
264 | if (!rrec->buckets) { |
| |
265 | ErrorF("AddResource(%lx, %lx, %p), client=%d \n", |
266 | id, type, value, cid); |
267 | FatalError("client not in use\n"); |
268 | } |
269 | if ((rrec->elements >= 4 * rrec->buckets) && |
| |
270 | (rrec->hashsize < MAXHASHSIZE11)) |
271 | rebuild_table(cid); |
| |
272 | head = &rrec->resources[hash(cid, id)]; |
273 | res = (ResourcePtr) fsalloc(sizeof(ResourceRec))FSalloc((unsigned long)sizeof(ResourceRec)); |
274 | if (!res) { |
275 | (*DeleteFuncs[type & TypeMask]) (value, id); |
276 | return FALSE0; |
277 | } |
278 | res->next = *head; |
279 | res->id = id; |
280 | res->type = type; |
281 | res->value = value; |
282 | *head = res; |
283 | rrec->elements++; |
284 | if (!(id & SERVER_BIT0x20000000) && (id >= rrec->expectID)) |
285 | rrec->expectID = id + 1; |
286 | return TRUE1; |
287 | } |
288 | |
289 | static void |
290 | rebuild_table(int client) |
291 | { |
292 | register int j; |
293 | register ResourcePtr res, |
294 | next; |
295 | ResourcePtr **tails, |
296 | *resources; |
297 | register ResourcePtr **tptr, |
298 | *rptr; |
299 | |
300 | |
301 | |
302 | |
303 | |
304 | |
305 | j = 2 * clientTable[client].buckets; |
306 | tails = (ResourcePtr **) ALLOCATE_LOCAL(j * sizeof(ResourcePtr *))__builtin_alloca((int)(j * sizeof(ResourcePtr *))); |
307 | if (!tails) |
| |
308 | return; |
309 | resources = (ResourcePtr *) fsalloc(j * sizeof(ResourcePtr))FSalloc((unsigned long)j * sizeof(ResourcePtr)); |
310 | if (!resources) { |
| 5 | | Assuming 'resources' is non-null | |
|
| |
311 | DEALLOCATE_LOCAL(tails)do {} while(0); |
312 | return; |
313 | } |
314 | for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) { |
| 7 | | Loop condition is false. Execution continues on line 318 | |
|
315 | *rptr = NullResource((ResourcePtr)((void *)0)); |
316 | *tptr = rptr; |
317 | } |
318 | clientTable[client].hashsize++; |
319 | for (j = clientTable[client].buckets, |
| 8 | | Loop condition is true. Entering loop body | |
|
320 | rptr = clientTable[client].resources; |
321 | --j >= 0; |
322 | rptr++) { |
323 | for (res = *rptr; res; res = next) { |
| 9 | | Loop condition is true. Entering loop body | |
|
324 | next = res->next; |
325 | res->next = NullResource((ResourcePtr)((void *)0)); |
326 | tptr = &tails[hash(client, res->id)]; |
327 | **tptr = res; |
| 10 | | Dereference of undefined pointer value |
|
328 | *tptr = &res->next; |
329 | } |
330 | } |
331 | DEALLOCATE_LOCAL(tails)do {} while(0); |
332 | clientTable[client].buckets *= 2; |
333 | fsfree(clientTable[client].resources)FSfree((pointer)clientTable[client].resources); |
334 | clientTable[client].resources = resources; |
335 | } |
336 | |
337 | void |
338 | FreeResource( |
339 | int cid, |
340 | FSID id, |
341 | RESTYPE skipDeleteFuncType) |
342 | { |
343 | register ResourcePtr res; |
344 | register ResourcePtr *prev, |
345 | *head; |
346 | register int *eltptr; |
347 | int elements; |
348 | Bool gotOne = FALSE0; |
349 | |
350 | if (clientTable[cid].buckets) { |
351 | head = &clientTable[cid].resources[hash(cid, id)]; |
352 | eltptr = &clientTable[cid].elements; |
353 | |
354 | prev = head; |
355 | while ((res = *prev) != (ResourcePtr) 0) { |
356 | if (res->id == id) { |
357 | RESTYPE rtype = res->type; |
358 | |
359 | *prev = res->next; |
360 | elements = --*eltptr; |
361 | if (rtype != skipDeleteFuncType) |
362 | (*DeleteFuncs[rtype & TypeMask]) (res->value, res->id); |
363 | fsfree(res)FSfree((pointer)res); |
364 | if (*eltptr != elements) |
365 | prev = head; |
366 | gotOne = TRUE1; |
367 | } else |
368 | prev = &res->next; |
369 | } |
370 | } |
371 | if (!gotOne) |
372 | FatalError("freeing resource id=%lX which isn't there\n", id); |
373 | } |
374 | |
375 | |
376 | void |
377 | FreeClientResources(ClientPtr client) |
378 | { |
379 | register ResourcePtr *resources; |
380 | register ResourcePtr this; |
381 | int j; |
382 | |
383 | |
384 | |
385 | |
386 | |
387 | |
388 | if (!client) |
389 | return; |
390 | |
391 | resources = clientTable[client->index].resources; |
392 | for (j = 0; j < clientTable[client->index].buckets; j++) { |
393 | |
394 | |
395 | |
396 | |
397 | |
398 | |
399 | |
400 | |
401 | |
402 | |
403 | |
404 | ResourcePtr *head; |
405 | |
406 | head = &resources[j]; |
407 | |
408 | for (this = *head; this; this = *head) { |
409 | RESTYPE rtype = this->type; |
410 | |
411 | *head = this->next; |
412 | (*DeleteFuncs[rtype & TypeMask]) (this->value, this->id); |
413 | fsfree(this)FSfree((pointer)this); |
414 | } |
415 | } |
416 | fsfree(clientTable[client->index].resources)FSfree((pointer)clientTable[client->index].resources); |
417 | clientTable[client->index].buckets = 0; |
418 | } |
419 | |
420 | void |
421 | FreeAllResources(void) |
422 | { |
423 | int i; |
424 | |
425 | for (i = 0; i < currentMaxClients; i++) { |
426 | if (clientTable[i].buckets) |
427 | FreeClientResources(clients[i]); |
428 | } |
429 | } |
430 | |
431 | |
432 | |
433 | |
434 | pointer |
435 | LookupIDByType( |
436 | int cid, |
437 | FSID id, |
438 | RESTYPE rtype) |
439 | { |
440 | register ResourcePtr res; |
441 | |
442 | if (clientTable[cid].buckets) { |
443 | res = clientTable[cid].resources[hash(cid, id)]; |
444 | |
445 | for (; res; res = res->next) |
446 | if ((res->id == id) && (res->type == rtype)) |
447 | return res->value; |
448 | } |
449 | return (pointer) NULL((void *)0); |
450 | } |
451 | |