Imported Upstream version 1.15.1
[deb_xorg-server.git] / dix / resource.c
CommitLineData
a09e091a
JB
1/************************************************************
2
3Copyright 1987, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27 All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45********************************************************/
46/* The panoramix components contained the following notice */
47/*****************************************************************
48
49Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
50
51Permission is hereby granted, free of charge, to any person obtaining a copy
52of this software and associated documentation files (the "Software"), to deal
53in the Software without restriction, including without limitation the rights
54to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
55copies of the Software.
56
57The above copyright notice and this permission notice shall be included in
58all copies or substantial portions of the Software.
59
60THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
63DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
64BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
65WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
66IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
67
68Except as contained in this notice, the name of Digital Equipment Corporation
69shall not be used in advertising or otherwise to promote the sale, use or other
70dealings in this Software without prior written authorization from Digital
71Equipment 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>
148typedef const char *string;
149
150#include "Xserver-dtrace.h"
151
152#define TypeNameString(t) LookupResourceName(t)
153#endif
154
155static 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
164typedef struct _Resource {
165 struct _Resource *next;
166 XID id;
167 RESTYPE type;
168 pointer value;
169} ResourceRec, *ResourcePtr;
170
171typedef 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
180RESTYPE lastResourceType;
181static RESTYPE lastResourceClass;
182RESTYPE TypeMask;
183
184struct 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 */
205static void
206GetDefaultBytes(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 */
226static void
227DefaultFindSubRes(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 */
240static unsigned long
241GetDrawableBytes(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 */
270static void
271GetPixmapBytes(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 */
299static void
300GetWindowBytes(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 */
341static void
342FindWindowSubRes(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 */
372static void
373GetGcBytes(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 */
413static void
414FindGCSubRes(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
432static struct ResourceType *resourceTypes;
433
434static 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
497CallbackListPtr ResourceStateCallback;
498
499static _X_INLINE void
500CallResourceStateCallback(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
508RESTYPE
509CreateNewResourceType(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 */
543SizeType
544GetResourceTypeSizeFunc(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 */
560void
561SetResourceTypeSizeFunc(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 */
578void
579SetResourceTypeFindSubResFunc(RESTYPE type, FindTypeSubResources findFunc)
580{
581 resourceTypes[type & TypeMask].findSubResFunc = findFunc;
582}
583
584void
585SetResourceTypeErrorValue(RESTYPE type, int errorValue)
586{
587 resourceTypes[type & TypeMask].errorValue = errorValue;
588}
589
590RESTYPE
591CreateNewResourceClass(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
602static 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
610Bool
611InitClientResources(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
646int
647HashResourceID(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
674static XID
675AvailableID(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
691void
692GetXIDRange(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
740unsigned int
741GetXIDList(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
768XID
769FakeClientID(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
789Bool
790AddResource(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
824static void
825RebuildTable(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
867static void
868doFreeResource(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
878void
879FreeResource(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
914void
915FreeResourceByType(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
950Bool
951ChangeResourceValue(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
974void
975FindClientResourcesByType(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
1001void 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
1010void
1011FindAllClientResources(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
1034pointer
1035LookupClientResourceComplex(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
1062void
1063FreeClientNeverRetainResources(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
1101void
1102FreeClientResources(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
1147void
1148FreeAllResources(void)
1149{
1150 int i;
1151
1152 for (i = currentMaxClients; --i >= 0;) {
1153 if (clientTable[i].buckets)
1154 FreeClientResources(clients[i]);
1155 }
1156}
1157
1158Bool
1159LegalNewID(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
1183int
1184dixLookupResourceByType(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
1218int
1219dixLookupResourceByClass(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}