resource.c revision 35c4bbdf
1/************************************************************
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27                        All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45********************************************************/
46/* The panoramix components contained the following notice */
47/*****************************************************************
48
49Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
50
51Permission is hereby granted, free of charge, to any person obtaining a copy
52of this software and associated documentation files (the "Software"), to deal
53in the Software without restriction, including without limitation the rights
54to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
55copies of the Software.
56
57The above copyright notice and this permission notice shall be included in
58all copies or substantial portions of the Software.
59
60THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
63DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
64BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
65WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
66IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
67
68Except as contained in this notice, the name of Digital Equipment Corporation
69shall not be used in advertising or otherwise to promote the sale, use or other
70dealings in this Software without prior written authorization from Digital
71Equipment Corporation.
72
73******************************************************************/
74/* XSERVER_DTRACE additions:
75 * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved.
76 *
77 * Permission is hereby granted, free of charge, to any person obtaining a
78 * copy of this software and associated documentation files (the "Software"),
79 * to deal in the Software without restriction, including without limitation
80 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
81 * and/or sell copies of the Software, and to permit persons to whom the
82 * Software is furnished to do so, subject to the following conditions:
83 *
84 * The above copyright notice and this permission notice (including the next
85 * paragraph) shall be included in all copies or substantial portions of the
86 * Software.
87 *
88 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
89 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
90 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
91 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
92 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
93 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
94 * DEALINGS IN THE SOFTWARE.
95 */
96
97/*	Routines to manage various kinds of resources:
98 *
99 *	CreateNewResourceType, CreateNewResourceClass, InitClientResources,
100 *	FakeClientID, AddResource, FreeResource, FreeClientResources,
101 *	FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange
102 */
103
104/*
105 *      A resource ID is a 32 bit quantity, the upper 2 bits of which are
106 *	off-limits for client-visible resources.  The next 8 bits are
107 *      used as client ID, and the low 22 bits come from the client.
108 *	A resource ID is "hashed" by extracting and xoring subfields
109 *      (varying with the size of the hash table).
110 *
111 *      It is sometimes necessary for the server to create an ID that looks
112 *      like it belongs to a client.  This ID, however,  must not be one
113 *      the client actually can create, or we have the potential for conflict.
114 *      The 31st bit of the ID is reserved for the server's use for this
115 *      purpose.  By setting CLIENT_ID(id) to the client, the SERVER_BIT to
116 *      1, and an otherwise arbitrary ID in the low 22 bits, we can create a
117 *      resource "owned" by the client.
118 */
119
120#ifdef HAVE_DIX_CONFIG_H
121#include <dix-config.h>
122#endif
123
124#include <X11/X.h>
125#include "misc.h"
126#include "os.h"
127#include "resource.h"
128#include "dixstruct.h"
129#include "opaque.h"
130#include "windowstr.h"
131#include "dixfont.h"
132#include "colormap.h"
133#include "inputstr.h"
134#include "dixevents.h"
135#include "dixgrabs.h"
136#include "cursor.h"
137#ifdef PANORAMIX
138#include "panoramiX.h"
139#include "panoramiXsrv.h"
140#endif
141#include "xace.h"
142#include <assert.h>
143#include "registry.h"
144#include "gcstruct.h"
145
146#ifdef XSERVER_DTRACE
147#include "probes.h"
148
149#define TypeNameString(t) LookupResourceName(t)
150#endif
151
152static void RebuildTable(int    /*client */
153    );
154
155#define SERVER_MINID 32
156
157#define INITBUCKETS 64
158#define INITHASHSIZE 6
159#define MAXHASHSIZE 11
160
161typedef struct _Resource {
162    struct _Resource *next;
163    XID id;
164    RESTYPE type;
165    void *value;
166} ResourceRec, *ResourcePtr;
167
168typedef 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
177RESTYPE lastResourceType;
178static RESTYPE lastResourceClass;
179RESTYPE TypeMask;
180
181struct 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 */
202static void
203GetDefaultBytes(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 */
223static void
224DefaultFindSubRes(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 */
237static unsigned long
238GetDrawableBytes(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 */
267static void
268GetPixmapBytes(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 */
296static void
297GetWindowBytes(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 */
338static void
339FindWindowSubRes(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 */
369static void
370GetGcBytes(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 */
410static void
411FindGCSubRes(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
429static struct ResourceType *resourceTypes;
430
431static 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
494CallbackListPtr ResourceStateCallback;
495
496static _X_INLINE void
497CallResourceStateCallback(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
505RESTYPE
506CreateNewResourceType(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 */
542SizeType
543GetResourceTypeSizeFunc(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 */
559void
560SetResourceTypeSizeFunc(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 */
577void
578SetResourceTypeFindSubResFunc(RESTYPE type, FindTypeSubResources findFunc)
579{
580    resourceTypes[type & TypeMask].findSubResFunc = findFunc;
581}
582
583void
584SetResourceTypeErrorValue(RESTYPE type, int errorValue)
585{
586    resourceTypes[type & TypeMask].errorValue = errorValue;
587}
588
589RESTYPE
590CreateNewResourceClass(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
601static ClientResourceRec clientTable[MAXCLIENTS];
602
603static unsigned int
604ilog2(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
620unsigned int
621ResourceClientBits(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
632Bool
633InitClientResources(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
668int
669HashResourceID(XID id, int numBits)
670{
671    id &= RESOURCE_ID_MASK;
672    switch (numBits)
673    {
674        case 6:
675            return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12))));
676        case 7:
677            return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13))));
678        case 8:
679            return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16))));
680        case 9:
681            return ((int)(0x1FF & (id ^ (id>>9))));
682        case 10:
683            return ((int)(0x3FF & (id ^ (id>>10))));
684        case 11:
685            return ((int)(0x7FF & (id ^ (id>>11))));
686    }
687    if (numBits >= 11)
688        return ((int)(0x7FF & (id ^ (id>>11))));
689    else
690    {
691        assert(numBits >= 0);
692        return id & ~((~0) << numBits);
693    }
694}
695
696static XID
697AvailableID(int client, XID id, XID maxid, XID goodid)
698{
699    ResourcePtr res;
700
701    if ((goodid >= id) && (goodid <= maxid))
702        return goodid;
703    for (; id <= maxid; id++) {
704        res = clientTable[client].resources[HashResourceID(id, clientTable[client].hashsize)];
705        while (res && (res->id != id))
706            res = res->next;
707        if (!res)
708            return id;
709    }
710    return 0;
711}
712
713void
714GetXIDRange(int client, Bool server, XID *minp, XID *maxp)
715{
716    XID id, maxid;
717    ResourcePtr *resp;
718    ResourcePtr res;
719    int i;
720    XID goodid;
721
722    id = (Mask) client << CLIENTOFFSET;
723    if (server)
724        id |= client ? SERVER_BIT : SERVER_MINID;
725    maxid = id | RESOURCE_ID_MASK;
726    goodid = 0;
727    for (resp = clientTable[client].resources, i = clientTable[client].buckets;
728         --i >= 0;) {
729        for (res = *resp++; res; res = res->next) {
730            if ((res->id < id) || (res->id > maxid))
731                continue;
732            if (((res->id - id) >= (maxid - res->id)) ?
733                (goodid = AvailableID(client, id, res->id - 1, goodid)) :
734                !(goodid = AvailableID(client, res->id + 1, maxid, goodid)))
735                maxid = res->id - 1;
736            else
737                id = res->id + 1;
738        }
739    }
740    if (id > maxid)
741        id = maxid = 0;
742    *minp = id;
743    *maxp = maxid;
744}
745
746/**
747 *  GetXIDList is called by the XC-MISC extension's MiscGetXIDList function.
748 *  This function tries to find count unused XIDs for the given client.  It
749 *  puts the IDs in the array pids and returns the number found, which should
750 *  almost always be the number requested.
751 *
752 *  The circumstances that lead to a call to this function are very rare.
753 *  Xlib must run out of IDs while trying to generate a request that wants
754 *  multiple ID's, like the Multi-buffering CreateImageBuffers request.
755 *
756 *  No rocket science in the implementation; just iterate over all
757 *  possible IDs for the given client and pick the first count IDs
758 *  that aren't in use.  A more efficient algorithm could probably be
759 *  invented, but this will be used so rarely that this should suffice.
760 */
761
762unsigned int
763GetXIDList(ClientPtr pClient, unsigned count, XID *pids)
764{
765    unsigned int found = 0;
766    XID rc, id = pClient->clientAsMask;
767    XID maxid;
768    void *val;
769
770    maxid = id | RESOURCE_ID_MASK;
771    while ((found < count) && (id <= maxid)) {
772        rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
773                                      DixGetAttrAccess);
774        if (rc == BadValue) {
775            pids[found++] = id;
776        }
777        id++;
778    }
779    return found;
780}
781
782/*
783 * Return the next usable fake client ID.
784 *
785 * Normally this is just the next one in line, but if we've used the last
786 * in the range, we need to find a new range of safe IDs to avoid
787 * over-running another client.
788 */
789
790XID
791FakeClientID(int client)
792{
793    XID id, maxid;
794
795    id = clientTable[client].fakeID++;
796    if (id != clientTable[client].endFakeID)
797        return id;
798    GetXIDRange(client, TRUE, &id, &maxid);
799    if (!id) {
800        if (!client)
801            FatalError("FakeClientID: server internal ids exhausted\n");
802        MarkClientException(clients[client]);
803        id = ((Mask) client << CLIENTOFFSET) | (SERVER_BIT * 3);
804        maxid = id | RESOURCE_ID_MASK;
805    }
806    clientTable[client].fakeID = id + 1;
807    clientTable[client].endFakeID = maxid + 1;
808    return id;
809}
810
811Bool
812AddResource(XID id, RESTYPE type, void *value)
813{
814    int client;
815    ClientResourceRec *rrec;
816    ResourcePtr res, *head;
817
818#ifdef XSERVER_DTRACE
819    XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type));
820#endif
821    client = CLIENT_ID(id);
822    rrec = &clientTable[client];
823    if (!rrec->buckets) {
824        ErrorF("[dix] AddResource(%lx, %x, %lx), client=%d \n",
825               (unsigned long) id, type, (unsigned long) value, client);
826        FatalError("client not in use\n");
827    }
828    if ((rrec->elements >= 4 * rrec->buckets) && (rrec->hashsize < MAXHASHSIZE))
829        RebuildTable(client);
830    head = &rrec->resources[HashResourceID(id, clientTable[client].hashsize)];
831    res = malloc(sizeof(ResourceRec));
832    if (!res) {
833        (*resourceTypes[type & TypeMask].deleteFunc) (value, id);
834        return FALSE;
835    }
836    res->next = *head;
837    res->id = id;
838    res->type = type;
839    res->value = value;
840    *head = res;
841    rrec->elements++;
842    CallResourceStateCallback(ResourceStateAdding, res);
843    return TRUE;
844}
845
846static void
847RebuildTable(int client)
848{
849    int j;
850    ResourcePtr res, next;
851    ResourcePtr **tails, *resources;
852    ResourcePtr **tptr, *rptr;
853
854    /*
855     * For now, preserve insertion order, since some ddx layers depend
856     * on resources being free in the opposite order they are added.
857     */
858
859    j = 2 * clientTable[client].buckets;
860    tails =  xallocarray(j, sizeof(ResourcePtr *));
861    if (!tails)
862        return;
863    resources =  xallocarray(j, sizeof(ResourcePtr));
864    if (!resources) {
865        free(tails);
866        return;
867    }
868    for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) {
869        *rptr = NULL;
870        *tptr = rptr;
871    }
872    clientTable[client].hashsize++;
873    for (j = clientTable[client].buckets,
874         rptr = clientTable[client].resources; --j >= 0; rptr++) {
875        for (res = *rptr; res; res = next) {
876            next = res->next;
877            res->next = NULL;
878            tptr = &tails[HashResourceID(res->id, clientTable[client].hashsize)];
879            **tptr = res;
880            *tptr = &res->next;
881        }
882    }
883    free(tails);
884    clientTable[client].buckets *= 2;
885    free(clientTable[client].resources);
886    clientTable[client].resources = resources;
887}
888
889static void
890doFreeResource(ResourcePtr res, Bool skip)
891{
892    CallResourceStateCallback(ResourceStateFreeing, res);
893
894    if (!skip)
895        resourceTypes[res->type & TypeMask].deleteFunc(res->value, res->id);
896
897    free(res);
898}
899
900void
901FreeResource(XID id, RESTYPE skipDeleteFuncType)
902{
903    int cid;
904    ResourcePtr res;
905    ResourcePtr *prev, *head;
906    int *eltptr;
907    int elements;
908
909    if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
910        head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
911        eltptr = &clientTable[cid].elements;
912
913        prev = head;
914        while ((res = *prev)) {
915            if (res->id == id) {
916                RESTYPE rtype = res->type;
917
918#ifdef XSERVER_DTRACE
919                XSERVER_RESOURCE_FREE(res->id, res->type,
920                                      res->value, TypeNameString(res->type));
921#endif
922                *prev = res->next;
923                elements = --*eltptr;
924
925                doFreeResource(res, rtype == skipDeleteFuncType);
926
927                if (*eltptr != elements)
928                    prev = head;        /* prev may no longer be valid */
929            }
930            else
931                prev = &res->next;
932        }
933    }
934}
935
936void
937FreeResourceByType(XID id, RESTYPE type, Bool skipFree)
938{
939    int cid;
940    ResourcePtr res;
941    ResourcePtr *prev, *head;
942
943    if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
944        head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
945
946        prev = head;
947        while ((res = *prev)) {
948            if (res->id == id && res->type == type) {
949#ifdef XSERVER_DTRACE
950                XSERVER_RESOURCE_FREE(res->id, res->type,
951                                      res->value, TypeNameString(res->type));
952#endif
953                *prev = res->next;
954                clientTable[cid].elements--;
955
956                doFreeResource(res, skipFree);
957
958                break;
959            }
960            else
961                prev = &res->next;
962        }
963    }
964}
965
966/*
967 * Change the value associated with a resource id.  Caller
968 * is responsible for "doing the right thing" with the old
969 * data
970 */
971
972Bool
973ChangeResourceValue(XID id, RESTYPE rtype, void *value)
974{
975    int cid;
976    ResourcePtr res;
977
978    if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
979        res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
980
981        for (; res; res = res->next)
982            if ((res->id == id) && (res->type == rtype)) {
983                res->value = value;
984                return TRUE;
985            }
986    }
987    return FALSE;
988}
989
990/* Note: if func adds or deletes resources, then func can get called
991 * more than once for some resources.  If func adds new resources,
992 * func might or might not get called for them.  func cannot both
993 * add and delete an equal number of resources!
994 */
995
996void
997FindClientResourcesByType(ClientPtr client,
998                          RESTYPE type, FindResType func, void *cdata)
999{
1000    ResourcePtr *resources;
1001    ResourcePtr this, next;
1002    int i, elements;
1003    int *eltptr;
1004
1005    if (!client)
1006        client = serverClient;
1007
1008    resources = clientTable[client->index].resources;
1009    eltptr = &clientTable[client->index].elements;
1010    for (i = 0; i < clientTable[client->index].buckets; i++) {
1011        for (this = resources[i]; this; this = next) {
1012            next = this->next;
1013            if (!type || this->type == type) {
1014                elements = *eltptr;
1015                (*func) (this->value, this->id, cdata);
1016                if (*eltptr != elements)
1017                    next = resources[i];        /* start over */
1018            }
1019        }
1020    }
1021}
1022
1023void FindSubResources(void *resource,
1024                      RESTYPE    type,
1025                      FindAllRes func,
1026                      void *cdata)
1027{
1028    struct ResourceType rtype = resourceTypes[type & TypeMask];
1029    rtype.findSubResFunc(resource, func, cdata);
1030}
1031
1032void
1033FindAllClientResources(ClientPtr client, FindAllRes func, void *cdata)
1034{
1035    ResourcePtr *resources;
1036    ResourcePtr this, next;
1037    int i, elements;
1038    int *eltptr;
1039
1040    if (!client)
1041        client = serverClient;
1042
1043    resources = clientTable[client->index].resources;
1044    eltptr = &clientTable[client->index].elements;
1045    for (i = 0; i < clientTable[client->index].buckets; i++) {
1046        for (this = resources[i]; this; this = next) {
1047            next = this->next;
1048            elements = *eltptr;
1049            (*func) (this->value, this->id, this->type, cdata);
1050            if (*eltptr != elements)
1051                next = resources[i];    /* start over */
1052        }
1053    }
1054}
1055
1056void *
1057LookupClientResourceComplex(ClientPtr client,
1058                            RESTYPE type,
1059                            FindComplexResType func, void *cdata)
1060{
1061    ResourcePtr *resources;
1062    ResourcePtr this, next;
1063    void *value;
1064    int i;
1065
1066    if (!client)
1067        client = serverClient;
1068
1069    resources = clientTable[client->index].resources;
1070    for (i = 0; i < clientTable[client->index].buckets; i++) {
1071        for (this = resources[i]; this; this = next) {
1072            next = this->next;
1073            if (!type || this->type == type) {
1074                /* workaround func freeing the type as DRI1 does */
1075                value = this->value;
1076                if ((*func) (value, this->id, cdata))
1077                    return value;
1078            }
1079        }
1080    }
1081    return NULL;
1082}
1083
1084void
1085FreeClientNeverRetainResources(ClientPtr client)
1086{
1087    ResourcePtr *resources;
1088    ResourcePtr this;
1089    ResourcePtr *prev;
1090    int j, elements;
1091    int *eltptr;
1092
1093    if (!client)
1094        return;
1095
1096    resources = clientTable[client->index].resources;
1097    eltptr = &clientTable[client->index].elements;
1098    for (j = 0; j < clientTable[client->index].buckets; j++) {
1099        prev = &resources[j];
1100        while ((this = *prev)) {
1101            RESTYPE rtype = this->type;
1102
1103            if (rtype & RC_NEVERRETAIN) {
1104#ifdef XSERVER_DTRACE
1105                XSERVER_RESOURCE_FREE(this->id, this->type,
1106                                      this->value, TypeNameString(this->type));
1107#endif
1108                *prev = this->next;
1109                clientTable[client->index].elements--;
1110                elements = *eltptr;
1111
1112                doFreeResource(this, FALSE);
1113
1114                if (*eltptr != elements)
1115                    prev = &resources[j];       /* prev may no longer be valid */
1116            }
1117            else
1118                prev = &this->next;
1119        }
1120    }
1121}
1122
1123void
1124FreeClientResources(ClientPtr client)
1125{
1126    ResourcePtr *resources;
1127    ResourcePtr this;
1128    int j;
1129
1130    /* This routine shouldn't be called with a null client, but just in
1131       case ... */
1132
1133    if (!client)
1134        return;
1135
1136    HandleSaveSet(client);
1137
1138    resources = clientTable[client->index].resources;
1139    for (j = 0; j < clientTable[client->index].buckets; j++) {
1140        /* It may seem silly to update the head of this resource list as
1141           we delete the members, since the entire list will be deleted any way,
1142           but there are some resource deletion functions "FreeClientPixels" for
1143           one which do a LookupID on another resource id (a Colormap id in this
1144           case), so the resource list must be kept valid up to the point that
1145           it is deleted, so every time we delete a resource, we must update the
1146           head, just like in FreeResource. I hope that this doesn't slow down
1147           mass deletion appreciably. PRH */
1148
1149        ResourcePtr *head;
1150
1151        head = &resources[j];
1152
1153        for (this = *head; this; this = *head) {
1154#ifdef XSERVER_DTRACE
1155            XSERVER_RESOURCE_FREE(this->id, this->type,
1156                                  this->value, TypeNameString(this->type));
1157#endif
1158            *head = this->next;
1159            clientTable[client->index].elements--;
1160
1161            doFreeResource(this, FALSE);
1162        }
1163    }
1164    free(clientTable[client->index].resources);
1165    clientTable[client->index].resources = NULL;
1166    clientTable[client->index].buckets = 0;
1167}
1168
1169void
1170FreeAllResources(void)
1171{
1172    int i;
1173
1174    for (i = currentMaxClients; --i >= 0;) {
1175        if (clientTable[i].buckets)
1176            FreeClientResources(clients[i]);
1177    }
1178}
1179
1180Bool
1181LegalNewID(XID id, ClientPtr client)
1182{
1183    void *val;
1184    int rc;
1185
1186#ifdef PANORAMIX
1187    XID minid, maxid;
1188
1189    if (!noPanoramiXExtension) {
1190        minid = client->clientAsMask | (client->index ?
1191                                        SERVER_BIT : SERVER_MINID);
1192        maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1;
1193        if ((id >= minid) && (id <= maxid))
1194            return TRUE;
1195    }
1196#endif                          /* PANORAMIX */
1197    if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) {
1198        rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
1199                                      DixGetAttrAccess);
1200        return rc == BadValue;
1201    }
1202    return FALSE;
1203}
1204
1205int
1206dixLookupResourceByType(void **result, XID id, RESTYPE rtype,
1207                        ClientPtr client, Mask mode)
1208{
1209    int cid = CLIENT_ID(id);
1210    ResourcePtr res = NULL;
1211
1212    *result = NULL;
1213    if ((rtype & TypeMask) > lastResourceType)
1214        return BadImplementation;
1215
1216    if ((cid < LimitClients) && clientTable[cid].buckets) {
1217        res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
1218
1219        for (; res; res = res->next)
1220            if (res->id == id && res->type == rtype)
1221                break;
1222    }
1223    if (!res)
1224        return resourceTypes[rtype & TypeMask].errorValue;
1225
1226    if (client) {
1227        client->errorValue = id;
1228        cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
1229                       res->value, RT_NONE, NULL, mode);
1230        if (cid == BadValue)
1231            return resourceTypes[rtype & TypeMask].errorValue;
1232        if (cid != Success)
1233            return cid;
1234    }
1235
1236    *result = res->value;
1237    return Success;
1238}
1239
1240int
1241dixLookupResourceByClass(void **result, XID id, RESTYPE rclass,
1242                         ClientPtr client, Mask mode)
1243{
1244    int cid = CLIENT_ID(id);
1245    ResourcePtr res = NULL;
1246
1247    *result = NULL;
1248
1249    if ((cid < LimitClients) && clientTable[cid].buckets) {
1250        res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
1251
1252        for (; res; res = res->next)
1253            if (res->id == id && (res->type & rclass))
1254                break;
1255    }
1256    if (!res)
1257        return BadValue;
1258
1259    if (client) {
1260        client->errorValue = id;
1261        cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
1262                       res->value, RT_NONE, NULL, mode);
1263        if (cid != Success)
1264            return cid;
1265    }
1266
1267    *result = res->value;
1268    return Success;
1269}
1270