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