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