resource.c revision 35c4bbdf
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 15905b261ecSmrg#define MAXHASHSIZE 11 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{ 67105b261ecSmrg id &= RESOURCE_ID_MASK; 67235c4bbdfSmrg switch (numBits) 67305b261ecSmrg { 67435c4bbdfSmrg case 6: 67535c4bbdfSmrg return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12)))); 67635c4bbdfSmrg case 7: 67735c4bbdfSmrg return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13)))); 67835c4bbdfSmrg case 8: 67935c4bbdfSmrg return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16)))); 68035c4bbdfSmrg case 9: 68135c4bbdfSmrg return ((int)(0x1FF & (id ^ (id>>9)))); 68235c4bbdfSmrg case 10: 68335c4bbdfSmrg return ((int)(0x3FF & (id ^ (id>>10)))); 68435c4bbdfSmrg case 11: 68535c4bbdfSmrg return ((int)(0x7FF & (id ^ (id>>11)))); 68635c4bbdfSmrg } 68735c4bbdfSmrg if (numBits >= 11) 68835c4bbdfSmrg return ((int)(0x7FF & (id ^ (id>>11)))); 68935c4bbdfSmrg else 69035c4bbdfSmrg { 69135c4bbdfSmrg assert(numBits >= 0); 69235c4bbdfSmrg return id & ~((~0) << numBits); 69335c4bbdfSmrg } 69405b261ecSmrg} 69505b261ecSmrg 69605b261ecSmrgstatic XID 69735c4bbdfSmrgAvailableID(int client, XID id, XID maxid, XID goodid) 69805b261ecSmrg{ 69905b261ecSmrg ResourcePtr res; 70005b261ecSmrg 70105b261ecSmrg if ((goodid >= id) && (goodid <= maxid)) 70235c4bbdfSmrg return goodid; 70335c4bbdfSmrg for (; id <= maxid; id++) { 70435c4bbdfSmrg res = clientTable[client].resources[HashResourceID(id, clientTable[client].hashsize)]; 70535c4bbdfSmrg while (res && (res->id != id)) 70635c4bbdfSmrg res = res->next; 70735c4bbdfSmrg if (!res) 70835c4bbdfSmrg return id; 70905b261ecSmrg } 71005b261ecSmrg return 0; 71105b261ecSmrg} 71205b261ecSmrg 7134642e01fSmrgvoid 71405b261ecSmrgGetXIDRange(int client, Bool server, XID *minp, XID *maxp) 71505b261ecSmrg{ 71605b261ecSmrg XID id, maxid; 71705b261ecSmrg ResourcePtr *resp; 71805b261ecSmrg ResourcePtr res; 71905b261ecSmrg int i; 72005b261ecSmrg XID goodid; 72105b261ecSmrg 72235c4bbdfSmrg id = (Mask) client << CLIENTOFFSET; 72305b261ecSmrg if (server) 72435c4bbdfSmrg id |= client ? SERVER_BIT : SERVER_MINID; 72505b261ecSmrg maxid = id | RESOURCE_ID_MASK; 72605b261ecSmrg goodid = 0; 72705b261ecSmrg for (resp = clientTable[client].resources, i = clientTable[client].buckets; 72835c4bbdfSmrg --i >= 0;) { 72935c4bbdfSmrg for (res = *resp++; res; res = res->next) { 73035c4bbdfSmrg if ((res->id < id) || (res->id > maxid)) 73135c4bbdfSmrg continue; 73235c4bbdfSmrg if (((res->id - id) >= (maxid - res->id)) ? 73335c4bbdfSmrg (goodid = AvailableID(client, id, res->id - 1, goodid)) : 73435c4bbdfSmrg !(goodid = AvailableID(client, res->id + 1, maxid, goodid))) 73535c4bbdfSmrg maxid = res->id - 1; 73635c4bbdfSmrg else 73735c4bbdfSmrg id = res->id + 1; 73835c4bbdfSmrg } 73905b261ecSmrg } 74005b261ecSmrg if (id > maxid) 74135c4bbdfSmrg id = maxid = 0; 74205b261ecSmrg *minp = id; 74305b261ecSmrg *maxp = maxid; 74405b261ecSmrg} 74505b261ecSmrg 74605b261ecSmrg/** 74705b261ecSmrg * GetXIDList is called by the XC-MISC extension's MiscGetXIDList function. 74835c4bbdfSmrg * This function tries to find count unused XIDs for the given client. It 74905b261ecSmrg * puts the IDs in the array pids and returns the number found, which should 75005b261ecSmrg * almost always be the number requested. 75105b261ecSmrg * 75205b261ecSmrg * The circumstances that lead to a call to this function are very rare. 75305b261ecSmrg * Xlib must run out of IDs while trying to generate a request that wants 75405b261ecSmrg * multiple ID's, like the Multi-buffering CreateImageBuffers request. 75505b261ecSmrg * 75605b261ecSmrg * No rocket science in the implementation; just iterate over all 75705b261ecSmrg * possible IDs for the given client and pick the first count IDs 75805b261ecSmrg * that aren't in use. A more efficient algorithm could probably be 75905b261ecSmrg * invented, but this will be used so rarely that this should suffice. 76005b261ecSmrg */ 76105b261ecSmrg 7624642e01fSmrgunsigned int 76305b261ecSmrgGetXIDList(ClientPtr pClient, unsigned count, XID *pids) 76405b261ecSmrg{ 76505b261ecSmrg unsigned int found = 0; 7666747b715Smrg XID rc, id = pClient->clientAsMask; 76705b261ecSmrg XID maxid; 76835c4bbdfSmrg void *val; 76905b261ecSmrg 77005b261ecSmrg maxid = id | RESOURCE_ID_MASK; 77135c4bbdfSmrg while ((found < count) && (id <= maxid)) { 77235c4bbdfSmrg rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, 77335c4bbdfSmrg DixGetAttrAccess); 77435c4bbdfSmrg if (rc == BadValue) { 77535c4bbdfSmrg pids[found++] = id; 77635c4bbdfSmrg } 77735c4bbdfSmrg id++; 77805b261ecSmrg } 77905b261ecSmrg return found; 78005b261ecSmrg} 78105b261ecSmrg 78205b261ecSmrg/* 78305b261ecSmrg * Return the next usable fake client ID. 78405b261ecSmrg * 78505b261ecSmrg * Normally this is just the next one in line, but if we've used the last 78605b261ecSmrg * in the range, we need to find a new range of safe IDs to avoid 78705b261ecSmrg * over-running another client. 78805b261ecSmrg */ 78905b261ecSmrg 7906747b715SmrgXID 79105b261ecSmrgFakeClientID(int client) 79205b261ecSmrg{ 79305b261ecSmrg XID id, maxid; 79405b261ecSmrg 79505b261ecSmrg id = clientTable[client].fakeID++; 79605b261ecSmrg if (id != clientTable[client].endFakeID) 79735c4bbdfSmrg return id; 79805b261ecSmrg GetXIDRange(client, TRUE, &id, &maxid); 79905b261ecSmrg if (!id) { 80035c4bbdfSmrg if (!client) 80135c4bbdfSmrg FatalError("FakeClientID: server internal ids exhausted\n"); 80235c4bbdfSmrg MarkClientException(clients[client]); 80335c4bbdfSmrg id = ((Mask) client << CLIENTOFFSET) | (SERVER_BIT * 3); 80435c4bbdfSmrg maxid = id | RESOURCE_ID_MASK; 80505b261ecSmrg } 80605b261ecSmrg clientTable[client].fakeID = id + 1; 80705b261ecSmrg clientTable[client].endFakeID = maxid + 1; 80805b261ecSmrg return id; 80905b261ecSmrg} 81005b261ecSmrg 8116747b715SmrgBool 81235c4bbdfSmrgAddResource(XID id, RESTYPE type, void *value) 81305b261ecSmrg{ 81405b261ecSmrg int client; 81505b261ecSmrg ClientResourceRec *rrec; 81605b261ecSmrg ResourcePtr res, *head; 81735c4bbdfSmrg 81805b261ecSmrg#ifdef XSERVER_DTRACE 81905b261ecSmrg XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type)); 82005b261ecSmrg#endif 82105b261ecSmrg client = CLIENT_ID(id); 82205b261ecSmrg rrec = &clientTable[client]; 82335c4bbdfSmrg if (!rrec->buckets) { 82435c4bbdfSmrg ErrorF("[dix] AddResource(%lx, %x, %lx), client=%d \n", 82535c4bbdfSmrg (unsigned long) id, type, (unsigned long) value, client); 82605b261ecSmrg FatalError("client not in use\n"); 82705b261ecSmrg } 82835c4bbdfSmrg if ((rrec->elements >= 4 * rrec->buckets) && (rrec->hashsize < MAXHASHSIZE)) 82935c4bbdfSmrg RebuildTable(client); 83035c4bbdfSmrg head = &rrec->resources[HashResourceID(id, clientTable[client].hashsize)]; 8316747b715Smrg res = malloc(sizeof(ResourceRec)); 83235c4bbdfSmrg if (!res) { 83335c4bbdfSmrg (*resourceTypes[type & TypeMask].deleteFunc) (value, id); 83435c4bbdfSmrg return FALSE; 83505b261ecSmrg } 83605b261ecSmrg res->next = *head; 83705b261ecSmrg res->id = id; 83805b261ecSmrg res->type = type; 83905b261ecSmrg res->value = value; 84005b261ecSmrg *head = res; 84105b261ecSmrg rrec->elements++; 8424642e01fSmrg CallResourceStateCallback(ResourceStateAdding, res); 84305b261ecSmrg return TRUE; 84405b261ecSmrg} 84505b261ecSmrg 84605b261ecSmrgstatic void 84705b261ecSmrgRebuildTable(int client) 84805b261ecSmrg{ 84905b261ecSmrg int j; 85005b261ecSmrg ResourcePtr res, next; 85105b261ecSmrg ResourcePtr **tails, *resources; 85205b261ecSmrg ResourcePtr **tptr, *rptr; 85305b261ecSmrg 85405b261ecSmrg /* 85505b261ecSmrg * For now, preserve insertion order, since some ddx layers depend 85605b261ecSmrg * on resources being free in the opposite order they are added. 85705b261ecSmrg */ 85805b261ecSmrg 85905b261ecSmrg j = 2 * clientTable[client].buckets; 86035c4bbdfSmrg tails = xallocarray(j, sizeof(ResourcePtr *)); 86105b261ecSmrg if (!tails) 86235c4bbdfSmrg return; 86335c4bbdfSmrg resources = xallocarray(j, sizeof(ResourcePtr)); 86435c4bbdfSmrg if (!resources) { 86535c4bbdfSmrg free(tails); 86635c4bbdfSmrg return; 86705b261ecSmrg } 86835c4bbdfSmrg for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) { 86935c4bbdfSmrg *rptr = NULL; 87035c4bbdfSmrg *tptr = rptr; 87105b261ecSmrg } 87205b261ecSmrg clientTable[client].hashsize++; 87305b261ecSmrg for (j = clientTable[client].buckets, 87435c4bbdfSmrg rptr = clientTable[client].resources; --j >= 0; rptr++) { 87535c4bbdfSmrg for (res = *rptr; res; res = next) { 87635c4bbdfSmrg next = res->next; 87735c4bbdfSmrg res->next = NULL; 87835c4bbdfSmrg tptr = &tails[HashResourceID(res->id, clientTable[client].hashsize)]; 87935c4bbdfSmrg **tptr = res; 88035c4bbdfSmrg *tptr = &res->next; 88135c4bbdfSmrg } 88205b261ecSmrg } 8836747b715Smrg free(tails); 88405b261ecSmrg clientTable[client].buckets *= 2; 8856747b715Smrg free(clientTable[client].resources); 88605b261ecSmrg clientTable[client].resources = resources; 88705b261ecSmrg} 88805b261ecSmrg 88935c4bbdfSmrgstatic void 89035c4bbdfSmrgdoFreeResource(ResourcePtr res, Bool skip) 89135c4bbdfSmrg{ 89235c4bbdfSmrg CallResourceStateCallback(ResourceStateFreeing, res); 89335c4bbdfSmrg 89435c4bbdfSmrg if (!skip) 89535c4bbdfSmrg resourceTypes[res->type & TypeMask].deleteFunc(res->value, res->id); 89635c4bbdfSmrg 89735c4bbdfSmrg free(res); 89835c4bbdfSmrg} 89935c4bbdfSmrg 9006747b715Smrgvoid 90105b261ecSmrgFreeResource(XID id, RESTYPE skipDeleteFuncType) 90205b261ecSmrg{ 90335c4bbdfSmrg int cid; 90405b261ecSmrg ResourcePtr res; 90505b261ecSmrg ResourcePtr *prev, *head; 90605b261ecSmrg int *eltptr; 90735c4bbdfSmrg int elements; 90805b261ecSmrg 90935c4bbdfSmrg if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) { 91035c4bbdfSmrg head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; 91135c4bbdfSmrg eltptr = &clientTable[cid].elements; 91205b261ecSmrg 91335c4bbdfSmrg prev = head; 91435c4bbdfSmrg while ((res = *prev)) { 91535c4bbdfSmrg if (res->id == id) { 91635c4bbdfSmrg RESTYPE rtype = res->type; 91705b261ecSmrg 91805b261ecSmrg#ifdef XSERVER_DTRACE 91935c4bbdfSmrg XSERVER_RESOURCE_FREE(res->id, res->type, 92035c4bbdfSmrg res->value, TypeNameString(res->type)); 92135c4bbdfSmrg#endif 92235c4bbdfSmrg *prev = res->next; 92335c4bbdfSmrg elements = --*eltptr; 92435c4bbdfSmrg 92535c4bbdfSmrg doFreeResource(res, rtype == skipDeleteFuncType); 92635c4bbdfSmrg 92735c4bbdfSmrg if (*eltptr != elements) 92835c4bbdfSmrg prev = head; /* prev may no longer be valid */ 92935c4bbdfSmrg } 93035c4bbdfSmrg else 93135c4bbdfSmrg prev = &res->next; 93205b261ecSmrg } 93305b261ecSmrg } 93405b261ecSmrg} 93505b261ecSmrg 9366747b715Smrgvoid 93705b261ecSmrgFreeResourceByType(XID id, RESTYPE type, Bool skipFree) 93805b261ecSmrg{ 93935c4bbdfSmrg int cid; 94005b261ecSmrg ResourcePtr res; 94105b261ecSmrg ResourcePtr *prev, *head; 94205b261ecSmrg 94335c4bbdfSmrg if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) { 94435c4bbdfSmrg head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; 94535c4bbdfSmrg 94635c4bbdfSmrg prev = head; 94735c4bbdfSmrg while ((res = *prev)) { 94835c4bbdfSmrg if (res->id == id && res->type == type) { 94905b261ecSmrg#ifdef XSERVER_DTRACE 95035c4bbdfSmrg XSERVER_RESOURCE_FREE(res->id, res->type, 95135c4bbdfSmrg res->value, TypeNameString(res->type)); 95235c4bbdfSmrg#endif 95335c4bbdfSmrg *prev = res->next; 95435c4bbdfSmrg clientTable[cid].elements--; 95535c4bbdfSmrg 95635c4bbdfSmrg doFreeResource(res, skipFree); 95735c4bbdfSmrg 95835c4bbdfSmrg break; 95935c4bbdfSmrg } 96035c4bbdfSmrg else 96135c4bbdfSmrg prev = &res->next; 96205b261ecSmrg } 96305b261ecSmrg } 96405b261ecSmrg} 96505b261ecSmrg 96605b261ecSmrg/* 96705b261ecSmrg * Change the value associated with a resource id. Caller 96805b261ecSmrg * is responsible for "doing the right thing" with the old 96905b261ecSmrg * data 97005b261ecSmrg */ 97105b261ecSmrg 9726747b715SmrgBool 97335c4bbdfSmrgChangeResourceValue(XID id, RESTYPE rtype, void *value) 97405b261ecSmrg{ 97535c4bbdfSmrg int cid; 97605b261ecSmrg ResourcePtr res; 97705b261ecSmrg 97835c4bbdfSmrg if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) { 97935c4bbdfSmrg res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; 98005b261ecSmrg 98135c4bbdfSmrg for (; res; res = res->next) 98235c4bbdfSmrg if ((res->id == id) && (res->type == rtype)) { 98335c4bbdfSmrg res->value = value; 98435c4bbdfSmrg return TRUE; 98535c4bbdfSmrg } 98605b261ecSmrg } 98705b261ecSmrg return FALSE; 98805b261ecSmrg} 98905b261ecSmrg 99005b261ecSmrg/* Note: if func adds or deletes resources, then func can get called 99105b261ecSmrg * more than once for some resources. If func adds new resources, 99205b261ecSmrg * func might or might not get called for them. func cannot both 99305b261ecSmrg * add and delete an equal number of resources! 99405b261ecSmrg */ 99505b261ecSmrg 9966747b715Smrgvoid 99735c4bbdfSmrgFindClientResourcesByType(ClientPtr client, 99835c4bbdfSmrg RESTYPE type, FindResType func, void *cdata) 99935c4bbdfSmrg{ 100005b261ecSmrg ResourcePtr *resources; 100105b261ecSmrg ResourcePtr this, next; 100205b261ecSmrg int i, elements; 100305b261ecSmrg int *eltptr; 100405b261ecSmrg 100505b261ecSmrg if (!client) 100635c4bbdfSmrg client = serverClient; 100705b261ecSmrg 100805b261ecSmrg resources = clientTable[client->index].resources; 100905b261ecSmrg eltptr = &clientTable[client->index].elements; 101035c4bbdfSmrg for (i = 0; i < clientTable[client->index].buckets; i++) { 101135c4bbdfSmrg for (this = resources[i]; this; this = next) { 101235c4bbdfSmrg next = this->next; 101335c4bbdfSmrg if (!type || this->type == type) { 101435c4bbdfSmrg elements = *eltptr; 101535c4bbdfSmrg (*func) (this->value, this->id, cdata); 101635c4bbdfSmrg if (*eltptr != elements) 101735c4bbdfSmrg next = resources[i]; /* start over */ 101835c4bbdfSmrg } 101935c4bbdfSmrg } 102005b261ecSmrg } 102105b261ecSmrg} 102205b261ecSmrg 102335c4bbdfSmrgvoid FindSubResources(void *resource, 102435c4bbdfSmrg RESTYPE type, 102535c4bbdfSmrg FindAllRes func, 102635c4bbdfSmrg void *cdata) 102735c4bbdfSmrg{ 102835c4bbdfSmrg struct ResourceType rtype = resourceTypes[type & TypeMask]; 102935c4bbdfSmrg rtype.findSubResFunc(resource, func, cdata); 103035c4bbdfSmrg} 103135c4bbdfSmrg 10326747b715Smrgvoid 103335c4bbdfSmrgFindAllClientResources(ClientPtr client, FindAllRes func, void *cdata) 103435c4bbdfSmrg{ 103505b261ecSmrg ResourcePtr *resources; 103605b261ecSmrg ResourcePtr this, next; 103705b261ecSmrg int i, elements; 103805b261ecSmrg int *eltptr; 103905b261ecSmrg 104005b261ecSmrg if (!client) 104105b261ecSmrg client = serverClient; 104205b261ecSmrg 104305b261ecSmrg resources = clientTable[client->index].resources; 104405b261ecSmrg eltptr = &clientTable[client->index].elements; 104535c4bbdfSmrg for (i = 0; i < clientTable[client->index].buckets; i++) { 104635c4bbdfSmrg for (this = resources[i]; this; this = next) { 104705b261ecSmrg next = this->next; 104805b261ecSmrg elements = *eltptr; 104935c4bbdfSmrg (*func) (this->value, this->id, this->type, cdata); 105005b261ecSmrg if (*eltptr != elements) 105135c4bbdfSmrg next = resources[i]; /* start over */ 105205b261ecSmrg } 105305b261ecSmrg } 105405b261ecSmrg} 105505b261ecSmrg 105635c4bbdfSmrgvoid * 105735c4bbdfSmrgLookupClientResourceComplex(ClientPtr client, 105835c4bbdfSmrg RESTYPE type, 105935c4bbdfSmrg FindComplexResType func, void *cdata) 106035c4bbdfSmrg{ 106105b261ecSmrg ResourcePtr *resources; 10626747b715Smrg ResourcePtr this, next; 106335c4bbdfSmrg void *value; 106405b261ecSmrg int i; 106505b261ecSmrg 106605b261ecSmrg if (!client) 106735c4bbdfSmrg client = serverClient; 106805b261ecSmrg 106905b261ecSmrg resources = clientTable[client->index].resources; 107005b261ecSmrg for (i = 0; i < clientTable[client->index].buckets; i++) { 10716747b715Smrg for (this = resources[i]; this; this = next) { 107235c4bbdfSmrg next = this->next; 107335c4bbdfSmrg if (!type || this->type == type) { 107435c4bbdfSmrg /* workaround func freeing the type as DRI1 does */ 107535c4bbdfSmrg value = this->value; 107635c4bbdfSmrg if ((*func) (value, this->id, cdata)) 107735c4bbdfSmrg return value; 107835c4bbdfSmrg } 107935c4bbdfSmrg } 108005b261ecSmrg } 108105b261ecSmrg return NULL; 108205b261ecSmrg} 108305b261ecSmrg 108405b261ecSmrgvoid 108505b261ecSmrgFreeClientNeverRetainResources(ClientPtr client) 108605b261ecSmrg{ 108705b261ecSmrg ResourcePtr *resources; 108805b261ecSmrg ResourcePtr this; 108905b261ecSmrg ResourcePtr *prev; 10906747b715Smrg int j, elements; 10916747b715Smrg int *eltptr; 109205b261ecSmrg 109305b261ecSmrg if (!client) 109435c4bbdfSmrg return; 109505b261ecSmrg 109605b261ecSmrg resources = clientTable[client->index].resources; 10976747b715Smrg eltptr = &clientTable[client->index].elements; 109835c4bbdfSmrg for (j = 0; j < clientTable[client->index].buckets; j++) { 109935c4bbdfSmrg prev = &resources[j]; 110035c4bbdfSmrg while ((this = *prev)) { 110135c4bbdfSmrg RESTYPE rtype = this->type; 110235c4bbdfSmrg 110335c4bbdfSmrg if (rtype & RC_NEVERRETAIN) { 110405b261ecSmrg#ifdef XSERVER_DTRACE 110535c4bbdfSmrg XSERVER_RESOURCE_FREE(this->id, this->type, 110635c4bbdfSmrg this->value, TypeNameString(this->type)); 110735c4bbdfSmrg#endif 110835c4bbdfSmrg *prev = this->next; 110935c4bbdfSmrg clientTable[client->index].elements--; 111035c4bbdfSmrg elements = *eltptr; 11114642e01fSmrg 111235c4bbdfSmrg doFreeResource(this, FALSE); 11134642e01fSmrg 111435c4bbdfSmrg if (*eltptr != elements) 111535c4bbdfSmrg prev = &resources[j]; /* prev may no longer be valid */ 111635c4bbdfSmrg } 111735c4bbdfSmrg else 111835c4bbdfSmrg prev = &this->next; 111935c4bbdfSmrg } 112005b261ecSmrg } 112105b261ecSmrg} 112205b261ecSmrg 112305b261ecSmrgvoid 112405b261ecSmrgFreeClientResources(ClientPtr client) 112505b261ecSmrg{ 112605b261ecSmrg ResourcePtr *resources; 112705b261ecSmrg ResourcePtr this; 112805b261ecSmrg int j; 112905b261ecSmrg 113005b261ecSmrg /* This routine shouldn't be called with a null client, but just in 113135c4bbdfSmrg case ... */ 113205b261ecSmrg 113305b261ecSmrg if (!client) 113435c4bbdfSmrg return; 113505b261ecSmrg 113605b261ecSmrg HandleSaveSet(client); 113705b261ecSmrg 113805b261ecSmrg resources = clientTable[client->index].resources; 113935c4bbdfSmrg for (j = 0; j < clientTable[client->index].buckets; j++) { 114005b261ecSmrg /* It may seem silly to update the head of this resource list as 114135c4bbdfSmrg we delete the members, since the entire list will be deleted any way, 114235c4bbdfSmrg but there are some resource deletion functions "FreeClientPixels" for 114335c4bbdfSmrg one which do a LookupID on another resource id (a Colormap id in this 114435c4bbdfSmrg case), so the resource list must be kept valid up to the point that 114535c4bbdfSmrg it is deleted, so every time we delete a resource, we must update the 114635c4bbdfSmrg head, just like in FreeResource. I hope that this doesn't slow down 114735c4bbdfSmrg mass deletion appreciably. PRH */ 114805b261ecSmrg 114935c4bbdfSmrg ResourcePtr *head; 115005b261ecSmrg 115135c4bbdfSmrg head = &resources[j]; 115205b261ecSmrg 115335c4bbdfSmrg for (this = *head; this; this = *head) { 115405b261ecSmrg#ifdef XSERVER_DTRACE 115535c4bbdfSmrg XSERVER_RESOURCE_FREE(this->id, this->type, 115635c4bbdfSmrg this->value, TypeNameString(this->type)); 115735c4bbdfSmrg#endif 115835c4bbdfSmrg *head = this->next; 115935c4bbdfSmrg clientTable[client->index].elements--; 11604642e01fSmrg 116135c4bbdfSmrg doFreeResource(this, FALSE); 116235c4bbdfSmrg } 116305b261ecSmrg } 11646747b715Smrg free(clientTable[client->index].resources); 116505b261ecSmrg clientTable[client->index].resources = NULL; 116605b261ecSmrg clientTable[client->index].buckets = 0; 116705b261ecSmrg} 116805b261ecSmrg 116905b261ecSmrgvoid 117005b261ecSmrgFreeAllResources(void) 117105b261ecSmrg{ 117235c4bbdfSmrg int i; 117305b261ecSmrg 117435c4bbdfSmrg for (i = currentMaxClients; --i >= 0;) { 117535c4bbdfSmrg if (clientTable[i].buckets) 117635c4bbdfSmrg FreeClientResources(clients[i]); 117705b261ecSmrg } 117805b261ecSmrg} 117905b261ecSmrg 11806747b715SmrgBool 118105b261ecSmrgLegalNewID(XID id, ClientPtr client) 118205b261ecSmrg{ 118335c4bbdfSmrg void *val; 11846747b715Smrg int rc; 118505b261ecSmrg 118605b261ecSmrg#ifdef PANORAMIX 118735c4bbdfSmrg XID minid, maxid; 118805b261ecSmrg 11899ace9065Smrg if (!noPanoramiXExtension) { 11909ace9065Smrg minid = client->clientAsMask | (client->index ? 11919ace9065Smrg SERVER_BIT : SERVER_MINID); 11929ace9065Smrg maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1; 11939ace9065Smrg if ((id >= minid) && (id <= maxid)) 11949ace9065Smrg return TRUE; 11959ace9065Smrg } 119635c4bbdfSmrg#endif /* PANORAMIX */ 119735c4bbdfSmrg if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) { 11989ace9065Smrg rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, 11999ace9065Smrg DixGetAttrAccess); 12009ace9065Smrg return rc == BadValue; 12019ace9065Smrg } 12029ace9065Smrg return FALSE; 120305b261ecSmrg} 120405b261ecSmrg 12056747b715Smrgint 120635c4bbdfSmrgdixLookupResourceByType(void **result, XID id, RESTYPE rtype, 120735c4bbdfSmrg ClientPtr client, Mask mode) 120805b261ecSmrg{ 12094642e01fSmrg int cid = CLIENT_ID(id); 121005b261ecSmrg ResourcePtr res = NULL; 121105b261ecSmrg 12124642e01fSmrg *result = NULL; 12136747b715Smrg if ((rtype & TypeMask) > lastResourceType) 121435c4bbdfSmrg return BadImplementation; 12154642e01fSmrg 121635c4bbdfSmrg if ((cid < LimitClients) && clientTable[cid].buckets) { 121735c4bbdfSmrg res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; 121805b261ecSmrg 121935c4bbdfSmrg for (; res; res = res->next) 122035c4bbdfSmrg if (res->id == id && res->type == rtype) 122135c4bbdfSmrg break; 1222b86d567bSmrg } 1223b86d567bSmrg if (!res) 122435c4bbdfSmrg return resourceTypes[rtype & TypeMask].errorValue; 1225b86d567bSmrg 1226b86d567bSmrg if (client) { 122735c4bbdfSmrg client->errorValue = id; 122835c4bbdfSmrg cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, 122935c4bbdfSmrg res->value, RT_NONE, NULL, mode); 123035c4bbdfSmrg if (cid == BadValue) 123135c4bbdfSmrg return resourceTypes[rtype & TypeMask].errorValue; 123235c4bbdfSmrg if (cid != Success) 123335c4bbdfSmrg return cid; 1234b86d567bSmrg } 1235b86d567bSmrg 1236b86d567bSmrg *result = res->value; 1237b86d567bSmrg return Success; 1238b86d567bSmrg} 1239b86d567bSmrg 12406747b715Smrgint 124135c4bbdfSmrgdixLookupResourceByClass(void **result, XID id, RESTYPE rclass, 124235c4bbdfSmrg ClientPtr client, Mask mode) 1243b86d567bSmrg{ 1244b86d567bSmrg int cid = CLIENT_ID(id); 1245b86d567bSmrg ResourcePtr res = NULL; 1246b86d567bSmrg 1247b86d567bSmrg *result = NULL; 1248b86d567bSmrg 124935c4bbdfSmrg if ((cid < LimitClients) && clientTable[cid].buckets) { 125035c4bbdfSmrg res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; 1251b86d567bSmrg 125235c4bbdfSmrg for (; res; res = res->next) 125335c4bbdfSmrg if (res->id == id && (res->type & rclass)) 125435c4bbdfSmrg break; 125505b261ecSmrg } 12564642e01fSmrg if (!res) 125735c4bbdfSmrg return BadValue; 12584642e01fSmrg 12594642e01fSmrg if (client) { 126035c4bbdfSmrg client->errorValue = id; 126135c4bbdfSmrg cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, 126235c4bbdfSmrg res->value, RT_NONE, NULL, mode); 126335c4bbdfSmrg if (cid != Success) 126435c4bbdfSmrg return cid; 12654642e01fSmrg } 126605b261ecSmrg 12674642e01fSmrg *result = res->value; 12684642e01fSmrg return Success; 126905b261ecSmrg} 1270