1 /************************************************************
3 Copyright 1987, 1998 The Open Group
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
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
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.
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.
25 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
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.
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
45 ********************************************************/
46 /* The panoramix components contained the following notice */
47 /*****************************************************************
49 Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
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.
57 The above copyright notice and this permission notice shall be included in
58 all copies or substantial portions of the Software.
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.
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.
73 ******************************************************************/
74 /* XSERVER_DTRACE additions:
75 * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved.
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:
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
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.
97 /* Routines to manage various kinds of resources:
99 * CreateNewResourceType, CreateNewResourceClass, InitClientResources,
100 * FakeClientID, AddResource, FreeResource, FreeClientResources,
101 * FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange
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).
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.
120 #ifdef HAVE_DIX_CONFIG_H
121 #include <dix-config.h>
127 #include "resource.h"
128 #include "dixstruct.h"
130 #include "windowstr.h"
132 #include "colormap.h"
133 #include "inputstr.h"
134 #include "dixevents.h"
135 #include "dixgrabs.h"
138 #include "panoramiX.h"
139 #include "panoramiXsrv.h"
143 #include "registry.h"
144 #include "gcstruct.h"
146 #ifdef XSERVER_DTRACE
147 #include <sys/types.h>
148 typedef const char *string
;
150 #include "Xserver-dtrace.h"
152 #define TypeNameString(t) LookupResourceName(t)
155 static void RebuildTable(int /*client */
158 #define SERVER_MINID 32
160 #define INITBUCKETS 64
161 #define INITHASHSIZE 6
162 #define MAXHASHSIZE 11
164 typedef struct _Resource
{
165 struct _Resource
*next
;
169 } ResourceRec
, *ResourcePtr
;
171 typedef struct _ClientResource
{
172 ResourcePtr
*resources
;
175 int hashsize
; /* log(2)(buckets) */
180 RESTYPE lastResourceType
;
181 static RESTYPE lastResourceClass
;
184 struct ResourceType
{
185 DeleteType deleteFunc
;
187 FindTypeSubResources findSubResFunc
;
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.
196 * @see GetResourceTypeSizeFunc, SetResourceTypeSizeFunc
198 * @param[in] value Pointer to resource object.
200 * @param[in] id Resource ID for the object.
202 * @param[out] size Fill all fields to zero to indicate that size of
203 * resource can't be determined.
206 GetDefaultBytes(pointer value
, XID id
, ResourceSizePtr size
)
208 size
->resourceSize
= 0;
209 size
->pixmapRefSize
= 0;
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.
218 * @see FindSubResources, SetResourceTypeFindSubResFunc
220 * @param[in] value Pointer to resource object.
222 * @param[in] func Function to call for each subresource.
224 * @param[out] cdata Pointer to opaque data.
227 DefaultFindSubRes(pointer value
, FindAllRes func
, pointer cdata
)
233 * Calculate drawable size in bytes. Reference counting is not taken
236 * @param[in] drawable Pointer to a drawable.
238 * @return Estimate of total memory usage for the drawable.
241 GetDrawableBytes(DrawablePtr drawable
)
247 int bytesPerPixel
= drawable
->bitsPerPixel
>> 3;
248 int numberOfPixels
= drawable
->width
* drawable
->height
;
249 bytes
= numberOfPixels
* bytesPerPixel
;
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
262 * @param[in] value Pointer to a pixmap.
264 * @param[in] id Resource ID of pixmap. If the pixmap hasn't been
265 * added as resource, just pass value->drawable.id.
267 * @param[out] size Estimate of memory usage attributed to a single
271 GetPixmapBytes(pointer value
, XID id
, ResourceSizePtr size
)
273 PixmapPtr pixmap
= value
;
275 size
->resourceSize
= 0;
276 size
->pixmapRefSize
= 0;
277 size
->refCnt
= pixmap
->refcnt
;
279 if (pixmap
&& pixmap
->refcnt
)
281 DrawablePtr drawable
= &pixmap
->drawable
;
282 size
->resourceSize
= GetDrawableBytes(drawable
);
283 size
->pixmapRefSize
= size
->resourceSize
/ pixmap
->refcnt
;
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.
292 * @param[in] value Pointer to a window.
294 * @param[in] id Resource ID of window.
296 * @param[out] size Estimate of memory usage attributed to a all
297 * pixmap references of a window.
300 GetWindowBytes(pointer value
, XID id
, ResourceSizePtr size
)
302 SizeType pixmapSizeFunc
= GetResourceTypeSizeFunc(RT_PIXMAP
);
303 ResourceSizeRec pixmapSize
= { 0, 0, 0 };
304 WindowPtr window
= value
;
306 /* Currently only pixmap bytes are reported to clients. */
307 size
->resourceSize
= 0;
309 /* Calculate pixmap reference sizes. */
310 size
->pixmapRefSize
= 0;
314 if (window
->backgroundState
== BackgroundPixmap
)
316 PixmapPtr pixmap
= window
->background
.pixmap
;
317 pixmapSizeFunc(pixmap
, pixmap
->drawable
.id
, &pixmapSize
);
318 size
->pixmapRefSize
+= pixmapSize
.pixmapRefSize
;
320 if (window
->border
.pixmap
&& !window
->borderIsPixel
)
322 PixmapPtr pixmap
= window
->border
.pixmap
;
323 pixmapSizeFunc(pixmap
, pixmap
->drawable
.id
, &pixmapSize
);
324 size
->pixmapRefSize
+= pixmapSize
.pixmapRefSize
;
329 * Iterate through subresources of a window. The purpose of this
330 * function is to gather accurate information on what resources
333 * @note Currently only sub-pixmaps are iterated
335 * @param[in] value Pointer to a window
337 * @param[in] func Function to call with each subresource
339 * @param[out] cdata Pointer to opaque data
342 FindWindowSubRes(pointer value
, FindAllRes func
, pointer cdata
)
344 WindowPtr window
= value
;
346 /* Currently only pixmap subresources are reported to clients. */
348 if (window
->backgroundState
== BackgroundPixmap
)
350 PixmapPtr pixmap
= window
->background
.pixmap
;
351 func(window
->background
.pixmap
, pixmap
->drawable
.id
, RT_PIXMAP
, cdata
);
353 if (window
->border
.pixmap
&& !window
->borderIsPixel
)
355 PixmapPtr pixmap
= window
->border
.pixmap
;
356 func(window
->background
.pixmap
, pixmap
->drawable
.id
, RT_PIXMAP
, cdata
);
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.
365 * @param[in] value Pointer to a graphics context.
367 * @param[in] id Resource ID of graphics context.
369 * @param[out] size Estimate of memory usage attributed to a all
370 * pixmap references of a graphics context.
373 GetGcBytes(pointer value
, XID id
, ResourceSizePtr size
)
375 SizeType pixmapSizeFunc
= GetResourceTypeSizeFunc(RT_PIXMAP
);
376 ResourceSizeRec pixmapSize
= { 0, 0, 0 };
379 /* Currently only pixmap bytes are reported to clients. */
380 size
->resourceSize
= 0;
382 /* Calculate pixmap reference sizes. */
383 size
->pixmapRefSize
= 0;
388 PixmapPtr pixmap
= gc
->stipple
;
389 pixmapSizeFunc(pixmap
, pixmap
->drawable
.id
, &pixmapSize
);
390 size
->pixmapRefSize
+= pixmapSize
.pixmapRefSize
;
392 if (gc
->tile
.pixmap
&& !gc
->tileIsPixel
)
394 PixmapPtr pixmap
= gc
->tile
.pixmap
;
395 pixmapSizeFunc(pixmap
, pixmap
->drawable
.id
, &pixmapSize
);
396 size
->pixmapRefSize
+= pixmapSize
.pixmapRefSize
;
401 * Iterate through subresources of a graphics context. The purpose of
402 * this function is to gather accurate information on what resources a
405 * @note Currently only sub-pixmaps are iterated
407 * @param[in] value Pointer to a window
409 * @param[in] func Function to call with each subresource
411 * @param[out] cdata Pointer to opaque data
414 FindGCSubRes(pointer value
, FindAllRes func
, pointer cdata
)
418 /* Currently only pixmap subresources are reported to clients. */
422 PixmapPtr pixmap
= gc
->stipple
;
423 func(pixmap
, pixmap
->drawable
.id
, RT_PIXMAP
, cdata
);
425 if (gc
->tile
.pixmap
&& !gc
->tileIsPixel
)
427 PixmapPtr pixmap
= gc
->tile
.pixmap
;
428 func(pixmap
, pixmap
->drawable
.id
, RT_PIXMAP
, cdata
);
432 static struct ResourceType
*resourceTypes
;
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
,
441 [RT_WINDOW
& (RC_LASTPREDEF
- 1)] = {
442 .deleteFunc
= DeleteWindow
,
443 .sizeFunc
= GetWindowBytes
,
444 .findSubResFunc
= FindWindowSubRes
,
445 .errorValue
= BadWindow
,
447 [RT_PIXMAP
& (RC_LASTPREDEF
- 1)] = {
448 .deleteFunc
= dixDestroyPixmap
,
449 .sizeFunc
= GetPixmapBytes
,
450 .findSubResFunc
= DefaultFindSubRes
,
451 .errorValue
= BadPixmap
,
453 [RT_GC
& (RC_LASTPREDEF
- 1)] = {
454 .deleteFunc
= FreeGC
,
455 .sizeFunc
= GetGcBytes
,
456 .findSubResFunc
= FindGCSubRes
,
459 [RT_FONT
& (RC_LASTPREDEF
- 1)] = {
460 .deleteFunc
= CloseFont
,
461 .sizeFunc
= GetDefaultBytes
,
462 .findSubResFunc
= DefaultFindSubRes
,
463 .errorValue
= BadFont
,
465 [RT_CURSOR
& (RC_LASTPREDEF
- 1)] = {
466 .deleteFunc
= FreeCursor
,
467 .sizeFunc
= GetDefaultBytes
,
468 .findSubResFunc
= DefaultFindSubRes
,
469 .errorValue
= BadCursor
,
471 [RT_COLORMAP
& (RC_LASTPREDEF
- 1)] = {
472 .deleteFunc
= FreeColormap
,
473 .sizeFunc
= GetDefaultBytes
,
474 .findSubResFunc
= DefaultFindSubRes
,
475 .errorValue
= BadColor
,
477 [RT_CMAPENTRY
& (RC_LASTPREDEF
- 1)] = {
478 .deleteFunc
= FreeClientPixels
,
479 .sizeFunc
= GetDefaultBytes
,
480 .findSubResFunc
= DefaultFindSubRes
,
481 .errorValue
= BadColor
,
483 [RT_OTHERCLIENT
& (RC_LASTPREDEF
- 1)] = {
484 .deleteFunc
= OtherClientGone
,
485 .sizeFunc
= GetDefaultBytes
,
486 .findSubResFunc
= DefaultFindSubRes
,
487 .errorValue
= BadValue
,
489 [RT_PASSIVEGRAB
& (RC_LASTPREDEF
- 1)] = {
490 .deleteFunc
= DeletePassiveGrab
,
491 .sizeFunc
= GetDefaultBytes
,
492 .findSubResFunc
= DefaultFindSubRes
,
493 .errorValue
= BadValue
,
497 CallbackListPtr ResourceStateCallback
;
499 static _X_INLINE
void
500 CallResourceStateCallback(ResourceState state
, ResourceRec
* res
)
502 if (ResourceStateCallback
) {
503 ResourceStateInfoRec rsi
= { state
, res
->id
, res
->type
, res
->value
};
504 CallCallbacks(&ResourceStateCallback
, &rsi
);
509 CreateNewResourceType(DeleteType deleteFunc
, const char *name
)
511 RESTYPE next
= lastResourceType
+ 1;
512 struct ResourceType
*types
;
514 if (next
& lastResourceClass
)
516 types
= realloc(resourceTypes
, (next
+ 1) * sizeof(*resourceTypes
));
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
;
527 /* Called even if name is NULL, to remove any previous entry */
528 RegisterResourceName(next
, name
);
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.
538 * @param[in] type Resource type used in size calculations.
540 * @return Function to calculate the size of a single
544 GetResourceTypeSizeFunc(RESTYPE type
)
546 return resourceTypes
[type
& TypeMask
].sizeFunc
;
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
555 * @param[in] type Resource type used in size calculations.
557 * @param[in] sizeFunc Function to calculate the size of a single
561 SetResourceTypeSizeFunc(RESTYPE type
, SizeType sizeFunc
)
563 resourceTypes
[type
& TypeMask
].sizeFunc
= sizeFunc
;
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.
571 * @see FindSubResources
573 * @param[in] type Resource type used in size calculations.
575 * @param[in] sizeFunc Function to calculate the size of a single
579 SetResourceTypeFindSubResFunc(RESTYPE type
, FindTypeSubResources findFunc
)
581 resourceTypes
[type
& TypeMask
].findSubResFunc
= findFunc
;
585 SetResourceTypeErrorValue(RESTYPE type
, int errorValue
)
587 resourceTypes
[type
& TypeMask
].errorValue
= errorValue
;
591 CreateNewResourceClass(void)
593 RESTYPE next
= lastResourceClass
>> 1;
595 if (next
& lastResourceType
)
597 lastResourceClass
= next
;
602 static ClientResourceRec clientTable
[MAXCLIENTS
];
605 * InitClientResources
606 * When a new client is created, call this to allocate space
611 InitClientResources(ClientPtr client
)
615 if (client
== serverClient
) {
616 lastResourceType
= RT_LASTPREDEF
;
617 lastResourceClass
= RC_LASTPREDEF
;
618 TypeMask
= RC_LASTPREDEF
- 1;
620 resourceTypes
= malloc(sizeof(predefTypes
));
623 memcpy(resourceTypes
, predefTypes
, sizeof(predefTypes
));
625 clientTable
[i
= client
->index
].resources
=
626 malloc(INITBUCKETS
* sizeof(ResourcePtr
));
627 if (!clientTable
[i
].resources
)
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.
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
;
647 HashResourceID(XID id
, int numBits
)
649 id
&= RESOURCE_ID_MASK
;
653 return ((int)(0x03F & (id
^ (id
>>6) ^ (id
>>12))));
655 return ((int)(0x07F & (id
^ (id
>>7) ^ (id
>>13))));
657 return ((int)(0x0FF & (id
^ (id
>>8) ^ (id
>>16))));
659 return ((int)(0x1FF & (id
^ (id
>>9))));
661 return ((int)(0x3FF & (id
^ (id
>>10))));
663 return ((int)(0x7FF & (id
^ (id
>>11))));
666 return ((int)(0x7FF & (id
^ (id
>>11))));
669 assert(numBits
>= 0);
670 return id
& ~((~0) << numBits
);
675 AvailableID(int client
, XID id
, XID maxid
, XID goodid
)
679 if ((goodid
>= id
) && (goodid
<= maxid
))
681 for (; id
<= maxid
; id
++) {
682 res
= clientTable
[client
].resources
[HashResourceID(id
, clientTable
[client
].hashsize
)];
683 while (res
&& (res
->id
!= id
))
692 GetXIDRange(int client
, Bool server
, XID
*minp
, XID
*maxp
)
700 id
= (Mask
) client
<< CLIENTOFFSET
;
702 id
|= client
? SERVER_BIT
: SERVER_MINID
;
703 maxid
= id
| RESOURCE_ID_MASK
;
705 for (resp
= clientTable
[client
].resources
, i
= clientTable
[client
].buckets
;
707 for (res
= *resp
++; res
; res
= res
->next
) {
708 if ((res
->id
< id
) || (res
->id
> maxid
))
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
)))
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.
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.
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.
741 GetXIDList(ClientPtr pClient
, unsigned count
, XID
*pids
)
743 unsigned int found
= 0;
744 XID rc
, id
= pClient
->clientAsMask
;
748 maxid
= id
| RESOURCE_ID_MASK
;
749 while ((found
< count
) && (id
<= maxid
)) {
750 rc
= dixLookupResourceByClass(&val
, id
, RC_ANY
, serverClient
,
752 if (rc
== BadValue
) {
761 * Return the next usable fake client ID.
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.
769 FakeClientID(int client
)
773 id
= clientTable
[client
].fakeID
++;
774 if (id
!= clientTable
[client
].endFakeID
)
776 GetXIDRange(client
, TRUE
, &id
, &maxid
);
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
;
784 clientTable
[client
].fakeID
= id
+ 1;
785 clientTable
[client
].endFakeID
= maxid
+ 1;
790 AddResource(XID id
, RESTYPE type
, pointer value
)
793 ClientResourceRec
*rrec
;
794 ResourcePtr res
, *head
;
796 #ifdef XSERVER_DTRACE
797 XSERVER_RESOURCE_ALLOC(id
, type
, value
, TypeNameString(type
));
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");
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
));
811 (*resourceTypes
[type
& TypeMask
].deleteFunc
) (value
, id
);
820 CallResourceStateCallback(ResourceStateAdding
, res
);
825 RebuildTable(int client
)
828 ResourcePtr res
, next
;
829 ResourcePtr
**tails
, *resources
;
830 ResourcePtr
**tptr
, *rptr
;
833 * For now, preserve insertion order, since some ddx layers depend
834 * on resources being free in the opposite order they are added.
837 j
= 2 * clientTable
[client
].buckets
;
838 tails
= malloc(j
* sizeof(ResourcePtr
*));
841 resources
= malloc(j
* sizeof(ResourcePtr
));
846 for (rptr
= resources
, tptr
= tails
; --j
>= 0; rptr
++, tptr
++) {
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
) {
856 tptr
= &tails
[HashResourceID(res
->id
, clientTable
[client
].hashsize
)];
862 clientTable
[client
].buckets
*= 2;
863 free(clientTable
[client
].resources
);
864 clientTable
[client
].resources
= resources
;
868 doFreeResource(ResourcePtr res
, Bool skip
)
870 CallResourceStateCallback(ResourceStateFreeing
, res
);
873 resourceTypes
[res
->type
& TypeMask
].deleteFunc(res
->value
, res
->id
);
879 FreeResource(XID id
, RESTYPE skipDeleteFuncType
)
883 ResourcePtr
*prev
, *head
;
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
;
892 while ((res
= *prev
)) {
894 RESTYPE rtype
= res
->type
;
896 #ifdef XSERVER_DTRACE
897 XSERVER_RESOURCE_FREE(res
->id
, res
->type
,
898 res
->value
, TypeNameString(res
->type
));
901 elements
= --*eltptr
;
903 doFreeResource(res
, rtype
== skipDeleteFuncType
);
905 if (*eltptr
!= elements
)
906 prev
= head
; /* prev may no longer be valid */
915 FreeResourceByType(XID id
, RESTYPE type
, Bool skipFree
)
919 ResourcePtr
*prev
, *head
;
921 if (((cid
= CLIENT_ID(id
)) < MAXCLIENTS
) && clientTable
[cid
].buckets
) {
922 head
= &clientTable
[cid
].resources
[HashResourceID(id
, clientTable
[cid
].hashsize
)];
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
));
932 clientTable
[cid
].elements
--;
934 doFreeResource(res
, skipFree
);
945 * Change the value associated with a resource id. Caller
946 * is responsible for "doing the right thing" with the old
951 ChangeResourceValue(XID id
, RESTYPE rtype
, pointer value
)
956 if (((cid
= CLIENT_ID(id
)) < MAXCLIENTS
) && clientTable
[cid
].buckets
) {
957 res
= clientTable
[cid
].resources
[HashResourceID(id
, clientTable
[cid
].hashsize
)];
959 for (; res
; res
= res
->next
)
960 if ((res
->id
== id
) && (res
->type
== rtype
)) {
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!
975 FindClientResourcesByType(ClientPtr client
,
976 RESTYPE type
, FindResType func
, pointer cdata
)
978 ResourcePtr
*resources
;
979 ResourcePtr
this, next
;
984 client
= serverClient
;
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
) {
991 if (!type
|| this->type
== type
) {
993 (*func
) (this->value
, this->id
, cdata
);
994 if (*eltptr
!= elements
)
995 next
= resources
[i
]; /* start over */
1001 void FindSubResources(pointer resource
,
1006 struct ResourceType rtype
= resourceTypes
[type
& TypeMask
];
1007 rtype
.findSubResFunc(resource
, func
, cdata
);
1011 FindAllClientResources(ClientPtr client
, FindAllRes func
, pointer cdata
)
1013 ResourcePtr
*resources
;
1014 ResourcePtr
this, next
;
1019 client
= serverClient
;
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
) {
1027 (*func
) (this->value
, this->id
, this->type
, cdata
);
1028 if (*eltptr
!= elements
)
1029 next
= resources
[i
]; /* start over */
1035 LookupClientResourceComplex(ClientPtr client
,
1037 FindComplexResType func
, pointer cdata
)
1039 ResourcePtr
*resources
;
1040 ResourcePtr
this, next
;
1045 client
= serverClient
;
1047 resources
= clientTable
[client
->index
].resources
;
1048 for (i
= 0; i
< clientTable
[client
->index
].buckets
; i
++) {
1049 for (this = resources
[i
]; this; 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
))
1063 FreeClientNeverRetainResources(ClientPtr client
)
1065 ResourcePtr
*resources
;
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
;
1081 if (rtype
& RC_NEVERRETAIN
) {
1082 #ifdef XSERVER_DTRACE
1083 XSERVER_RESOURCE_FREE(this->id
, this->type
,
1084 this->value
, TypeNameString(this->type
));
1087 clientTable
[client
->index
].elements
--;
1090 doFreeResource(this, FALSE
);
1092 if (*eltptr
!= elements
)
1093 prev
= &resources
[j
]; /* prev may no longer be valid */
1102 FreeClientResources(ClientPtr client
)
1104 ResourcePtr
*resources
;
1108 /* This routine shouldn't be called with a null client, but just in
1114 HandleSaveSet(client
);
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 */
1129 head
= &resources
[j
];
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
));
1137 clientTable
[client
->index
].elements
--;
1139 doFreeResource(this, FALSE
);
1142 free(clientTable
[client
->index
].resources
);
1143 clientTable
[client
->index
].resources
= NULL
;
1144 clientTable
[client
->index
].buckets
= 0;
1148 FreeAllResources(void)
1152 for (i
= currentMaxClients
; --i
>= 0;) {
1153 if (clientTable
[i
].buckets
)
1154 FreeClientResources(clients
[i
]);
1159 LegalNewID(XID id
, ClientPtr client
)
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
))
1174 #endif /* PANORAMIX */
1175 if (client
->clientAsMask
== (id
& ~RESOURCE_ID_MASK
)) {
1176 rc
= dixLookupResourceByClass(&val
, id
, RC_ANY
, serverClient
,
1178 return rc
== BadValue
;
1184 dixLookupResourceByType(pointer
*result
, XID id
, RESTYPE rtype
,
1185 ClientPtr client
, Mask mode
)
1187 int cid
= CLIENT_ID(id
);
1188 ResourcePtr res
= NULL
;
1191 if ((rtype
& TypeMask
) > lastResourceType
)
1192 return BadImplementation
;
1194 if ((cid
< MAXCLIENTS
) && clientTable
[cid
].buckets
) {
1195 res
= clientTable
[cid
].resources
[HashResourceID(id
, clientTable
[cid
].hashsize
)];
1197 for (; res
; res
= res
->next
)
1198 if (res
->id
== id
&& res
->type
== rtype
)
1202 return resourceTypes
[rtype
& TypeMask
].errorValue
;
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
;
1214 *result
= res
->value
;
1219 dixLookupResourceByClass(pointer
*result
, XID id
, RESTYPE rclass
,
1220 ClientPtr client
, Mask mode
)
1222 int cid
= CLIENT_ID(id
);
1223 ResourcePtr res
= NULL
;
1227 if ((cid
< MAXCLIENTS
) && clientTable
[cid
].buckets
) {
1228 res
= clientTable
[cid
].resources
[HashResourceID(id
, clientTable
[cid
].hashsize
)];
1230 for (; res
; res
= res
->next
)
1231 if (res
->id
== id
&& (res
->type
& rclass
))
1238 client
->errorValue
= id
;
1239 cid
= XaceHook(XACE_RESOURCE_ACCESS
, client
, id
, res
->type
,
1240 res
->value
, RT_NONE
, NULL
, mode
);
1245 *result
= res
->value
;