resource.c revision 1b5d61b8
105b261ecSmrg/************************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1987, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg
2505b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2605b261ecSmrg
2705b261ecSmrg                        All Rights Reserved
2805b261ecSmrg
2935c4bbdfSmrgPermission to use, copy, modify, and distribute this software and its
3035c4bbdfSmrgdocumentation for any purpose and without fee is hereby granted,
3105b261ecSmrgprovided that the above copyright notice appear in all copies and that
3235c4bbdfSmrgboth that copyright notice and this permission notice appear in
3305b261ecSmrgsupporting documentation, and that the name of Digital not be
3405b261ecSmrgused in advertising or publicity pertaining to distribution of the
3535c4bbdfSmrgsoftware without specific, written prior permission.
3605b261ecSmrg
3705b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3805b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
3905b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4005b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4105b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4205b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4305b261ecSmrgSOFTWARE.
4405b261ecSmrg
4505b261ecSmrg********************************************************/
4605b261ecSmrg/* The panoramix components contained the following notice */
4705b261ecSmrg/*****************************************************************
4805b261ecSmrg
4905b261ecSmrgCopyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
5005b261ecSmrg
5105b261ecSmrgPermission is hereby granted, free of charge, to any person obtaining a copy
5205b261ecSmrgof this software and associated documentation files (the "Software"), to deal
5305b261ecSmrgin the Software without restriction, including without limitation the rights
5405b261ecSmrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5505b261ecSmrgcopies of the Software.
5605b261ecSmrg
5705b261ecSmrgThe above copyright notice and this permission notice shall be included in
5805b261ecSmrgall copies or substantial portions of the Software.
5905b261ecSmrg
6005b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6105b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6205b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
6305b261ecSmrgDIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
6405b261ecSmrgBUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
6505b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
6605b261ecSmrgIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6705b261ecSmrg
6805b261ecSmrgExcept as contained in this notice, the name of Digital Equipment Corporation
6905b261ecSmrgshall not be used in advertising or otherwise to promote the sale, use or other
7005b261ecSmrgdealings in this Software without prior written authorization from Digital
7105b261ecSmrgEquipment Corporation.
7205b261ecSmrg
7305b261ecSmrg******************************************************************/
7405b261ecSmrg/* XSERVER_DTRACE additions:
759ace9065Smrg * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved.
7605b261ecSmrg *
7705b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a
786747b715Smrg * copy of this software and associated documentation files (the "Software"),
796747b715Smrg * to deal in the Software without restriction, including without limitation
806747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
816747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the
826747b715Smrg * Software is furnished to do so, subject to the following conditions:
836747b715Smrg *
846747b715Smrg * The above copyright notice and this permission notice (including the next
856747b715Smrg * paragraph) shall be included in all copies or substantial portions of the
866747b715Smrg * Software.
876747b715Smrg *
886747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
896747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
906747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
916747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
926747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
936747b715Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
946747b715Smrg * DEALINGS IN THE SOFTWARE.
9505b261ecSmrg */
9605b261ecSmrg
9705b261ecSmrg/*	Routines to manage various kinds of resources:
9805b261ecSmrg *
9905b261ecSmrg *	CreateNewResourceType, CreateNewResourceClass, InitClientResources,
10005b261ecSmrg *	FakeClientID, AddResource, FreeResource, FreeClientResources,
10105b261ecSmrg *	FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange
10205b261ecSmrg */
10305b261ecSmrg
10435c4bbdfSmrg/*
10505b261ecSmrg *      A resource ID is a 32 bit quantity, the upper 2 bits of which are
10605b261ecSmrg *	off-limits for client-visible resources.  The next 8 bits are
10705b261ecSmrg *      used as client ID, and the low 22 bits come from the client.
10805b261ecSmrg *	A resource ID is "hashed" by extracting and xoring subfields
10905b261ecSmrg *      (varying with the size of the hash table).
11005b261ecSmrg *
11105b261ecSmrg *      It is sometimes necessary for the server to create an ID that looks
11205b261ecSmrg *      like it belongs to a client.  This ID, however,  must not be one
11305b261ecSmrg *      the client actually can create, or we have the potential for conflict.
11405b261ecSmrg *      The 31st bit of the ID is reserved for the server's use for this
11505b261ecSmrg *      purpose.  By setting CLIENT_ID(id) to the client, the SERVER_BIT to
11605b261ecSmrg *      1, and an otherwise arbitrary ID in the low 22 bits, we can create a
11705b261ecSmrg *      resource "owned" by the client.
11805b261ecSmrg */
11905b261ecSmrg
12005b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
12105b261ecSmrg#include <dix-config.h>
12205b261ecSmrg#endif
12305b261ecSmrg
12405b261ecSmrg#include <X11/X.h>
12505b261ecSmrg#include "misc.h"
12605b261ecSmrg#include "os.h"
12705b261ecSmrg#include "resource.h"
12835c4bbdfSmrg#include "dixstruct.h"
12905b261ecSmrg#include "opaque.h"
13005b261ecSmrg#include "windowstr.h"
13105b261ecSmrg#include "dixfont.h"
13205b261ecSmrg#include "colormap.h"
13305b261ecSmrg#include "inputstr.h"
13405b261ecSmrg#include "dixevents.h"
13505b261ecSmrg#include "dixgrabs.h"
13605b261ecSmrg#include "cursor.h"
13705b261ecSmrg#ifdef PANORAMIX
13805b261ecSmrg#include "panoramiX.h"
13905b261ecSmrg#include "panoramiXsrv.h"
14005b261ecSmrg#endif
14105b261ecSmrg#include "xace.h"
14205b261ecSmrg#include <assert.h>
1436747b715Smrg#include "registry.h"
14435c4bbdfSmrg#include "gcstruct.h"
14505b261ecSmrg
14605b261ecSmrg#ifdef XSERVER_DTRACE
14735c4bbdfSmrg#include "probes.h"
14805b261ecSmrg
1494642e01fSmrg#define TypeNameString(t) LookupResourceName(t)
15005b261ecSmrg#endif
15105b261ecSmrg
15235c4bbdfSmrgstatic void RebuildTable(int    /*client */
15335c4bbdfSmrg    );
15405b261ecSmrg
15505b261ecSmrg#define SERVER_MINID 32
15605b261ecSmrg
15705b261ecSmrg#define INITBUCKETS 64
15805b261ecSmrg#define INITHASHSIZE 6
1591b5d61b8Smrg#define MAXHASHSIZE 16
16005b261ecSmrg
16105b261ecSmrgtypedef struct _Resource {
16235c4bbdfSmrg    struct _Resource *next;
16335c4bbdfSmrg    XID id;
16435c4bbdfSmrg    RESTYPE type;
16535c4bbdfSmrg    void *value;
16605b261ecSmrg} ResourceRec, *ResourcePtr;
16705b261ecSmrg
16805b261ecSmrgtypedef struct _ClientResource {
16905b261ecSmrg    ResourcePtr *resources;
17035c4bbdfSmrg    int elements;
17135c4bbdfSmrg    int buckets;
17235c4bbdfSmrg    int hashsize;               /* log(2)(buckets) */
17335c4bbdfSmrg    XID fakeID;
17435c4bbdfSmrg    XID endFakeID;
17505b261ecSmrg} ClientResourceRec;
17605b261ecSmrg
1776747b715SmrgRESTYPE lastResourceType;
17805b261ecSmrgstatic RESTYPE lastResourceClass;
1796747b715SmrgRESTYPE TypeMask;
1806747b715Smrg
1816747b715Smrgstruct ResourceType {
1826747b715Smrg    DeleteType deleteFunc;
18335c4bbdfSmrg    SizeType sizeFunc;
18435c4bbdfSmrg    FindTypeSubResources findSubResFunc;
1856747b715Smrg    int errorValue;
1866747b715Smrg};
1876747b715Smrg
18835c4bbdfSmrg/**
18935c4bbdfSmrg * Used by all resources that don't specify a function to calculate
19035c4bbdfSmrg * resource size. Currently this is used for all resources with
19135c4bbdfSmrg * insignificant memory usage.
19235c4bbdfSmrg *
19335c4bbdfSmrg * @see GetResourceTypeSizeFunc, SetResourceTypeSizeFunc
19435c4bbdfSmrg *
19535c4bbdfSmrg * @param[in] value Pointer to resource object.
19635c4bbdfSmrg *
19735c4bbdfSmrg * @param[in] id Resource ID for the object.
19835c4bbdfSmrg *
19935c4bbdfSmrg * @param[out] size Fill all fields to zero to indicate that size of
20035c4bbdfSmrg *                  resource can't be determined.
20135c4bbdfSmrg */
20235c4bbdfSmrgstatic void
20335c4bbdfSmrgGetDefaultBytes(void *value, XID id, ResourceSizePtr size)
20435c4bbdfSmrg{
20535c4bbdfSmrg    size->resourceSize = 0;
20635c4bbdfSmrg    size->pixmapRefSize = 0;
20735c4bbdfSmrg    size->refCnt = 1;
20835c4bbdfSmrg}
20935c4bbdfSmrg
21035c4bbdfSmrg/**
21135c4bbdfSmrg * Used by all resources that don't specify a function to iterate
21235c4bbdfSmrg * through subresources. Currently this is used for all resources with
21335c4bbdfSmrg * insignificant memory usage.
21435c4bbdfSmrg *
21535c4bbdfSmrg * @see FindSubResources, SetResourceTypeFindSubResFunc
21635c4bbdfSmrg *
21735c4bbdfSmrg * @param[in] value Pointer to resource object.
21835c4bbdfSmrg *
21935c4bbdfSmrg * @param[in] func Function to call for each subresource.
22035c4bbdfSmrg
22135c4bbdfSmrg * @param[out] cdata Pointer to opaque data.
22235c4bbdfSmrg */
22335c4bbdfSmrgstatic void
22435c4bbdfSmrgDefaultFindSubRes(void *value, FindAllRes func, void *cdata)
22535c4bbdfSmrg{
22635c4bbdfSmrg    /* do nothing */
22735c4bbdfSmrg}
22835c4bbdfSmrg
22935c4bbdfSmrg/**
23035c4bbdfSmrg * Calculate drawable size in bytes. Reference counting is not taken
23135c4bbdfSmrg * into account.
23235c4bbdfSmrg *
23335c4bbdfSmrg * @param[in] drawable Pointer to a drawable.
23435c4bbdfSmrg *
23535c4bbdfSmrg * @return Estimate of total memory usage for the drawable.
23635c4bbdfSmrg */
23735c4bbdfSmrgstatic unsigned long
23835c4bbdfSmrgGetDrawableBytes(DrawablePtr drawable)
23935c4bbdfSmrg{
24035c4bbdfSmrg    int bytes = 0;
24135c4bbdfSmrg
24235c4bbdfSmrg    if (drawable)
24335c4bbdfSmrg    {
24435c4bbdfSmrg        int bytesPerPixel = drawable->bitsPerPixel >> 3;
24535c4bbdfSmrg        int numberOfPixels = drawable->width * drawable->height;
24635c4bbdfSmrg        bytes = numberOfPixels * bytesPerPixel;
24735c4bbdfSmrg    }
24835c4bbdfSmrg
24935c4bbdfSmrg    return bytes;
25035c4bbdfSmrg}
25135c4bbdfSmrg
25235c4bbdfSmrg/**
25335c4bbdfSmrg * Calculate pixmap size in bytes. Reference counting is taken into
25435c4bbdfSmrg * account. Any extra data attached by extensions and drivers is not
25535c4bbdfSmrg * taken into account. The purpose of this function is to estimate
25635c4bbdfSmrg * memory usage that can be attributed to single reference of the
25735c4bbdfSmrg * pixmap.
25835c4bbdfSmrg *
25935c4bbdfSmrg * @param[in] value Pointer to a pixmap.
26035c4bbdfSmrg *
26135c4bbdfSmrg * @param[in] id Resource ID of pixmap. If the pixmap hasn't been
26235c4bbdfSmrg *               added as resource, just pass value->drawable.id.
26335c4bbdfSmrg *
26435c4bbdfSmrg * @param[out] size Estimate of memory usage attributed to a single
26535c4bbdfSmrg *                  pixmap reference.
26635c4bbdfSmrg */
26735c4bbdfSmrgstatic void
26835c4bbdfSmrgGetPixmapBytes(void *value, XID id, ResourceSizePtr size)
26935c4bbdfSmrg{
27035c4bbdfSmrg    PixmapPtr pixmap = value;
27135c4bbdfSmrg
27235c4bbdfSmrg    size->resourceSize = 0;
27335c4bbdfSmrg    size->pixmapRefSize = 0;
27435c4bbdfSmrg    size->refCnt = pixmap->refcnt;
27535c4bbdfSmrg
27635c4bbdfSmrg    if (pixmap && pixmap->refcnt)
27735c4bbdfSmrg    {
27835c4bbdfSmrg        DrawablePtr drawable = &pixmap->drawable;
27935c4bbdfSmrg        size->resourceSize = GetDrawableBytes(drawable);
28035c4bbdfSmrg        size->pixmapRefSize = size->resourceSize / pixmap->refcnt;
28135c4bbdfSmrg    }
28235c4bbdfSmrg}
28335c4bbdfSmrg
28435c4bbdfSmrg/**
28535c4bbdfSmrg * Calculate window size in bytes. The purpose of this function is to
28635c4bbdfSmrg * estimate memory usage that can be attributed to all pixmap
28735c4bbdfSmrg * references of the window.
28835c4bbdfSmrg *
28935c4bbdfSmrg * @param[in] value Pointer to a window.
29035c4bbdfSmrg *
29135c4bbdfSmrg * @param[in] id Resource ID of window.
29235c4bbdfSmrg *
29335c4bbdfSmrg * @param[out] size Estimate of memory usage attributed to a all
29435c4bbdfSmrg *                  pixmap references of a window.
29535c4bbdfSmrg */
29635c4bbdfSmrgstatic void
29735c4bbdfSmrgGetWindowBytes(void *value, XID id, ResourceSizePtr size)
29835c4bbdfSmrg{
29935c4bbdfSmrg    SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
30035c4bbdfSmrg    ResourceSizeRec pixmapSize = { 0, 0, 0 };
30135c4bbdfSmrg    WindowPtr window = value;
30235c4bbdfSmrg
30335c4bbdfSmrg    /* Currently only pixmap bytes are reported to clients. */
30435c4bbdfSmrg    size->resourceSize = 0;
30535c4bbdfSmrg
30635c4bbdfSmrg    /* Calculate pixmap reference sizes. */
30735c4bbdfSmrg    size->pixmapRefSize = 0;
30835c4bbdfSmrg
30935c4bbdfSmrg    size->refCnt = 1;
31035c4bbdfSmrg
31135c4bbdfSmrg    if (window->backgroundState == BackgroundPixmap)
31235c4bbdfSmrg    {
31335c4bbdfSmrg        PixmapPtr pixmap = window->background.pixmap;
31435c4bbdfSmrg        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
31535c4bbdfSmrg        size->pixmapRefSize += pixmapSize.pixmapRefSize;
31635c4bbdfSmrg    }
31735c4bbdfSmrg    if (window->border.pixmap && !window->borderIsPixel)
31835c4bbdfSmrg    {
31935c4bbdfSmrg        PixmapPtr pixmap = window->border.pixmap;
32035c4bbdfSmrg        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
32135c4bbdfSmrg        size->pixmapRefSize += pixmapSize.pixmapRefSize;
32235c4bbdfSmrg    }
32335c4bbdfSmrg}
32435c4bbdfSmrg
32535c4bbdfSmrg/**
32635c4bbdfSmrg * Iterate through subresources of a window. The purpose of this
32735c4bbdfSmrg * function is to gather accurate information on what resources
32835c4bbdfSmrg * a resource uses.
32935c4bbdfSmrg *
33035c4bbdfSmrg * @note Currently only sub-pixmaps are iterated
33135c4bbdfSmrg *
33235c4bbdfSmrg * @param[in] value  Pointer to a window
33335c4bbdfSmrg *
33435c4bbdfSmrg * @param[in] func   Function to call with each subresource
33535c4bbdfSmrg *
33635c4bbdfSmrg * @param[out] cdata Pointer to opaque data
33735c4bbdfSmrg */
33835c4bbdfSmrgstatic void
33935c4bbdfSmrgFindWindowSubRes(void *value, FindAllRes func, void *cdata)
34035c4bbdfSmrg{
34135c4bbdfSmrg    WindowPtr window = value;
34235c4bbdfSmrg
34335c4bbdfSmrg    /* Currently only pixmap subresources are reported to clients. */
34435c4bbdfSmrg
34535c4bbdfSmrg    if (window->backgroundState == BackgroundPixmap)
34635c4bbdfSmrg    {
34735c4bbdfSmrg        PixmapPtr pixmap = window->background.pixmap;
34835c4bbdfSmrg        func(window->background.pixmap, pixmap->drawable.id, RT_PIXMAP, cdata);
34935c4bbdfSmrg    }
35035c4bbdfSmrg    if (window->border.pixmap && !window->borderIsPixel)
35135c4bbdfSmrg    {
35235c4bbdfSmrg        PixmapPtr pixmap = window->border.pixmap;
35335c4bbdfSmrg        func(window->background.pixmap, pixmap->drawable.id, RT_PIXMAP, cdata);
35435c4bbdfSmrg    }
35535c4bbdfSmrg}
35635c4bbdfSmrg
35735c4bbdfSmrg/**
35835c4bbdfSmrg * Calculate graphics context size in bytes. The purpose of this
35935c4bbdfSmrg * function is to estimate memory usage that can be attributed to all
36035c4bbdfSmrg * pixmap references of the graphics context.
36135c4bbdfSmrg *
36235c4bbdfSmrg * @param[in] value Pointer to a graphics context.
36335c4bbdfSmrg *
36435c4bbdfSmrg * @param[in] id    Resource ID of graphics context.
36535c4bbdfSmrg *
36635c4bbdfSmrg * @param[out] size Estimate of memory usage attributed to a all
36735c4bbdfSmrg *                  pixmap references of a graphics context.
36835c4bbdfSmrg */
36935c4bbdfSmrgstatic void
37035c4bbdfSmrgGetGcBytes(void *value, XID id, ResourceSizePtr size)
37135c4bbdfSmrg{
37235c4bbdfSmrg    SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
37335c4bbdfSmrg    ResourceSizeRec pixmapSize = { 0, 0, 0 };
37435c4bbdfSmrg    GCPtr gc = value;
37535c4bbdfSmrg
37635c4bbdfSmrg    /* Currently only pixmap bytes are reported to clients. */
37735c4bbdfSmrg    size->resourceSize = 0;
37835c4bbdfSmrg
37935c4bbdfSmrg    /* Calculate pixmap reference sizes. */
38035c4bbdfSmrg    size->pixmapRefSize = 0;
38135c4bbdfSmrg
38235c4bbdfSmrg    size->refCnt = 1;
38335c4bbdfSmrg    if (gc->stipple)
38435c4bbdfSmrg    {
38535c4bbdfSmrg        PixmapPtr pixmap = gc->stipple;
38635c4bbdfSmrg        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
38735c4bbdfSmrg        size->pixmapRefSize += pixmapSize.pixmapRefSize;
38835c4bbdfSmrg    }
38935c4bbdfSmrg    if (gc->tile.pixmap && !gc->tileIsPixel)
39035c4bbdfSmrg    {
39135c4bbdfSmrg        PixmapPtr pixmap = gc->tile.pixmap;
39235c4bbdfSmrg        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
39335c4bbdfSmrg        size->pixmapRefSize += pixmapSize.pixmapRefSize;
39435c4bbdfSmrg    }
39535c4bbdfSmrg}
39635c4bbdfSmrg
39735c4bbdfSmrg/**
39835c4bbdfSmrg * Iterate through subresources of a graphics context. The purpose of
39935c4bbdfSmrg * this function is to gather accurate information on what resources a
40035c4bbdfSmrg * resource uses.
40135c4bbdfSmrg *
40235c4bbdfSmrg * @note Currently only sub-pixmaps are iterated
40335c4bbdfSmrg *
40435c4bbdfSmrg * @param[in] value  Pointer to a window
40535c4bbdfSmrg *
40635c4bbdfSmrg * @param[in] func   Function to call with each subresource
40735c4bbdfSmrg *
40835c4bbdfSmrg * @param[out] cdata Pointer to opaque data
40935c4bbdfSmrg */
41035c4bbdfSmrgstatic void
41135c4bbdfSmrgFindGCSubRes(void *value, FindAllRes func, void *cdata)
41235c4bbdfSmrg{
41335c4bbdfSmrg    GCPtr gc = value;
41435c4bbdfSmrg
41535c4bbdfSmrg    /* Currently only pixmap subresources are reported to clients. */
41635c4bbdfSmrg
41735c4bbdfSmrg    if (gc->stipple)
41835c4bbdfSmrg    {
41935c4bbdfSmrg        PixmapPtr pixmap = gc->stipple;
42035c4bbdfSmrg        func(pixmap, pixmap->drawable.id, RT_PIXMAP, cdata);
42135c4bbdfSmrg    }
42235c4bbdfSmrg    if (gc->tile.pixmap && !gc->tileIsPixel)
42335c4bbdfSmrg    {
42435c4bbdfSmrg        PixmapPtr pixmap = gc->tile.pixmap;
42535c4bbdfSmrg        func(pixmap, pixmap->drawable.id, RT_PIXMAP, cdata);
42635c4bbdfSmrg    }
42735c4bbdfSmrg}
42835c4bbdfSmrg
4296747b715Smrgstatic struct ResourceType *resourceTypes;
43035c4bbdfSmrg
4316747b715Smrgstatic const struct ResourceType predefTypes[] = {
4326747b715Smrg    [RT_NONE & (RC_LASTPREDEF - 1)] = {
43335c4bbdfSmrg                                       .deleteFunc = (DeleteType) NoopDDA,
43435c4bbdfSmrg                                       .sizeFunc = GetDefaultBytes,
43535c4bbdfSmrg                                       .findSubResFunc = DefaultFindSubRes,
43635c4bbdfSmrg                                       .errorValue = BadValue,
43735c4bbdfSmrg                                       },
4386747b715Smrg    [RT_WINDOW & (RC_LASTPREDEF - 1)] = {
43935c4bbdfSmrg                                         .deleteFunc = DeleteWindow,
44035c4bbdfSmrg                                         .sizeFunc = GetWindowBytes,
44135c4bbdfSmrg                                         .findSubResFunc = FindWindowSubRes,
44235c4bbdfSmrg                                         .errorValue = BadWindow,
44335c4bbdfSmrg                                         },
4446747b715Smrg    [RT_PIXMAP & (RC_LASTPREDEF - 1)] = {
44535c4bbdfSmrg                                         .deleteFunc = dixDestroyPixmap,
44635c4bbdfSmrg                                         .sizeFunc = GetPixmapBytes,
44735c4bbdfSmrg                                         .findSubResFunc = DefaultFindSubRes,
44835c4bbdfSmrg                                         .errorValue = BadPixmap,
44935c4bbdfSmrg                                         },
4506747b715Smrg    [RT_GC & (RC_LASTPREDEF - 1)] = {
45135c4bbdfSmrg                                     .deleteFunc = FreeGC,
45235c4bbdfSmrg                                     .sizeFunc = GetGcBytes,
45335c4bbdfSmrg                                     .findSubResFunc = FindGCSubRes,
45435c4bbdfSmrg                                     .errorValue = BadGC,
45535c4bbdfSmrg                                     },
4566747b715Smrg    [RT_FONT & (RC_LASTPREDEF - 1)] = {
45735c4bbdfSmrg                                       .deleteFunc = CloseFont,
45835c4bbdfSmrg                                       .sizeFunc = GetDefaultBytes,
45935c4bbdfSmrg                                       .findSubResFunc = DefaultFindSubRes,
46035c4bbdfSmrg                                       .errorValue = BadFont,
46135c4bbdfSmrg                                       },
4626747b715Smrg    [RT_CURSOR & (RC_LASTPREDEF - 1)] = {
46335c4bbdfSmrg                                         .deleteFunc = FreeCursor,
46435c4bbdfSmrg                                         .sizeFunc = GetDefaultBytes,
46535c4bbdfSmrg                                         .findSubResFunc = DefaultFindSubRes,
46635c4bbdfSmrg                                         .errorValue = BadCursor,
46735c4bbdfSmrg                                         },
4686747b715Smrg    [RT_COLORMAP & (RC_LASTPREDEF - 1)] = {
46935c4bbdfSmrg                                           .deleteFunc = FreeColormap,
47035c4bbdfSmrg                                           .sizeFunc = GetDefaultBytes,
47135c4bbdfSmrg                                           .findSubResFunc = DefaultFindSubRes,
47235c4bbdfSmrg                                           .errorValue = BadColor,
47335c4bbdfSmrg                                           },
4746747b715Smrg    [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = {
47535c4bbdfSmrg                                            .deleteFunc = FreeClientPixels,
47635c4bbdfSmrg                                            .sizeFunc = GetDefaultBytes,
47735c4bbdfSmrg                                            .findSubResFunc = DefaultFindSubRes,
47835c4bbdfSmrg                                            .errorValue = BadColor,
47935c4bbdfSmrg                                            },
4806747b715Smrg    [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = {
48135c4bbdfSmrg                                              .deleteFunc = OtherClientGone,
48235c4bbdfSmrg                                              .sizeFunc = GetDefaultBytes,
48335c4bbdfSmrg                                              .findSubResFunc = DefaultFindSubRes,
48435c4bbdfSmrg                                              .errorValue = BadValue,
48535c4bbdfSmrg                                              },
4866747b715Smrg    [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = {
48735c4bbdfSmrg                                              .deleteFunc = DeletePassiveGrab,
48835c4bbdfSmrg                                              .sizeFunc = GetDefaultBytes,
48935c4bbdfSmrg                                              .findSubResFunc = DefaultFindSubRes,
49035c4bbdfSmrg                                              .errorValue = BadValue,
49135c4bbdfSmrg                                              },
4926747b715Smrg};
4936747b715Smrg
4946747b715SmrgCallbackListPtr ResourceStateCallback;
49505b261ecSmrg
4964642e01fSmrgstatic _X_INLINE void
49735c4bbdfSmrgCallResourceStateCallback(ResourceState state, ResourceRec * res)
49805b261ecSmrg{
4994642e01fSmrg    if (ResourceStateCallback) {
50035c4bbdfSmrg        ResourceStateInfoRec rsi = { state, res->id, res->type, res->value };
50135c4bbdfSmrg        CallCallbacks(&ResourceStateCallback, &rsi);
5024642e01fSmrg    }
50305b261ecSmrg}
50405b261ecSmrg
5056747b715SmrgRESTYPE
50635c4bbdfSmrgCreateNewResourceType(DeleteType deleteFunc, const char *name)
50705b261ecSmrg{
50805b261ecSmrg    RESTYPE next = lastResourceType + 1;
5096747b715Smrg    struct ResourceType *types;
51005b261ecSmrg
51105b261ecSmrg    if (next & lastResourceClass)
51235c4bbdfSmrg        return 0;
51335c4bbdfSmrg    types = reallocarray(resourceTypes, next + 1, sizeof(*resourceTypes));
5146747b715Smrg    if (!types)
51535c4bbdfSmrg        return 0;
51605b261ecSmrg
51705b261ecSmrg    lastResourceType = next;
5186747b715Smrg    resourceTypes = types;
5196747b715Smrg    resourceTypes[next].deleteFunc = deleteFunc;
52035c4bbdfSmrg    resourceTypes[next].sizeFunc = GetDefaultBytes;
52135c4bbdfSmrg    resourceTypes[next].findSubResFunc = DefaultFindSubRes;
5226747b715Smrg    resourceTypes[next].errorValue = BadValue;
5236747b715Smrg
52435c4bbdfSmrg#if X_REGISTRY_RESOURCE
5256747b715Smrg    /* Called even if name is NULL, to remove any previous entry */
5266747b715Smrg    RegisterResourceName(next, name);
52735c4bbdfSmrg#endif
5286747b715Smrg
52905b261ecSmrg    return next;
53005b261ecSmrg}
53105b261ecSmrg
53235c4bbdfSmrg/**
53335c4bbdfSmrg * Get the function used to calculate resource size. Extensions and
53435c4bbdfSmrg * drivers need to be able to determine the current size calculation
53535c4bbdfSmrg * function if they want to wrap or override it.
53635c4bbdfSmrg *
53735c4bbdfSmrg * @param[in] type     Resource type used in size calculations.
53835c4bbdfSmrg *
53935c4bbdfSmrg * @return Function to calculate the size of a single
54035c4bbdfSmrg *                     resource.
54135c4bbdfSmrg */
54235c4bbdfSmrgSizeType
54335c4bbdfSmrgGetResourceTypeSizeFunc(RESTYPE type)
54435c4bbdfSmrg{
54535c4bbdfSmrg    return resourceTypes[type & TypeMask].sizeFunc;
54635c4bbdfSmrg}
54735c4bbdfSmrg
54835c4bbdfSmrg/**
54935c4bbdfSmrg * Override the default function that calculates resource size. For
55035c4bbdfSmrg * example, video driver knows better how to calculate pixmap memory
55135c4bbdfSmrg * usage and can therefore wrap or override size calculation for
55235c4bbdfSmrg * RT_PIXMAP.
55335c4bbdfSmrg *
55435c4bbdfSmrg * @param[in] type     Resource type used in size calculations.
55535c4bbdfSmrg *
55635c4bbdfSmrg * @param[in] sizeFunc Function to calculate the size of a single
55735c4bbdfSmrg *                     resource.
55835c4bbdfSmrg */
55935c4bbdfSmrgvoid
56035c4bbdfSmrgSetResourceTypeSizeFunc(RESTYPE type, SizeType sizeFunc)
56135c4bbdfSmrg{
56235c4bbdfSmrg    resourceTypes[type & TypeMask].sizeFunc = sizeFunc;
56335c4bbdfSmrg}
56435c4bbdfSmrg
56535c4bbdfSmrg/**
56635c4bbdfSmrg * Provide a function for iterating the subresources of a resource.
56735c4bbdfSmrg * This allows for example more accurate accounting of the (memory)
56835c4bbdfSmrg * resources consumed by a resource.
56935c4bbdfSmrg *
57035c4bbdfSmrg * @see FindSubResources
57135c4bbdfSmrg *
57235c4bbdfSmrg * @param[in] type     Resource type used in size calculations.
57335c4bbdfSmrg *
57435c4bbdfSmrg * @param[in] sizeFunc Function to calculate the size of a single
57535c4bbdfSmrg *                     resource.
57635c4bbdfSmrg */
57735c4bbdfSmrgvoid
57835c4bbdfSmrgSetResourceTypeFindSubResFunc(RESTYPE type, FindTypeSubResources findFunc)
57935c4bbdfSmrg{
58035c4bbdfSmrg    resourceTypes[type & TypeMask].findSubResFunc = findFunc;
58135c4bbdfSmrg}
58235c4bbdfSmrg
5836747b715Smrgvoid
5846747b715SmrgSetResourceTypeErrorValue(RESTYPE type, int errorValue)
5856747b715Smrg{
5866747b715Smrg    resourceTypes[type & TypeMask].errorValue = errorValue;
5876747b715Smrg}
5886747b715Smrg
5896747b715SmrgRESTYPE
59005b261ecSmrgCreateNewResourceClass(void)
59105b261ecSmrg{
59205b261ecSmrg    RESTYPE next = lastResourceClass >> 1;
59305b261ecSmrg
59405b261ecSmrg    if (next & lastResourceType)
59535c4bbdfSmrg        return 0;
59605b261ecSmrg    lastResourceClass = next;
59705b261ecSmrg    TypeMask = next - 1;
59805b261ecSmrg    return next;
59905b261ecSmrg}
60005b261ecSmrg
60105b261ecSmrgstatic ClientResourceRec clientTable[MAXCLIENTS];
60205b261ecSmrg
60335c4bbdfSmrgstatic unsigned int
60435c4bbdfSmrgilog2(int val)
60535c4bbdfSmrg{
60635c4bbdfSmrg    int bits;
60735c4bbdfSmrg
60835c4bbdfSmrg    if (val <= 0)
60935c4bbdfSmrg	return 0;
61035c4bbdfSmrg    for (bits = 0; val != 0; bits++)
61135c4bbdfSmrg	val >>= 1;
61235c4bbdfSmrg    return bits - 1;
61335c4bbdfSmrg}
61435c4bbdfSmrg
61535c4bbdfSmrg/*****************
61635c4bbdfSmrg * ResourceClientBits
61735c4bbdfSmrg *    Returns the client bit offset in the client + resources ID field
61835c4bbdfSmrg *****************/
61935c4bbdfSmrg
62035c4bbdfSmrgunsigned int
62135c4bbdfSmrgResourceClientBits(void)
62235c4bbdfSmrg{
62335c4bbdfSmrg    return (ilog2(LimitClients));
62435c4bbdfSmrg}
62535c4bbdfSmrg
62605b261ecSmrg/*****************
62705b261ecSmrg * InitClientResources
62805b261ecSmrg *    When a new client is created, call this to allocate space
62905b261ecSmrg *    in resource table
63005b261ecSmrg *****************/
63105b261ecSmrg
63205b261ecSmrgBool
63305b261ecSmrgInitClientResources(ClientPtr client)
63405b261ecSmrg{
63505b261ecSmrg    int i, j;
63635c4bbdfSmrg
63735c4bbdfSmrg    if (client == serverClient) {
63835c4bbdfSmrg        lastResourceType = RT_LASTPREDEF;
63935c4bbdfSmrg        lastResourceClass = RC_LASTPREDEF;
64035c4bbdfSmrg        TypeMask = RC_LASTPREDEF - 1;
64135c4bbdfSmrg        free(resourceTypes);
64235c4bbdfSmrg        resourceTypes = malloc(sizeof(predefTypes));
64335c4bbdfSmrg        if (!resourceTypes)
64435c4bbdfSmrg            return FALSE;
64535c4bbdfSmrg        memcpy(resourceTypes, predefTypes, sizeof(predefTypes));
64605b261ecSmrg    }
64705b261ecSmrg    clientTable[i = client->index].resources =
64835c4bbdfSmrg        malloc(INITBUCKETS * sizeof(ResourcePtr));
64905b261ecSmrg    if (!clientTable[i].resources)
65035c4bbdfSmrg        return FALSE;
65105b261ecSmrg    clientTable[i].buckets = INITBUCKETS;
65205b261ecSmrg    clientTable[i].elements = 0;
65305b261ecSmrg    clientTable[i].hashsize = INITHASHSIZE;
65405b261ecSmrg    /* Many IDs allocated from the server client are visible to clients,
65505b261ecSmrg     * so we don't use the SERVER_BIT for them, but we have to start
65605b261ecSmrg     * past the magic value constants used in the protocol.  For normal
65705b261ecSmrg     * clients, we can start from zero, with SERVER_BIT set.
65805b261ecSmrg     */
65905b261ecSmrg    clientTable[i].fakeID = client->clientAsMask |
66035c4bbdfSmrg        (client->index ? SERVER_BIT : SERVER_MINID);
66105b261ecSmrg    clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1;
66235c4bbdfSmrg    for (j = 0; j < INITBUCKETS; j++) {
6639ace9065Smrg        clientTable[i].resources[j] = NULL;
66405b261ecSmrg    }
66505b261ecSmrg    return TRUE;
66605b261ecSmrg}
66705b261ecSmrg
66835c4bbdfSmrgint
66935c4bbdfSmrgHashResourceID(XID id, int numBits)
67005b261ecSmrg{
6711b5d61b8Smrg    static XID mask;
6721b5d61b8Smrg
6731b5d61b8Smrg    if (!mask)
6741b5d61b8Smrg        mask = RESOURCE_ID_MASK;
6751b5d61b8Smrg    id &= mask;
6761b5d61b8Smrg    if (numBits < 9)
6771b5d61b8Smrg        return (id ^ (id >> numBits) ^ (id >> (numBits<<1))) & ~((~0) << numBits);
6781b5d61b8Smrg    return (id ^ (id >> numBits)) & ~((~0) << numBits);
67905b261ecSmrg}
68005b261ecSmrg
68105b261ecSmrgstatic XID
68235c4bbdfSmrgAvailableID(int client, XID id, XID maxid, XID goodid)
68305b261ecSmrg{
68405b261ecSmrg    ResourcePtr res;
68505b261ecSmrg
68605b261ecSmrg    if ((goodid >= id) && (goodid <= maxid))
68735c4bbdfSmrg        return goodid;
68835c4bbdfSmrg    for (; id <= maxid; id++) {
68935c4bbdfSmrg        res = clientTable[client].resources[HashResourceID(id, clientTable[client].hashsize)];
69035c4bbdfSmrg        while (res && (res->id != id))
69135c4bbdfSmrg            res = res->next;
69235c4bbdfSmrg        if (!res)
69335c4bbdfSmrg            return id;
69405b261ecSmrg    }
69505b261ecSmrg    return 0;
69605b261ecSmrg}
69705b261ecSmrg
6984642e01fSmrgvoid
69905b261ecSmrgGetXIDRange(int client, Bool server, XID *minp, XID *maxp)
70005b261ecSmrg{
70105b261ecSmrg    XID id, maxid;
70205b261ecSmrg    ResourcePtr *resp;
70305b261ecSmrg    ResourcePtr res;
70405b261ecSmrg    int i;
70505b261ecSmrg    XID goodid;
70605b261ecSmrg
70735c4bbdfSmrg    id = (Mask) client << CLIENTOFFSET;
70805b261ecSmrg    if (server)
70935c4bbdfSmrg        id |= client ? SERVER_BIT : SERVER_MINID;
71005b261ecSmrg    maxid = id | RESOURCE_ID_MASK;
71105b261ecSmrg    goodid = 0;
71205b261ecSmrg    for (resp = clientTable[client].resources, i = clientTable[client].buckets;
71335c4bbdfSmrg         --i >= 0;) {
71435c4bbdfSmrg        for (res = *resp++; res; res = res->next) {
71535c4bbdfSmrg            if ((res->id < id) || (res->id > maxid))
71635c4bbdfSmrg                continue;
71735c4bbdfSmrg            if (((res->id - id) >= (maxid - res->id)) ?
71835c4bbdfSmrg                (goodid = AvailableID(client, id, res->id - 1, goodid)) :
71935c4bbdfSmrg                !(goodid = AvailableID(client, res->id + 1, maxid, goodid)))
72035c4bbdfSmrg                maxid = res->id - 1;
72135c4bbdfSmrg            else
72235c4bbdfSmrg                id = res->id + 1;
72335c4bbdfSmrg        }
72405b261ecSmrg    }
72505b261ecSmrg    if (id > maxid)
72635c4bbdfSmrg        id = maxid = 0;
72705b261ecSmrg    *minp = id;
72805b261ecSmrg    *maxp = maxid;
72905b261ecSmrg}
73005b261ecSmrg
73105b261ecSmrg/**
73205b261ecSmrg *  GetXIDList is called by the XC-MISC extension's MiscGetXIDList function.
73335c4bbdfSmrg *  This function tries to find count unused XIDs for the given client.  It
73405b261ecSmrg *  puts the IDs in the array pids and returns the number found, which should
73505b261ecSmrg *  almost always be the number requested.
73605b261ecSmrg *
73705b261ecSmrg *  The circumstances that lead to a call to this function are very rare.
73805b261ecSmrg *  Xlib must run out of IDs while trying to generate a request that wants
73905b261ecSmrg *  multiple ID's, like the Multi-buffering CreateImageBuffers request.
74005b261ecSmrg *
74105b261ecSmrg *  No rocket science in the implementation; just iterate over all
74205b261ecSmrg *  possible IDs for the given client and pick the first count IDs
74305b261ecSmrg *  that aren't in use.  A more efficient algorithm could probably be
74405b261ecSmrg *  invented, but this will be used so rarely that this should suffice.
74505b261ecSmrg */
74605b261ecSmrg
7474642e01fSmrgunsigned int
74805b261ecSmrgGetXIDList(ClientPtr pClient, unsigned count, XID *pids)
74905b261ecSmrg{
75005b261ecSmrg    unsigned int found = 0;
7516747b715Smrg    XID rc, id = pClient->clientAsMask;
75205b261ecSmrg    XID maxid;
75335c4bbdfSmrg    void *val;
75405b261ecSmrg
75505b261ecSmrg    maxid = id | RESOURCE_ID_MASK;
75635c4bbdfSmrg    while ((found < count) && (id <= maxid)) {
75735c4bbdfSmrg        rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
75835c4bbdfSmrg                                      DixGetAttrAccess);
75935c4bbdfSmrg        if (rc == BadValue) {
76035c4bbdfSmrg            pids[found++] = id;
76135c4bbdfSmrg        }
76235c4bbdfSmrg        id++;
76305b261ecSmrg    }
76405b261ecSmrg    return found;
76505b261ecSmrg}
76605b261ecSmrg
76705b261ecSmrg/*
76805b261ecSmrg * Return the next usable fake client ID.
76905b261ecSmrg *
77005b261ecSmrg * Normally this is just the next one in line, but if we've used the last
77105b261ecSmrg * in the range, we need to find a new range of safe IDs to avoid
77205b261ecSmrg * over-running another client.
77305b261ecSmrg */
77405b261ecSmrg
7756747b715SmrgXID
77605b261ecSmrgFakeClientID(int client)
77705b261ecSmrg{
77805b261ecSmrg    XID id, maxid;
77905b261ecSmrg
78005b261ecSmrg    id = clientTable[client].fakeID++;
78105b261ecSmrg    if (id != clientTable[client].endFakeID)
78235c4bbdfSmrg        return id;
78305b261ecSmrg    GetXIDRange(client, TRUE, &id, &maxid);
78405b261ecSmrg    if (!id) {
78535c4bbdfSmrg        if (!client)
78635c4bbdfSmrg            FatalError("FakeClientID: server internal ids exhausted\n");
78735c4bbdfSmrg        MarkClientException(clients[client]);
78835c4bbdfSmrg        id = ((Mask) client << CLIENTOFFSET) | (SERVER_BIT * 3);
78935c4bbdfSmrg        maxid = id | RESOURCE_ID_MASK;
79005b261ecSmrg    }
79105b261ecSmrg    clientTable[client].fakeID = id + 1;
79205b261ecSmrg    clientTable[client].endFakeID = maxid + 1;
79305b261ecSmrg    return id;
79405b261ecSmrg}
79505b261ecSmrg
7966747b715SmrgBool
79735c4bbdfSmrgAddResource(XID id, RESTYPE type, void *value)
79805b261ecSmrg{
79905b261ecSmrg    int client;
80005b261ecSmrg    ClientResourceRec *rrec;
80105b261ecSmrg    ResourcePtr res, *head;
80235c4bbdfSmrg
80305b261ecSmrg#ifdef XSERVER_DTRACE
80405b261ecSmrg    XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type));
80505b261ecSmrg#endif
80605b261ecSmrg    client = CLIENT_ID(id);
80705b261ecSmrg    rrec = &clientTable[client];
80835c4bbdfSmrg    if (!rrec->buckets) {
80935c4bbdfSmrg        ErrorF("[dix] AddResource(%lx, %x, %lx), client=%d \n",
81035c4bbdfSmrg               (unsigned long) id, type, (unsigned long) value, client);
81105b261ecSmrg        FatalError("client not in use\n");
81205b261ecSmrg    }
81335c4bbdfSmrg    if ((rrec->elements >= 4 * rrec->buckets) && (rrec->hashsize < MAXHASHSIZE))
81435c4bbdfSmrg        RebuildTable(client);
81535c4bbdfSmrg    head = &rrec->resources[HashResourceID(id, clientTable[client].hashsize)];
8166747b715Smrg    res = malloc(sizeof(ResourceRec));
81735c4bbdfSmrg    if (!res) {
81835c4bbdfSmrg        (*resourceTypes[type & TypeMask].deleteFunc) (value, id);
81935c4bbdfSmrg        return FALSE;
82005b261ecSmrg    }
82105b261ecSmrg    res->next = *head;
82205b261ecSmrg    res->id = id;
82305b261ecSmrg    res->type = type;
82405b261ecSmrg    res->value = value;
82505b261ecSmrg    *head = res;
82605b261ecSmrg    rrec->elements++;
8274642e01fSmrg    CallResourceStateCallback(ResourceStateAdding, res);
82805b261ecSmrg    return TRUE;
82905b261ecSmrg}
83005b261ecSmrg
83105b261ecSmrgstatic void
83205b261ecSmrgRebuildTable(int client)
83305b261ecSmrg{
83405b261ecSmrg    int j;
83505b261ecSmrg    ResourcePtr res, next;
83605b261ecSmrg    ResourcePtr **tails, *resources;
83705b261ecSmrg    ResourcePtr **tptr, *rptr;
83805b261ecSmrg
83905b261ecSmrg    /*
84005b261ecSmrg     * For now, preserve insertion order, since some ddx layers depend
84105b261ecSmrg     * on resources being free in the opposite order they are added.
84205b261ecSmrg     */
84305b261ecSmrg
84405b261ecSmrg    j = 2 * clientTable[client].buckets;
84535c4bbdfSmrg    tails =  xallocarray(j, sizeof(ResourcePtr *));
84605b261ecSmrg    if (!tails)
84735c4bbdfSmrg        return;
84835c4bbdfSmrg    resources =  xallocarray(j, sizeof(ResourcePtr));
84935c4bbdfSmrg    if (!resources) {
85035c4bbdfSmrg        free(tails);
85135c4bbdfSmrg        return;
85205b261ecSmrg    }
85335c4bbdfSmrg    for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) {
85435c4bbdfSmrg        *rptr = NULL;
85535c4bbdfSmrg        *tptr = rptr;
85605b261ecSmrg    }
85705b261ecSmrg    clientTable[client].hashsize++;
85805b261ecSmrg    for (j = clientTable[client].buckets,
85935c4bbdfSmrg         rptr = clientTable[client].resources; --j >= 0; rptr++) {
86035c4bbdfSmrg        for (res = *rptr; res; res = next) {
86135c4bbdfSmrg            next = res->next;
86235c4bbdfSmrg            res->next = NULL;
86335c4bbdfSmrg            tptr = &tails[HashResourceID(res->id, clientTable[client].hashsize)];
86435c4bbdfSmrg            **tptr = res;
86535c4bbdfSmrg            *tptr = &res->next;
86635c4bbdfSmrg        }
86705b261ecSmrg    }
8686747b715Smrg    free(tails);
86905b261ecSmrg    clientTable[client].buckets *= 2;
8706747b715Smrg    free(clientTable[client].resources);
87105b261ecSmrg    clientTable[client].resources = resources;
87205b261ecSmrg}
87305b261ecSmrg
87435c4bbdfSmrgstatic void
87535c4bbdfSmrgdoFreeResource(ResourcePtr res, Bool skip)
87635c4bbdfSmrg{
87735c4bbdfSmrg    CallResourceStateCallback(ResourceStateFreeing, res);
87835c4bbdfSmrg
87935c4bbdfSmrg    if (!skip)
88035c4bbdfSmrg        resourceTypes[res->type & TypeMask].deleteFunc(res->value, res->id);
88135c4bbdfSmrg
88235c4bbdfSmrg    free(res);
88335c4bbdfSmrg}
88435c4bbdfSmrg
8856747b715Smrgvoid
88605b261ecSmrgFreeResource(XID id, RESTYPE skipDeleteFuncType)
88705b261ecSmrg{
88835c4bbdfSmrg    int cid;
88905b261ecSmrg    ResourcePtr res;
89005b261ecSmrg    ResourcePtr *prev, *head;
89105b261ecSmrg    int *eltptr;
89235c4bbdfSmrg    int elements;
89305b261ecSmrg
89435c4bbdfSmrg    if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
89535c4bbdfSmrg        head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
89635c4bbdfSmrg        eltptr = &clientTable[cid].elements;
89705b261ecSmrg
89835c4bbdfSmrg        prev = head;
89935c4bbdfSmrg        while ((res = *prev)) {
90035c4bbdfSmrg            if (res->id == id) {
90135c4bbdfSmrg                RESTYPE rtype = res->type;
90205b261ecSmrg
90305b261ecSmrg#ifdef XSERVER_DTRACE
90435c4bbdfSmrg                XSERVER_RESOURCE_FREE(res->id, res->type,
90535c4bbdfSmrg                                      res->value, TypeNameString(res->type));
90635c4bbdfSmrg#endif
90735c4bbdfSmrg                *prev = res->next;
90835c4bbdfSmrg                elements = --*eltptr;
90935c4bbdfSmrg
91035c4bbdfSmrg                doFreeResource(res, rtype == skipDeleteFuncType);
91135c4bbdfSmrg
91235c4bbdfSmrg                if (*eltptr != elements)
91335c4bbdfSmrg                    prev = head;        /* prev may no longer be valid */
91435c4bbdfSmrg            }
91535c4bbdfSmrg            else
91635c4bbdfSmrg                prev = &res->next;
91705b261ecSmrg        }
91805b261ecSmrg    }
91905b261ecSmrg}
92005b261ecSmrg
9216747b715Smrgvoid
92205b261ecSmrgFreeResourceByType(XID id, RESTYPE type, Bool skipFree)
92305b261ecSmrg{
92435c4bbdfSmrg    int cid;
92505b261ecSmrg    ResourcePtr res;
92605b261ecSmrg    ResourcePtr *prev, *head;
92705b261ecSmrg
92835c4bbdfSmrg    if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
92935c4bbdfSmrg        head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
93035c4bbdfSmrg
93135c4bbdfSmrg        prev = head;
93235c4bbdfSmrg        while ((res = *prev)) {
93335c4bbdfSmrg            if (res->id == id && res->type == type) {
93405b261ecSmrg#ifdef XSERVER_DTRACE
93535c4bbdfSmrg                XSERVER_RESOURCE_FREE(res->id, res->type,
93635c4bbdfSmrg                                      res->value, TypeNameString(res->type));
93735c4bbdfSmrg#endif
93835c4bbdfSmrg                *prev = res->next;
93935c4bbdfSmrg                clientTable[cid].elements--;
94035c4bbdfSmrg
94135c4bbdfSmrg                doFreeResource(res, skipFree);
94235c4bbdfSmrg
94335c4bbdfSmrg                break;
94435c4bbdfSmrg            }
94535c4bbdfSmrg            else
94635c4bbdfSmrg                prev = &res->next;
94705b261ecSmrg        }
94805b261ecSmrg    }
94905b261ecSmrg}
95005b261ecSmrg
95105b261ecSmrg/*
95205b261ecSmrg * Change the value associated with a resource id.  Caller
95305b261ecSmrg * is responsible for "doing the right thing" with the old
95405b261ecSmrg * data
95505b261ecSmrg */
95605b261ecSmrg
9576747b715SmrgBool
95835c4bbdfSmrgChangeResourceValue(XID id, RESTYPE rtype, void *value)
95905b261ecSmrg{
96035c4bbdfSmrg    int cid;
96105b261ecSmrg    ResourcePtr res;
96205b261ecSmrg
96335c4bbdfSmrg    if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
96435c4bbdfSmrg        res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
96505b261ecSmrg
96635c4bbdfSmrg        for (; res; res = res->next)
96735c4bbdfSmrg            if ((res->id == id) && (res->type == rtype)) {
96835c4bbdfSmrg                res->value = value;
96935c4bbdfSmrg                return TRUE;
97035c4bbdfSmrg            }
97105b261ecSmrg    }
97205b261ecSmrg    return FALSE;
97305b261ecSmrg}
97405b261ecSmrg
97505b261ecSmrg/* Note: if func adds or deletes resources, then func can get called
97605b261ecSmrg * more than once for some resources.  If func adds new resources,
97705b261ecSmrg * func might or might not get called for them.  func cannot both
97805b261ecSmrg * add and delete an equal number of resources!
97905b261ecSmrg */
98005b261ecSmrg
9816747b715Smrgvoid
98235c4bbdfSmrgFindClientResourcesByType(ClientPtr client,
98335c4bbdfSmrg                          RESTYPE type, FindResType func, void *cdata)
98435c4bbdfSmrg{
98505b261ecSmrg    ResourcePtr *resources;
98605b261ecSmrg    ResourcePtr this, next;
98705b261ecSmrg    int i, elements;
98805b261ecSmrg    int *eltptr;
98905b261ecSmrg
99005b261ecSmrg    if (!client)
99135c4bbdfSmrg        client = serverClient;
99205b261ecSmrg
99305b261ecSmrg    resources = clientTable[client->index].resources;
99405b261ecSmrg    eltptr = &clientTable[client->index].elements;
99535c4bbdfSmrg    for (i = 0; i < clientTable[client->index].buckets; i++) {
99635c4bbdfSmrg        for (this = resources[i]; this; this = next) {
99735c4bbdfSmrg            next = this->next;
99835c4bbdfSmrg            if (!type || this->type == type) {
99935c4bbdfSmrg                elements = *eltptr;
100035c4bbdfSmrg                (*func) (this->value, this->id, cdata);
100135c4bbdfSmrg                if (*eltptr != elements)
100235c4bbdfSmrg                    next = resources[i];        /* start over */
100335c4bbdfSmrg            }
100435c4bbdfSmrg        }
100505b261ecSmrg    }
100605b261ecSmrg}
100705b261ecSmrg
100835c4bbdfSmrgvoid FindSubResources(void *resource,
100935c4bbdfSmrg                      RESTYPE    type,
101035c4bbdfSmrg                      FindAllRes func,
101135c4bbdfSmrg                      void *cdata)
101235c4bbdfSmrg{
101335c4bbdfSmrg    struct ResourceType rtype = resourceTypes[type & TypeMask];
101435c4bbdfSmrg    rtype.findSubResFunc(resource, func, cdata);
101535c4bbdfSmrg}
101635c4bbdfSmrg
10176747b715Smrgvoid
101835c4bbdfSmrgFindAllClientResources(ClientPtr client, FindAllRes func, void *cdata)
101935c4bbdfSmrg{
102005b261ecSmrg    ResourcePtr *resources;
102105b261ecSmrg    ResourcePtr this, next;
102205b261ecSmrg    int i, elements;
102305b261ecSmrg    int *eltptr;
102405b261ecSmrg
102505b261ecSmrg    if (!client)
102605b261ecSmrg        client = serverClient;
102705b261ecSmrg
102805b261ecSmrg    resources = clientTable[client->index].resources;
102905b261ecSmrg    eltptr = &clientTable[client->index].elements;
103035c4bbdfSmrg    for (i = 0; i < clientTable[client->index].buckets; i++) {
103135c4bbdfSmrg        for (this = resources[i]; this; this = next) {
103205b261ecSmrg            next = this->next;
103305b261ecSmrg            elements = *eltptr;
103435c4bbdfSmrg            (*func) (this->value, this->id, this->type, cdata);
103505b261ecSmrg            if (*eltptr != elements)
103635c4bbdfSmrg                next = resources[i];    /* start over */
103705b261ecSmrg        }
103805b261ecSmrg    }
103905b261ecSmrg}
104005b261ecSmrg
104135c4bbdfSmrgvoid *
104235c4bbdfSmrgLookupClientResourceComplex(ClientPtr client,
104335c4bbdfSmrg                            RESTYPE type,
104435c4bbdfSmrg                            FindComplexResType func, void *cdata)
104535c4bbdfSmrg{
104605b261ecSmrg    ResourcePtr *resources;
10476747b715Smrg    ResourcePtr this, next;
104835c4bbdfSmrg    void *value;
104905b261ecSmrg    int i;
105005b261ecSmrg
105105b261ecSmrg    if (!client)
105235c4bbdfSmrg        client = serverClient;
105305b261ecSmrg
105405b261ecSmrg    resources = clientTable[client->index].resources;
105505b261ecSmrg    for (i = 0; i < clientTable[client->index].buckets; i++) {
10566747b715Smrg        for (this = resources[i]; this; this = next) {
105735c4bbdfSmrg            next = this->next;
105835c4bbdfSmrg            if (!type || this->type == type) {
105935c4bbdfSmrg                /* workaround func freeing the type as DRI1 does */
106035c4bbdfSmrg                value = this->value;
106135c4bbdfSmrg                if ((*func) (value, this->id, cdata))
106235c4bbdfSmrg                    return value;
106335c4bbdfSmrg            }
106435c4bbdfSmrg        }
106505b261ecSmrg    }
106605b261ecSmrg    return NULL;
106705b261ecSmrg}
106805b261ecSmrg
106905b261ecSmrgvoid
107005b261ecSmrgFreeClientNeverRetainResources(ClientPtr client)
107105b261ecSmrg{
107205b261ecSmrg    ResourcePtr *resources;
107305b261ecSmrg    ResourcePtr this;
107405b261ecSmrg    ResourcePtr *prev;
10756747b715Smrg    int j, elements;
10766747b715Smrg    int *eltptr;
107705b261ecSmrg
107805b261ecSmrg    if (!client)
107935c4bbdfSmrg        return;
108005b261ecSmrg
108105b261ecSmrg    resources = clientTable[client->index].resources;
10826747b715Smrg    eltptr = &clientTable[client->index].elements;
108335c4bbdfSmrg    for (j = 0; j < clientTable[client->index].buckets; j++) {
108435c4bbdfSmrg        prev = &resources[j];
108535c4bbdfSmrg        while ((this = *prev)) {
108635c4bbdfSmrg            RESTYPE rtype = this->type;
108735c4bbdfSmrg
108835c4bbdfSmrg            if (rtype & RC_NEVERRETAIN) {
108905b261ecSmrg#ifdef XSERVER_DTRACE
109035c4bbdfSmrg                XSERVER_RESOURCE_FREE(this->id, this->type,
109135c4bbdfSmrg                                      this->value, TypeNameString(this->type));
109235c4bbdfSmrg#endif
109335c4bbdfSmrg                *prev = this->next;
109435c4bbdfSmrg                clientTable[client->index].elements--;
109535c4bbdfSmrg                elements = *eltptr;
10964642e01fSmrg
109735c4bbdfSmrg                doFreeResource(this, FALSE);
10984642e01fSmrg
109935c4bbdfSmrg                if (*eltptr != elements)
110035c4bbdfSmrg                    prev = &resources[j];       /* prev may no longer be valid */
110135c4bbdfSmrg            }
110235c4bbdfSmrg            else
110335c4bbdfSmrg                prev = &this->next;
110435c4bbdfSmrg        }
110505b261ecSmrg    }
110605b261ecSmrg}
110705b261ecSmrg
110805b261ecSmrgvoid
110905b261ecSmrgFreeClientResources(ClientPtr client)
111005b261ecSmrg{
111105b261ecSmrg    ResourcePtr *resources;
111205b261ecSmrg    ResourcePtr this;
111305b261ecSmrg    int j;
111405b261ecSmrg
111505b261ecSmrg    /* This routine shouldn't be called with a null client, but just in
111635c4bbdfSmrg       case ... */
111705b261ecSmrg
111805b261ecSmrg    if (!client)
111935c4bbdfSmrg        return;
112005b261ecSmrg
112105b261ecSmrg    HandleSaveSet(client);
112205b261ecSmrg
112305b261ecSmrg    resources = clientTable[client->index].resources;
112435c4bbdfSmrg    for (j = 0; j < clientTable[client->index].buckets; j++) {
112505b261ecSmrg        /* It may seem silly to update the head of this resource list as
112635c4bbdfSmrg           we delete the members, since the entire list will be deleted any way,
112735c4bbdfSmrg           but there are some resource deletion functions "FreeClientPixels" for
112835c4bbdfSmrg           one which do a LookupID on another resource id (a Colormap id in this
112935c4bbdfSmrg           case), so the resource list must be kept valid up to the point that
113035c4bbdfSmrg           it is deleted, so every time we delete a resource, we must update the
113135c4bbdfSmrg           head, just like in FreeResource. I hope that this doesn't slow down
113235c4bbdfSmrg           mass deletion appreciably. PRH */
113305b261ecSmrg
113435c4bbdfSmrg        ResourcePtr *head;
113505b261ecSmrg
113635c4bbdfSmrg        head = &resources[j];
113705b261ecSmrg
113835c4bbdfSmrg        for (this = *head; this; this = *head) {
113905b261ecSmrg#ifdef XSERVER_DTRACE
114035c4bbdfSmrg            XSERVER_RESOURCE_FREE(this->id, this->type,
114135c4bbdfSmrg                                  this->value, TypeNameString(this->type));
114235c4bbdfSmrg#endif
114335c4bbdfSmrg            *head = this->next;
114435c4bbdfSmrg            clientTable[client->index].elements--;
11454642e01fSmrg
114635c4bbdfSmrg            doFreeResource(this, FALSE);
114735c4bbdfSmrg        }
114805b261ecSmrg    }
11496747b715Smrg    free(clientTable[client->index].resources);
115005b261ecSmrg    clientTable[client->index].resources = NULL;
115105b261ecSmrg    clientTable[client->index].buckets = 0;
115205b261ecSmrg}
115305b261ecSmrg
115405b261ecSmrgvoid
115505b261ecSmrgFreeAllResources(void)
115605b261ecSmrg{
115735c4bbdfSmrg    int i;
115805b261ecSmrg
115935c4bbdfSmrg    for (i = currentMaxClients; --i >= 0;) {
116035c4bbdfSmrg        if (clientTable[i].buckets)
116135c4bbdfSmrg            FreeClientResources(clients[i]);
116205b261ecSmrg    }
116305b261ecSmrg}
116405b261ecSmrg
11656747b715SmrgBool
116605b261ecSmrgLegalNewID(XID id, ClientPtr client)
116705b261ecSmrg{
116835c4bbdfSmrg    void *val;
11696747b715Smrg    int rc;
117005b261ecSmrg
117105b261ecSmrg#ifdef PANORAMIX
117235c4bbdfSmrg    XID minid, maxid;
117305b261ecSmrg
11749ace9065Smrg    if (!noPanoramiXExtension) {
11759ace9065Smrg        minid = client->clientAsMask | (client->index ?
11769ace9065Smrg                                        SERVER_BIT : SERVER_MINID);
11779ace9065Smrg        maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1;
11789ace9065Smrg        if ((id >= minid) && (id <= maxid))
11799ace9065Smrg            return TRUE;
11809ace9065Smrg    }
118135c4bbdfSmrg#endif                          /* PANORAMIX */
118235c4bbdfSmrg    if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) {
11839ace9065Smrg        rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
11849ace9065Smrg                                      DixGetAttrAccess);
11859ace9065Smrg        return rc == BadValue;
11869ace9065Smrg    }
11879ace9065Smrg    return FALSE;
118805b261ecSmrg}
118905b261ecSmrg
11906747b715Smrgint
119135c4bbdfSmrgdixLookupResourceByType(void **result, XID id, RESTYPE rtype,
119235c4bbdfSmrg                        ClientPtr client, Mask mode)
119305b261ecSmrg{
11944642e01fSmrg    int cid = CLIENT_ID(id);
119505b261ecSmrg    ResourcePtr res = NULL;
119605b261ecSmrg
11974642e01fSmrg    *result = NULL;
11986747b715Smrg    if ((rtype & TypeMask) > lastResourceType)
119935c4bbdfSmrg        return BadImplementation;
12004642e01fSmrg
120135c4bbdfSmrg    if ((cid < LimitClients) && clientTable[cid].buckets) {
120235c4bbdfSmrg        res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
120305b261ecSmrg
120435c4bbdfSmrg        for (; res; res = res->next)
120535c4bbdfSmrg            if (res->id == id && res->type == rtype)
120635c4bbdfSmrg                break;
1207b86d567bSmrg    }
12081b5d61b8Smrg    if (client) {
12091b5d61b8Smrg        client->errorValue = id;
12101b5d61b8Smrg    }
1211b86d567bSmrg    if (!res)
121235c4bbdfSmrg        return resourceTypes[rtype & TypeMask].errorValue;
1213b86d567bSmrg
1214b86d567bSmrg    if (client) {
121535c4bbdfSmrg        cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
121635c4bbdfSmrg                       res->value, RT_NONE, NULL, mode);
121735c4bbdfSmrg        if (cid == BadValue)
121835c4bbdfSmrg            return resourceTypes[rtype & TypeMask].errorValue;
121935c4bbdfSmrg        if (cid != Success)
122035c4bbdfSmrg            return cid;
1221b86d567bSmrg    }
1222b86d567bSmrg
1223b86d567bSmrg    *result = res->value;
1224b86d567bSmrg    return Success;
1225b86d567bSmrg}
1226b86d567bSmrg
12276747b715Smrgint
122835c4bbdfSmrgdixLookupResourceByClass(void **result, XID id, RESTYPE rclass,
122935c4bbdfSmrg                         ClientPtr client, Mask mode)
1230b86d567bSmrg{
1231b86d567bSmrg    int cid = CLIENT_ID(id);
1232b86d567bSmrg    ResourcePtr res = NULL;
1233b86d567bSmrg
1234b86d567bSmrg    *result = NULL;
1235b86d567bSmrg
123635c4bbdfSmrg    if ((cid < LimitClients) && clientTable[cid].buckets) {
123735c4bbdfSmrg        res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
1238b86d567bSmrg
123935c4bbdfSmrg        for (; res; res = res->next)
124035c4bbdfSmrg            if (res->id == id && (res->type & rclass))
124135c4bbdfSmrg                break;
124205b261ecSmrg    }
12431b5d61b8Smrg    if (client) {
12441b5d61b8Smrg        client->errorValue = id;
12451b5d61b8Smrg    }
12464642e01fSmrg    if (!res)
124735c4bbdfSmrg        return BadValue;
12484642e01fSmrg
12494642e01fSmrg    if (client) {
125035c4bbdfSmrg        cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
125135c4bbdfSmrg                       res->value, RT_NONE, NULL, mode);
125235c4bbdfSmrg        if (cid != Success)
125335c4bbdfSmrg            return cid;
12544642e01fSmrg    }
125505b261ecSmrg
12564642e01fSmrg    *result = res->value;
12574642e01fSmrg    return Success;
125805b261ecSmrg}
1259