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