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