Commit | Line | Data |
---|---|---|
a09e091a JB |
1 | /************************************************************ |
2 | ||
3 | Copyright 1987, 1998 The Open Group | |
4 | ||
5 | Permission to use, copy, modify, distribute, and sell this software and its | |
6 | documentation for any purpose is hereby granted without fee, provided that | |
7 | the above copyright notice appear in all copies and that both that | |
8 | copyright notice and this permission notice appear in supporting | |
9 | documentation. | |
10 | ||
11 | The above copyright notice and this permission notice shall be included in | |
12 | all copies or substantial portions of the Software. | |
13 | ||
14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 | OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN | |
18 | AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
20 | ||
21 | Except as contained in this notice, the name of The Open Group shall not be | |
22 | used in advertising or otherwise to promote the sale, use or other dealings | |
23 | in this Software without prior written authorization from The Open Group. | |
24 | ||
25 | Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. | |
26 | ||
27 | All Rights Reserved | |
28 | ||
29 | Permission to use, copy, modify, and distribute this software and its | |
30 | documentation for any purpose and without fee is hereby granted, | |
31 | provided that the above copyright notice appear in all copies and that | |
32 | both that copyright notice and this permission notice appear in | |
33 | supporting documentation, and that the name of Digital not be | |
34 | used in advertising or publicity pertaining to distribution of the | |
35 | software without specific, written prior permission. | |
36 | ||
37 | DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING | |
38 | ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL | |
39 | DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR | |
40 | ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, | |
41 | WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, | |
42 | ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS | |
43 | SOFTWARE. | |
44 | ||
45 | ********************************************************/ | |
46 | /* The panoramix components contained the following notice */ | |
47 | /***************************************************************** | |
48 | ||
49 | Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. | |
50 | ||
51 | Permission is hereby granted, free of charge, to any person obtaining a copy | |
52 | of this software and associated documentation files (the "Software"), to deal | |
53 | in the Software without restriction, including without limitation the rights | |
54 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
55 | copies of the Software. | |
56 | ||
57 | The above copyright notice and this permission notice shall be included in | |
58 | all copies or substantial portions of the Software. | |
59 | ||
60 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
61 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
62 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
63 | DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, | |
64 | BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, | |
65 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR | |
66 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
67 | ||
68 | Except as contained in this notice, the name of Digital Equipment Corporation | |
69 | shall not be used in advertising or otherwise to promote the sale, use or other | |
70 | dealings in this Software without prior written authorization from Digital | |
71 | Equipment Corporation. | |
72 | ||
73 | ******************************************************************/ | |
74 | /* XSERVER_DTRACE additions: | |
75 | * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved. | |
76 | * | |
77 | * Permission is hereby granted, free of charge, to any person obtaining a | |
78 | * copy of this software and associated documentation files (the "Software"), | |
79 | * to deal in the Software without restriction, including without limitation | |
80 | * the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
81 | * and/or sell copies of the Software, and to permit persons to whom the | |
82 | * Software is furnished to do so, subject to the following conditions: | |
83 | * | |
84 | * The above copyright notice and this permission notice (including the next | |
85 | * paragraph) shall be included in all copies or substantial portions of the | |
86 | * Software. | |
87 | * | |
88 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
89 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
90 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
91 | * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
92 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | |
93 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
94 | * DEALINGS IN THE SOFTWARE. | |
95 | */ | |
96 | ||
97 | /* Routines to manage various kinds of resources: | |
98 | * | |
99 | * CreateNewResourceType, CreateNewResourceClass, InitClientResources, | |
100 | * FakeClientID, AddResource, FreeResource, FreeClientResources, | |
101 | * FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange | |
102 | */ | |
103 | ||
104 | /* | |
105 | * A resource ID is a 32 bit quantity, the upper 2 bits of which are | |
106 | * off-limits for client-visible resources. The next 8 bits are | |
107 | * used as client ID, and the low 22 bits come from the client. | |
108 | * A resource ID is "hashed" by extracting and xoring subfields | |
109 | * (varying with the size of the hash table). | |
110 | * | |
111 | * It is sometimes necessary for the server to create an ID that looks | |
112 | * like it belongs to a client. This ID, however, must not be one | |
113 | * the client actually can create, or we have the potential for conflict. | |
114 | * The 31st bit of the ID is reserved for the server's use for this | |
115 | * purpose. By setting CLIENT_ID(id) to the client, the SERVER_BIT to | |
116 | * 1, and an otherwise arbitrary ID in the low 22 bits, we can create a | |
117 | * resource "owned" by the client. | |
118 | */ | |
119 | ||
120 | #ifdef HAVE_DIX_CONFIG_H | |
121 | #include <dix-config.h> | |
122 | #endif | |
123 | ||
124 | #include <X11/X.h> | |
125 | #include "misc.h" | |
126 | #include "os.h" | |
127 | #include "resource.h" | |
128 | #include "dixstruct.h" | |
129 | #include "opaque.h" | |
130 | #include "windowstr.h" | |
131 | #include "dixfont.h" | |
132 | #include "colormap.h" | |
133 | #include "inputstr.h" | |
134 | #include "dixevents.h" | |
135 | #include "dixgrabs.h" | |
136 | #include "cursor.h" | |
137 | #ifdef PANORAMIX | |
138 | #include "panoramiX.h" | |
139 | #include "panoramiXsrv.h" | |
140 | #endif | |
141 | #include "xace.h" | |
142 | #include <assert.h> | |
143 | #include "registry.h" | |
144 | #include "gcstruct.h" | |
145 | ||
146 | #ifdef XSERVER_DTRACE | |
147 | #include <sys/types.h> | |
148 | typedef const char *string; | |
149 | ||
150 | #include "Xserver-dtrace.h" | |
151 | ||
152 | #define TypeNameString(t) LookupResourceName(t) | |
153 | #endif | |
154 | ||
155 | static void RebuildTable(int /*client */ | |
156 | ); | |
157 | ||
158 | #define SERVER_MINID 32 | |
159 | ||
160 | #define INITBUCKETS 64 | |
161 | #define INITHASHSIZE 6 | |
162 | #define MAXHASHSIZE 11 | |
163 | ||
164 | typedef struct _Resource { | |
165 | struct _Resource *next; | |
166 | XID id; | |
167 | RESTYPE type; | |
168 | pointer value; | |
169 | } ResourceRec, *ResourcePtr; | |
170 | ||
171 | typedef struct _ClientResource { | |
172 | ResourcePtr *resources; | |
173 | int elements; | |
174 | int buckets; | |
175 | int hashsize; /* log(2)(buckets) */ | |
176 | XID fakeID; | |
177 | XID endFakeID; | |
178 | } ClientResourceRec; | |
179 | ||
180 | RESTYPE lastResourceType; | |
181 | static RESTYPE lastResourceClass; | |
182 | RESTYPE TypeMask; | |
183 | ||
184 | struct ResourceType { | |
185 | DeleteType deleteFunc; | |
186 | SizeType sizeFunc; | |
187 | FindTypeSubResources findSubResFunc; | |
188 | int errorValue; | |
189 | }; | |
190 | ||
191 | /** | |
192 | * Used by all resources that don't specify a function to calculate | |
193 | * resource size. Currently this is used for all resources with | |
194 | * insignificant memory usage. | |
195 | * | |
196 | * @see GetResourceTypeSizeFunc, SetResourceTypeSizeFunc | |
197 | * | |
198 | * @param[in] value Pointer to resource object. | |
199 | * | |
200 | * @param[in] id Resource ID for the object. | |
201 | * | |
202 | * @param[out] size Fill all fields to zero to indicate that size of | |
203 | * resource can't be determined. | |
204 | */ | |
205 | static void | |
206 | GetDefaultBytes(pointer value, XID id, ResourceSizePtr size) | |
207 | { | |
208 | size->resourceSize = 0; | |
209 | size->pixmapRefSize = 0; | |
210 | size->refCnt = 1; | |
211 | } | |
212 | ||
213 | /** | |
214 | * Used by all resources that don't specify a function to iterate | |
215 | * through subresources. Currently this is used for all resources with | |
216 | * insignificant memory usage. | |
217 | * | |
218 | * @see FindSubResources, SetResourceTypeFindSubResFunc | |
219 | * | |
220 | * @param[in] value Pointer to resource object. | |
221 | * | |
222 | * @param[in] func Function to call for each subresource. | |
223 | ||
224 | * @param[out] cdata Pointer to opaque data. | |
225 | */ | |
226 | static void | |
227 | DefaultFindSubRes(pointer value, FindAllRes func, pointer cdata) | |
228 | { | |
229 | /* do nothing */ | |
230 | } | |
231 | ||
232 | /** | |
233 | * Calculate drawable size in bytes. Reference counting is not taken | |
234 | * into account. | |
235 | * | |
236 | * @param[in] drawable Pointer to a drawable. | |
237 | * | |
238 | * @return Estimate of total memory usage for the drawable. | |
239 | */ | |
240 | static unsigned long | |
241 | GetDrawableBytes(DrawablePtr drawable) | |
242 | { | |
243 | int bytes = 0; | |
244 | ||
245 | if (drawable) | |
246 | { | |
247 | int bytesPerPixel = drawable->bitsPerPixel >> 3; | |
248 | int numberOfPixels = drawable->width * drawable->height; | |
249 | bytes = numberOfPixels * bytesPerPixel; | |
250 | } | |
251 | ||
252 | return bytes; | |
253 | } | |
254 | ||
255 | /** | |
256 | * Calculate pixmap size in bytes. Reference counting is taken into | |
257 | * account. Any extra data attached by extensions and drivers is not | |
258 | * taken into account. The purpose of this function is to estimate | |
259 | * memory usage that can be attributed to single reference of the | |
260 | * pixmap. | |
261 | * | |
262 | * @param[in] value Pointer to a pixmap. | |
263 | * | |
264 | * @param[in] id Resource ID of pixmap. If the pixmap hasn't been | |
265 | * added as resource, just pass value->drawable.id. | |
266 | * | |
267 | * @param[out] size Estimate of memory usage attributed to a single | |
268 | * pixmap reference. | |
269 | */ | |
270 | static void | |
271 | GetPixmapBytes(pointer value, XID id, ResourceSizePtr size) | |
272 | { | |
273 | PixmapPtr pixmap = value; | |
274 | ||
275 | size->resourceSize = 0; | |
276 | size->pixmapRefSize = 0; | |
277 | size->refCnt = pixmap->refcnt; | |
278 | ||
279 | if (pixmap && pixmap->refcnt) | |
280 | { | |
281 | DrawablePtr drawable = &pixmap->drawable; | |
282 | size->resourceSize = GetDrawableBytes(drawable); | |
283 | size->pixmapRefSize = size->resourceSize / pixmap->refcnt; | |
284 | } | |
285 | } | |
286 | ||
287 | /** | |
288 | * Calculate window size in bytes. The purpose of this function is to | |
289 | * estimate memory usage that can be attributed to all pixmap | |
290 | * references of the window. | |
291 | * | |
292 | * @param[in] value Pointer to a window. | |
293 | * | |
294 | * @param[in] id Resource ID of window. | |
295 | * | |
296 | * @param[out] size Estimate of memory usage attributed to a all | |
297 | * pixmap references of a window. | |
298 | */ | |
299 | static void | |
300 | GetWindowBytes(pointer value, XID id, ResourceSizePtr size) | |
301 | { | |
302 | SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP); | |
303 | ResourceSizeRec pixmapSize = { 0, 0, 0 }; | |
304 | WindowPtr window = value; | |
305 | ||
306 | /* Currently only pixmap bytes are reported to clients. */ | |
307 | size->resourceSize = 0; | |
308 | ||
309 | /* Calculate pixmap reference sizes. */ | |
310 | size->pixmapRefSize = 0; | |
311 | ||
312 | size->refCnt = 1; | |
313 | ||
314 | if (window->backgroundState == BackgroundPixmap) | |
315 | { | |
316 | PixmapPtr pixmap = window->background.pixmap; | |
317 | pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize); | |
318 | size->pixmapRefSize += pixmapSize.pixmapRefSize; | |
319 | } | |
320 | if (window->border.pixmap && !window->borderIsPixel) | |
321 | { | |
322 | PixmapPtr pixmap = window->border.pixmap; | |
323 | pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize); | |
324 | size->pixmapRefSize += pixmapSize.pixmapRefSize; | |
325 | } | |
326 | } | |
327 | ||
328 | /** | |
329 | * Iterate through subresources of a window. The purpose of this | |
330 | * function is to gather accurate information on what resources | |
331 | * a resource uses. | |
332 | * | |
333 | * @note Currently only sub-pixmaps are iterated | |
334 | * | |
335 | * @param[in] value Pointer to a window | |
336 | * | |
337 | * @param[in] func Function to call with each subresource | |
338 | * | |
339 | * @param[out] cdata Pointer to opaque data | |
340 | */ | |
341 | static void | |
342 | FindWindowSubRes(pointer value, FindAllRes func, pointer cdata) | |
343 | { | |
344 | WindowPtr window = value; | |
345 | ||
346 | /* Currently only pixmap subresources are reported to clients. */ | |
347 | ||
348 | if (window->backgroundState == BackgroundPixmap) | |
349 | { | |
350 | PixmapPtr pixmap = window->background.pixmap; | |
351 | func(window->background.pixmap, pixmap->drawable.id, RT_PIXMAP, cdata); | |
352 | } | |
353 | if (window->border.pixmap && !window->borderIsPixel) | |
354 | { | |
355 | PixmapPtr pixmap = window->border.pixmap; | |
356 | func(window->background.pixmap, pixmap->drawable.id, RT_PIXMAP, cdata); | |
357 | } | |
358 | } | |
359 | ||
360 | /** | |
361 | * Calculate graphics context size in bytes. The purpose of this | |
362 | * function is to estimate memory usage that can be attributed to all | |
363 | * pixmap references of the graphics context. | |
364 | * | |
365 | * @param[in] value Pointer to a graphics context. | |
366 | * | |
367 | * @param[in] id Resource ID of graphics context. | |
368 | * | |
369 | * @param[out] size Estimate of memory usage attributed to a all | |
370 | * pixmap references of a graphics context. | |
371 | */ | |
372 | static void | |
373 | GetGcBytes(pointer value, XID id, ResourceSizePtr size) | |
374 | { | |
375 | SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP); | |
376 | ResourceSizeRec pixmapSize = { 0, 0, 0 }; | |
377 | GCPtr gc = value; | |
378 | ||
379 | /* Currently only pixmap bytes are reported to clients. */ | |
380 | size->resourceSize = 0; | |
381 | ||
382 | /* Calculate pixmap reference sizes. */ | |
383 | size->pixmapRefSize = 0; | |
384 | ||
385 | size->refCnt = 1; | |
386 | if (gc->stipple) | |
387 | { | |
388 | PixmapPtr pixmap = gc->stipple; | |
389 | pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize); | |
390 | size->pixmapRefSize += pixmapSize.pixmapRefSize; | |
391 | } | |
392 | if (gc->tile.pixmap && !gc->tileIsPixel) | |
393 | { | |
394 | PixmapPtr pixmap = gc->tile.pixmap; | |
395 | pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize); | |
396 | size->pixmapRefSize += pixmapSize.pixmapRefSize; | |
397 | } | |
398 | } | |
399 | ||
400 | /** | |
401 | * Iterate through subresources of a graphics context. The purpose of | |
402 | * this function is to gather accurate information on what resources a | |
403 | * resource uses. | |
404 | * | |
405 | * @note Currently only sub-pixmaps are iterated | |
406 | * | |
407 | * @param[in] value Pointer to a window | |
408 | * | |
409 | * @param[in] func Function to call with each subresource | |
410 | * | |
411 | * @param[out] cdata Pointer to opaque data | |
412 | */ | |
413 | static void | |
414 | FindGCSubRes(pointer value, FindAllRes func, pointer cdata) | |
415 | { | |
416 | GCPtr gc = value; | |
417 | ||
418 | /* Currently only pixmap subresources are reported to clients. */ | |
419 | ||
420 | if (gc->stipple) | |
421 | { | |
422 | PixmapPtr pixmap = gc->stipple; | |
423 | func(pixmap, pixmap->drawable.id, RT_PIXMAP, cdata); | |
424 | } | |
425 | if (gc->tile.pixmap && !gc->tileIsPixel) | |
426 | { | |
427 | PixmapPtr pixmap = gc->tile.pixmap; | |
428 | func(pixmap, pixmap->drawable.id, RT_PIXMAP, cdata); | |
429 | } | |
430 | } | |
431 | ||
432 | static struct ResourceType *resourceTypes; | |
433 | ||
434 | static const struct ResourceType predefTypes[] = { | |
435 | [RT_NONE & (RC_LASTPREDEF - 1)] = { | |
436 | .deleteFunc = (DeleteType) NoopDDA, | |
437 | .sizeFunc = GetDefaultBytes, | |
438 | .findSubResFunc = DefaultFindSubRes, | |
439 | .errorValue = BadValue, | |
440 | }, | |
441 | [RT_WINDOW & (RC_LASTPREDEF - 1)] = { | |
442 | .deleteFunc = DeleteWindow, | |
443 | .sizeFunc = GetWindowBytes, | |
444 | .findSubResFunc = FindWindowSubRes, | |
445 | .errorValue = BadWindow, | |
446 | }, | |
447 | [RT_PIXMAP & (RC_LASTPREDEF - 1)] = { | |
448 | .deleteFunc = dixDestroyPixmap, | |
449 | .sizeFunc = GetPixmapBytes, | |
450 | .findSubResFunc = DefaultFindSubRes, | |
451 | .errorValue = BadPixmap, | |
452 | }, | |
453 | [RT_GC & (RC_LASTPREDEF - 1)] = { | |
454 | .deleteFunc = FreeGC, | |
455 | .sizeFunc = GetGcBytes, | |
456 | .findSubResFunc = FindGCSubRes, | |
457 | .errorValue = BadGC, | |
458 | }, | |
459 | [RT_FONT & (RC_LASTPREDEF - 1)] = { | |
460 | .deleteFunc = CloseFont, | |
461 | .sizeFunc = GetDefaultBytes, | |
462 | .findSubResFunc = DefaultFindSubRes, | |
463 | .errorValue = BadFont, | |
464 | }, | |
465 | [RT_CURSOR & (RC_LASTPREDEF - 1)] = { | |
466 | .deleteFunc = FreeCursor, | |
467 | .sizeFunc = GetDefaultBytes, | |
468 | .findSubResFunc = DefaultFindSubRes, | |
469 | .errorValue = BadCursor, | |
470 | }, | |
471 | [RT_COLORMAP & (RC_LASTPREDEF - 1)] = { | |
472 | .deleteFunc = FreeColormap, | |
473 | .sizeFunc = GetDefaultBytes, | |
474 | .findSubResFunc = DefaultFindSubRes, | |
475 | .errorValue = BadColor, | |
476 | }, | |
477 | [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = { | |
478 | .deleteFunc = FreeClientPixels, | |
479 | .sizeFunc = GetDefaultBytes, | |
480 | .findSubResFunc = DefaultFindSubRes, | |
481 | .errorValue = BadColor, | |
482 | }, | |
483 | [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = { | |
484 | .deleteFunc = OtherClientGone, | |
485 | .sizeFunc = GetDefaultBytes, | |
486 | .findSubResFunc = DefaultFindSubRes, | |
487 | .errorValue = BadValue, | |
488 | }, | |
489 | [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = { | |
490 | .deleteFunc = DeletePassiveGrab, | |
491 | .sizeFunc = GetDefaultBytes, | |
492 | .findSubResFunc = DefaultFindSubRes, | |
493 | .errorValue = BadValue, | |
494 | }, | |
495 | }; | |
496 | ||
497 | CallbackListPtr ResourceStateCallback; | |
498 | ||
499 | static _X_INLINE void | |
500 | CallResourceStateCallback(ResourceState state, ResourceRec * res) | |
501 | { | |
502 | if (ResourceStateCallback) { | |
503 | ResourceStateInfoRec rsi = { state, res->id, res->type, res->value }; | |
504 | CallCallbacks(&ResourceStateCallback, &rsi); | |
505 | } | |
506 | } | |
507 | ||
508 | RESTYPE | |
509 | CreateNewResourceType(DeleteType deleteFunc, const char *name) | |
510 | { | |
511 | RESTYPE next = lastResourceType + 1; | |
512 | struct ResourceType *types; | |
513 | ||
514 | if (next & lastResourceClass) | |
515 | return 0; | |
516 | types = realloc(resourceTypes, (next + 1) * sizeof(*resourceTypes)); | |
517 | if (!types) | |
518 | return 0; | |
519 | ||
520 | lastResourceType = next; | |
521 | resourceTypes = types; | |
522 | resourceTypes[next].deleteFunc = deleteFunc; | |
523 | resourceTypes[next].sizeFunc = GetDefaultBytes; | |
524 | resourceTypes[next].findSubResFunc = DefaultFindSubRes; | |
525 | resourceTypes[next].errorValue = BadValue; | |
526 | ||
527 | /* Called even if name is NULL, to remove any previous entry */ | |
528 | RegisterResourceName(next, name); | |
529 | ||
530 | return next; | |
531 | } | |
532 | ||
533 | /** | |
534 | * Get the function used to calculate resource size. Extensions and | |
535 | * drivers need to be able to determine the current size calculation | |
536 | * function if they want to wrap or override it. | |
537 | * | |
538 | * @param[in] type Resource type used in size calculations. | |
539 | * | |
540 | * @return Function to calculate the size of a single | |
541 | * resource. | |
542 | */ | |
543 | SizeType | |
544 | GetResourceTypeSizeFunc(RESTYPE type) | |
545 | { | |
546 | return resourceTypes[type & TypeMask].sizeFunc; | |
547 | } | |
548 | ||
549 | /** | |
550 | * Override the default function that calculates resource size. For | |
551 | * example, video driver knows better how to calculate pixmap memory | |
552 | * usage and can therefore wrap or override size calculation for | |
553 | * RT_PIXMAP. | |
554 | * | |
555 | * @param[in] type Resource type used in size calculations. | |
556 | * | |
557 | * @param[in] sizeFunc Function to calculate the size of a single | |
558 | * resource. | |
559 | */ | |
560 | void | |
561 | SetResourceTypeSizeFunc(RESTYPE type, SizeType sizeFunc) | |
562 | { | |
563 | resourceTypes[type & TypeMask].sizeFunc = sizeFunc; | |
564 | } | |
565 | ||
566 | /** | |
567 | * Provide a function for iterating the subresources of a resource. | |
568 | * This allows for example more accurate accounting of the (memory) | |
569 | * resources consumed by a resource. | |
570 | * | |
571 | * @see FindSubResources | |
572 | * | |
573 | * @param[in] type Resource type used in size calculations. | |
574 | * | |
575 | * @param[in] sizeFunc Function to calculate the size of a single | |
576 | * resource. | |
577 | */ | |
578 | void | |
579 | SetResourceTypeFindSubResFunc(RESTYPE type, FindTypeSubResources findFunc) | |
580 | { | |
581 | resourceTypes[type & TypeMask].findSubResFunc = findFunc; | |
582 | } | |
583 | ||
584 | void | |
585 | SetResourceTypeErrorValue(RESTYPE type, int errorValue) | |
586 | { | |
587 | resourceTypes[type & TypeMask].errorValue = errorValue; | |
588 | } | |
589 | ||
590 | RESTYPE | |
591 | CreateNewResourceClass(void) | |
592 | { | |
593 | RESTYPE next = lastResourceClass >> 1; | |
594 | ||
595 | if (next & lastResourceType) | |
596 | return 0; | |
597 | lastResourceClass = next; | |
598 | TypeMask = next - 1; | |
599 | return next; | |
600 | } | |
601 | ||
602 | static ClientResourceRec clientTable[MAXCLIENTS]; | |
603 | ||
604 | /***************** | |
605 | * InitClientResources | |
606 | * When a new client is created, call this to allocate space | |
607 | * in resource table | |
608 | *****************/ | |
609 | ||
610 | Bool | |
611 | InitClientResources(ClientPtr client) | |
612 | { | |
613 | int i, j; | |
614 | ||
615 | if (client == serverClient) { | |
616 | lastResourceType = RT_LASTPREDEF; | |
617 | lastResourceClass = RC_LASTPREDEF; | |
618 | TypeMask = RC_LASTPREDEF - 1; | |
619 | free(resourceTypes); | |
620 | resourceTypes = malloc(sizeof(predefTypes)); | |
621 | if (!resourceTypes) | |
622 | return FALSE; | |
623 | memcpy(resourceTypes, predefTypes, sizeof(predefTypes)); | |
624 | } | |
625 | clientTable[i = client->index].resources = | |
626 | malloc(INITBUCKETS * sizeof(ResourcePtr)); | |
627 | if (!clientTable[i].resources) | |
628 | return FALSE; | |
629 | clientTable[i].buckets = INITBUCKETS; | |
630 | clientTable[i].elements = 0; | |
631 | clientTable[i].hashsize = INITHASHSIZE; | |
632 | /* Many IDs allocated from the server client are visible to clients, | |
633 | * so we don't use the SERVER_BIT for them, but we have to start | |
634 | * past the magic value constants used in the protocol. For normal | |
635 | * clients, we can start from zero, with SERVER_BIT set. | |
636 | */ | |
637 | clientTable[i].fakeID = client->clientAsMask | | |
638 | (client->index ? SERVER_BIT : SERVER_MINID); | |
639 | clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1; | |
640 | for (j = 0; j < INITBUCKETS; j++) { | |
641 | clientTable[i].resources[j] = NULL; | |
642 | } | |
643 | return TRUE; | |
644 | } | |
645 | ||
646 | int | |
647 | HashResourceID(XID id, int numBits) | |
648 | { | |
649 | id &= RESOURCE_ID_MASK; | |
650 | switch (numBits) | |
651 | { | |
652 | case 6: | |
653 | return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12)))); | |
654 | case 7: | |
655 | return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13)))); | |
656 | case 8: | |
657 | return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16)))); | |
658 | case 9: | |
659 | return ((int)(0x1FF & (id ^ (id>>9)))); | |
660 | case 10: | |
661 | return ((int)(0x3FF & (id ^ (id>>10)))); | |
662 | case 11: | |
663 | return ((int)(0x7FF & (id ^ (id>>11)))); | |
664 | } | |
665 | if (numBits >= 11) | |
666 | return ((int)(0x7FF & (id ^ (id>>11)))); | |
667 | else | |
668 | { | |
669 | assert(numBits >= 0); | |
670 | return id & ~((~0) << numBits); | |
671 | } | |
672 | } | |
673 | ||
674 | static XID | |
675 | AvailableID(int client, XID id, XID maxid, XID goodid) | |
676 | { | |
677 | ResourcePtr res; | |
678 | ||
679 | if ((goodid >= id) && (goodid <= maxid)) | |
680 | return goodid; | |
681 | for (; id <= maxid; id++) { | |
682 | res = clientTable[client].resources[HashResourceID(id, clientTable[client].hashsize)]; | |
683 | while (res && (res->id != id)) | |
684 | res = res->next; | |
685 | if (!res) | |
686 | return id; | |
687 | } | |
688 | return 0; | |
689 | } | |
690 | ||
691 | void | |
692 | GetXIDRange(int client, Bool server, XID *minp, XID *maxp) | |
693 | { | |
694 | XID id, maxid; | |
695 | ResourcePtr *resp; | |
696 | ResourcePtr res; | |
697 | int i; | |
698 | XID goodid; | |
699 | ||
700 | id = (Mask) client << CLIENTOFFSET; | |
701 | if (server) | |
702 | id |= client ? SERVER_BIT : SERVER_MINID; | |
703 | maxid = id | RESOURCE_ID_MASK; | |
704 | goodid = 0; | |
705 | for (resp = clientTable[client].resources, i = clientTable[client].buckets; | |
706 | --i >= 0;) { | |
707 | for (res = *resp++; res; res = res->next) { | |
708 | if ((res->id < id) || (res->id > maxid)) | |
709 | continue; | |
710 | if (((res->id - id) >= (maxid - res->id)) ? | |
711 | (goodid = AvailableID(client, id, res->id - 1, goodid)) : | |
712 | !(goodid = AvailableID(client, res->id + 1, maxid, goodid))) | |
713 | maxid = res->id - 1; | |
714 | else | |
715 | id = res->id + 1; | |
716 | } | |
717 | } | |
718 | if (id > maxid) | |
719 | id = maxid = 0; | |
720 | *minp = id; | |
721 | *maxp = maxid; | |
722 | } | |
723 | ||
724 | /** | |
725 | * GetXIDList is called by the XC-MISC extension's MiscGetXIDList function. | |
726 | * This function tries to find count unused XIDs for the given client. It | |
727 | * puts the IDs in the array pids and returns the number found, which should | |
728 | * almost always be the number requested. | |
729 | * | |
730 | * The circumstances that lead to a call to this function are very rare. | |
731 | * Xlib must run out of IDs while trying to generate a request that wants | |
732 | * multiple ID's, like the Multi-buffering CreateImageBuffers request. | |
733 | * | |
734 | * No rocket science in the implementation; just iterate over all | |
735 | * possible IDs for the given client and pick the first count IDs | |
736 | * that aren't in use. A more efficient algorithm could probably be | |
737 | * invented, but this will be used so rarely that this should suffice. | |
738 | */ | |
739 | ||
740 | unsigned int | |
741 | GetXIDList(ClientPtr pClient, unsigned count, XID *pids) | |
742 | { | |
743 | unsigned int found = 0; | |
744 | XID rc, id = pClient->clientAsMask; | |
745 | XID maxid; | |
746 | pointer val; | |
747 | ||
748 | maxid = id | RESOURCE_ID_MASK; | |
749 | while ((found < count) && (id <= maxid)) { | |
750 | rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, | |
751 | DixGetAttrAccess); | |
752 | if (rc == BadValue) { | |
753 | pids[found++] = id; | |
754 | } | |
755 | id++; | |
756 | } | |
757 | return found; | |
758 | } | |
759 | ||
760 | /* | |
761 | * Return the next usable fake client ID. | |
762 | * | |
763 | * Normally this is just the next one in line, but if we've used the last | |
764 | * in the range, we need to find a new range of safe IDs to avoid | |
765 | * over-running another client. | |
766 | */ | |
767 | ||
768 | XID | |
769 | FakeClientID(int client) | |
770 | { | |
771 | XID id, maxid; | |
772 | ||
773 | id = clientTable[client].fakeID++; | |
774 | if (id != clientTable[client].endFakeID) | |
775 | return id; | |
776 | GetXIDRange(client, TRUE, &id, &maxid); | |
777 | if (!id) { | |
778 | if (!client) | |
779 | FatalError("FakeClientID: server internal ids exhausted\n"); | |
780 | MarkClientException(clients[client]); | |
781 | id = ((Mask) client << CLIENTOFFSET) | (SERVER_BIT * 3); | |
782 | maxid = id | RESOURCE_ID_MASK; | |
783 | } | |
784 | clientTable[client].fakeID = id + 1; | |
785 | clientTable[client].endFakeID = maxid + 1; | |
786 | return id; | |
787 | } | |
788 | ||
789 | Bool | |
790 | AddResource(XID id, RESTYPE type, pointer value) | |
791 | { | |
792 | int client; | |
793 | ClientResourceRec *rrec; | |
794 | ResourcePtr res, *head; | |
795 | ||
796 | #ifdef XSERVER_DTRACE | |
797 | XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type)); | |
798 | #endif | |
799 | client = CLIENT_ID(id); | |
800 | rrec = &clientTable[client]; | |
801 | if (!rrec->buckets) { | |
802 | ErrorF("[dix] AddResource(%lx, %x, %lx), client=%d \n", | |
803 | (unsigned long) id, type, (unsigned long) value, client); | |
804 | FatalError("client not in use\n"); | |
805 | } | |
806 | if ((rrec->elements >= 4 * rrec->buckets) && (rrec->hashsize < MAXHASHSIZE)) | |
807 | RebuildTable(client); | |
808 | head = &rrec->resources[HashResourceID(id, clientTable[client].hashsize)]; | |
809 | res = malloc(sizeof(ResourceRec)); | |
810 | if (!res) { | |
811 | (*resourceTypes[type & TypeMask].deleteFunc) (value, id); | |
812 | return FALSE; | |
813 | } | |
814 | res->next = *head; | |
815 | res->id = id; | |
816 | res->type = type; | |
817 | res->value = value; | |
818 | *head = res; | |
819 | rrec->elements++; | |
820 | CallResourceStateCallback(ResourceStateAdding, res); | |
821 | return TRUE; | |
822 | } | |
823 | ||
824 | static void | |
825 | RebuildTable(int client) | |
826 | { | |
827 | int j; | |
828 | ResourcePtr res, next; | |
829 | ResourcePtr **tails, *resources; | |
830 | ResourcePtr **tptr, *rptr; | |
831 | ||
832 | /* | |
833 | * For now, preserve insertion order, since some ddx layers depend | |
834 | * on resources being free in the opposite order they are added. | |
835 | */ | |
836 | ||
837 | j = 2 * clientTable[client].buckets; | |
838 | tails = malloc(j * sizeof(ResourcePtr *)); | |
839 | if (!tails) | |
840 | return; | |
841 | resources = malloc(j * sizeof(ResourcePtr)); | |
842 | if (!resources) { | |
843 | free(tails); | |
844 | return; | |
845 | } | |
846 | for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) { | |
847 | *rptr = NULL; | |
848 | *tptr = rptr; | |
849 | } | |
850 | clientTable[client].hashsize++; | |
851 | for (j = clientTable[client].buckets, | |
852 | rptr = clientTable[client].resources; --j >= 0; rptr++) { | |
853 | for (res = *rptr; res; res = next) { | |
854 | next = res->next; | |
855 | res->next = NULL; | |
856 | tptr = &tails[HashResourceID(res->id, clientTable[client].hashsize)]; | |
857 | **tptr = res; | |
858 | *tptr = &res->next; | |
859 | } | |
860 | } | |
861 | free(tails); | |
862 | clientTable[client].buckets *= 2; | |
863 | free(clientTable[client].resources); | |
864 | clientTable[client].resources = resources; | |
865 | } | |
866 | ||
867 | static void | |
868 | doFreeResource(ResourcePtr res, Bool skip) | |
869 | { | |
870 | CallResourceStateCallback(ResourceStateFreeing, res); | |
871 | ||
872 | if (!skip) | |
873 | resourceTypes[res->type & TypeMask].deleteFunc(res->value, res->id); | |
874 | ||
875 | free(res); | |
876 | } | |
877 | ||
878 | void | |
879 | FreeResource(XID id, RESTYPE skipDeleteFuncType) | |
880 | { | |
881 | int cid; | |
882 | ResourcePtr res; | |
883 | ResourcePtr *prev, *head; | |
884 | int *eltptr; | |
885 | int elements; | |
886 | ||
887 | if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) { | |
888 | head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; | |
889 | eltptr = &clientTable[cid].elements; | |
890 | ||
891 | prev = head; | |
892 | while ((res = *prev)) { | |
893 | if (res->id == id) { | |
894 | RESTYPE rtype = res->type; | |
895 | ||
896 | #ifdef XSERVER_DTRACE | |
897 | XSERVER_RESOURCE_FREE(res->id, res->type, | |
898 | res->value, TypeNameString(res->type)); | |
899 | #endif | |
900 | *prev = res->next; | |
901 | elements = --*eltptr; | |
902 | ||
903 | doFreeResource(res, rtype == skipDeleteFuncType); | |
904 | ||
905 | if (*eltptr != elements) | |
906 | prev = head; /* prev may no longer be valid */ | |
907 | } | |
908 | else | |
909 | prev = &res->next; | |
910 | } | |
911 | } | |
912 | } | |
913 | ||
914 | void | |
915 | FreeResourceByType(XID id, RESTYPE type, Bool skipFree) | |
916 | { | |
917 | int cid; | |
918 | ResourcePtr res; | |
919 | ResourcePtr *prev, *head; | |
920 | ||
921 | if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) { | |
922 | head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; | |
923 | ||
924 | prev = head; | |
925 | while ((res = *prev)) { | |
926 | if (res->id == id && res->type == type) { | |
927 | #ifdef XSERVER_DTRACE | |
928 | XSERVER_RESOURCE_FREE(res->id, res->type, | |
929 | res->value, TypeNameString(res->type)); | |
930 | #endif | |
931 | *prev = res->next; | |
932 | clientTable[cid].elements--; | |
933 | ||
934 | doFreeResource(res, skipFree); | |
935 | ||
936 | break; | |
937 | } | |
938 | else | |
939 | prev = &res->next; | |
940 | } | |
941 | } | |
942 | } | |
943 | ||
944 | /* | |
945 | * Change the value associated with a resource id. Caller | |
946 | * is responsible for "doing the right thing" with the old | |
947 | * data | |
948 | */ | |
949 | ||
950 | Bool | |
951 | ChangeResourceValue(XID id, RESTYPE rtype, pointer value) | |
952 | { | |
953 | int cid; | |
954 | ResourcePtr res; | |
955 | ||
956 | if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) { | |
957 | res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; | |
958 | ||
959 | for (; res; res = res->next) | |
960 | if ((res->id == id) && (res->type == rtype)) { | |
961 | res->value = value; | |
962 | return TRUE; | |
963 | } | |
964 | } | |
965 | return FALSE; | |
966 | } | |
967 | ||
968 | /* Note: if func adds or deletes resources, then func can get called | |
969 | * more than once for some resources. If func adds new resources, | |
970 | * func might or might not get called for them. func cannot both | |
971 | * add and delete an equal number of resources! | |
972 | */ | |
973 | ||
974 | void | |
975 | FindClientResourcesByType(ClientPtr client, | |
976 | RESTYPE type, FindResType func, pointer cdata) | |
977 | { | |
978 | ResourcePtr *resources; | |
979 | ResourcePtr this, next; | |
980 | int i, elements; | |
981 | int *eltptr; | |
982 | ||
983 | if (!client) | |
984 | client = serverClient; | |
985 | ||
986 | resources = clientTable[client->index].resources; | |
987 | eltptr = &clientTable[client->index].elements; | |
988 | for (i = 0; i < clientTable[client->index].buckets; i++) { | |
989 | for (this = resources[i]; this; this = next) { | |
990 | next = this->next; | |
991 | if (!type || this->type == type) { | |
992 | elements = *eltptr; | |
993 | (*func) (this->value, this->id, cdata); | |
994 | if (*eltptr != elements) | |
995 | next = resources[i]; /* start over */ | |
996 | } | |
997 | } | |
998 | } | |
999 | } | |
1000 | ||
1001 | void FindSubResources(pointer resource, | |
1002 | RESTYPE type, | |
1003 | FindAllRes func, | |
1004 | pointer cdata) | |
1005 | { | |
1006 | struct ResourceType rtype = resourceTypes[type & TypeMask]; | |
1007 | rtype.findSubResFunc(resource, func, cdata); | |
1008 | } | |
1009 | ||
1010 | void | |
1011 | FindAllClientResources(ClientPtr client, FindAllRes func, pointer cdata) | |
1012 | { | |
1013 | ResourcePtr *resources; | |
1014 | ResourcePtr this, next; | |
1015 | int i, elements; | |
1016 | int *eltptr; | |
1017 | ||
1018 | if (!client) | |
1019 | client = serverClient; | |
1020 | ||
1021 | resources = clientTable[client->index].resources; | |
1022 | eltptr = &clientTable[client->index].elements; | |
1023 | for (i = 0; i < clientTable[client->index].buckets; i++) { | |
1024 | for (this = resources[i]; this; this = next) { | |
1025 | next = this->next; | |
1026 | elements = *eltptr; | |
1027 | (*func) (this->value, this->id, this->type, cdata); | |
1028 | if (*eltptr != elements) | |
1029 | next = resources[i]; /* start over */ | |
1030 | } | |
1031 | } | |
1032 | } | |
1033 | ||
1034 | pointer | |
1035 | LookupClientResourceComplex(ClientPtr client, | |
1036 | RESTYPE type, | |
1037 | FindComplexResType func, pointer cdata) | |
1038 | { | |
1039 | ResourcePtr *resources; | |
1040 | ResourcePtr this, next; | |
1041 | pointer value; | |
1042 | int i; | |
1043 | ||
1044 | if (!client) | |
1045 | client = serverClient; | |
1046 | ||
1047 | resources = clientTable[client->index].resources; | |
1048 | for (i = 0; i < clientTable[client->index].buckets; i++) { | |
1049 | for (this = resources[i]; this; this = next) { | |
1050 | next = this->next; | |
1051 | if (!type || this->type == type) { | |
1052 | /* workaround func freeing the type as DRI1 does */ | |
1053 | value = this->value; | |
1054 | if ((*func) (value, this->id, cdata)) | |
1055 | return value; | |
1056 | } | |
1057 | } | |
1058 | } | |
1059 | return NULL; | |
1060 | } | |
1061 | ||
1062 | void | |
1063 | FreeClientNeverRetainResources(ClientPtr client) | |
1064 | { | |
1065 | ResourcePtr *resources; | |
1066 | ResourcePtr this; | |
1067 | ResourcePtr *prev; | |
1068 | int j, elements; | |
1069 | int *eltptr; | |
1070 | ||
1071 | if (!client) | |
1072 | return; | |
1073 | ||
1074 | resources = clientTable[client->index].resources; | |
1075 | eltptr = &clientTable[client->index].elements; | |
1076 | for (j = 0; j < clientTable[client->index].buckets; j++) { | |
1077 | prev = &resources[j]; | |
1078 | while ((this = *prev)) { | |
1079 | RESTYPE rtype = this->type; | |
1080 | ||
1081 | if (rtype & RC_NEVERRETAIN) { | |
1082 | #ifdef XSERVER_DTRACE | |
1083 | XSERVER_RESOURCE_FREE(this->id, this->type, | |
1084 | this->value, TypeNameString(this->type)); | |
1085 | #endif | |
1086 | *prev = this->next; | |
1087 | clientTable[client->index].elements--; | |
1088 | elements = *eltptr; | |
1089 | ||
1090 | doFreeResource(this, FALSE); | |
1091 | ||
1092 | if (*eltptr != elements) | |
1093 | prev = &resources[j]; /* prev may no longer be valid */ | |
1094 | } | |
1095 | else | |
1096 | prev = &this->next; | |
1097 | } | |
1098 | } | |
1099 | } | |
1100 | ||
1101 | void | |
1102 | FreeClientResources(ClientPtr client) | |
1103 | { | |
1104 | ResourcePtr *resources; | |
1105 | ResourcePtr this; | |
1106 | int j; | |
1107 | ||
1108 | /* This routine shouldn't be called with a null client, but just in | |
1109 | case ... */ | |
1110 | ||
1111 | if (!client) | |
1112 | return; | |
1113 | ||
1114 | HandleSaveSet(client); | |
1115 | ||
1116 | resources = clientTable[client->index].resources; | |
1117 | for (j = 0; j < clientTable[client->index].buckets; j++) { | |
1118 | /* It may seem silly to update the head of this resource list as | |
1119 | we delete the members, since the entire list will be deleted any way, | |
1120 | but there are some resource deletion functions "FreeClientPixels" for | |
1121 | one which do a LookupID on another resource id (a Colormap id in this | |
1122 | case), so the resource list must be kept valid up to the point that | |
1123 | it is deleted, so every time we delete a resource, we must update the | |
1124 | head, just like in FreeResource. I hope that this doesn't slow down | |
1125 | mass deletion appreciably. PRH */ | |
1126 | ||
1127 | ResourcePtr *head; | |
1128 | ||
1129 | head = &resources[j]; | |
1130 | ||
1131 | for (this = *head; this; this = *head) { | |
1132 | #ifdef XSERVER_DTRACE | |
1133 | XSERVER_RESOURCE_FREE(this->id, this->type, | |
1134 | this->value, TypeNameString(this->type)); | |
1135 | #endif | |
1136 | *head = this->next; | |
1137 | clientTable[client->index].elements--; | |
1138 | ||
1139 | doFreeResource(this, FALSE); | |
1140 | } | |
1141 | } | |
1142 | free(clientTable[client->index].resources); | |
1143 | clientTable[client->index].resources = NULL; | |
1144 | clientTable[client->index].buckets = 0; | |
1145 | } | |
1146 | ||
1147 | void | |
1148 | FreeAllResources(void) | |
1149 | { | |
1150 | int i; | |
1151 | ||
1152 | for (i = currentMaxClients; --i >= 0;) { | |
1153 | if (clientTable[i].buckets) | |
1154 | FreeClientResources(clients[i]); | |
1155 | } | |
1156 | } | |
1157 | ||
1158 | Bool | |
1159 | LegalNewID(XID id, ClientPtr client) | |
1160 | { | |
1161 | pointer val; | |
1162 | int rc; | |
1163 | ||
1164 | #ifdef PANORAMIX | |
1165 | XID minid, maxid; | |
1166 | ||
1167 | if (!noPanoramiXExtension) { | |
1168 | minid = client->clientAsMask | (client->index ? | |
1169 | SERVER_BIT : SERVER_MINID); | |
1170 | maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1; | |
1171 | if ((id >= minid) && (id <= maxid)) | |
1172 | return TRUE; | |
1173 | } | |
1174 | #endif /* PANORAMIX */ | |
1175 | if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) { | |
1176 | rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, | |
1177 | DixGetAttrAccess); | |
1178 | return rc == BadValue; | |
1179 | } | |
1180 | return FALSE; | |
1181 | } | |
1182 | ||
1183 | int | |
1184 | dixLookupResourceByType(pointer *result, XID id, RESTYPE rtype, | |
1185 | ClientPtr client, Mask mode) | |
1186 | { | |
1187 | int cid = CLIENT_ID(id); | |
1188 | ResourcePtr res = NULL; | |
1189 | ||
1190 | *result = NULL; | |
1191 | if ((rtype & TypeMask) > lastResourceType) | |
1192 | return BadImplementation; | |
1193 | ||
1194 | if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { | |
1195 | res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; | |
1196 | ||
1197 | for (; res; res = res->next) | |
1198 | if (res->id == id && res->type == rtype) | |
1199 | break; | |
1200 | } | |
1201 | if (!res) | |
1202 | return resourceTypes[rtype & TypeMask].errorValue; | |
1203 | ||
1204 | if (client) { | |
1205 | client->errorValue = id; | |
1206 | cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, | |
1207 | res->value, RT_NONE, NULL, mode); | |
1208 | if (cid == BadValue) | |
1209 | return resourceTypes[rtype & TypeMask].errorValue; | |
1210 | if (cid != Success) | |
1211 | return cid; | |
1212 | } | |
1213 | ||
1214 | *result = res->value; | |
1215 | return Success; | |
1216 | } | |
1217 | ||
1218 | int | |
1219 | dixLookupResourceByClass(pointer *result, XID id, RESTYPE rclass, | |
1220 | ClientPtr client, Mask mode) | |
1221 | { | |
1222 | int cid = CLIENT_ID(id); | |
1223 | ResourcePtr res = NULL; | |
1224 | ||
1225 | *result = NULL; | |
1226 | ||
1227 | if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { | |
1228 | res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; | |
1229 | ||
1230 | for (; res; res = res->next) | |
1231 | if (res->id == id && (res->type & rclass)) | |
1232 | break; | |
1233 | } | |
1234 | if (!res) | |
1235 | return BadValue; | |
1236 | ||
1237 | if (client) { | |
1238 | client->errorValue = id; | |
1239 | cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, | |
1240 | res->value, RT_NONE, NULL, mode); | |
1241 | if (cid != Success) | |
1242 | return cid; | |
1243 | } | |
1244 | ||
1245 | *result = res->value; | |
1246 | return Success; | |
1247 | } |