resource.c revision 9ace9065
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
2505b261ecSmrg
2605b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2705b261ecSmrg
2805b261ecSmrg                        All Rights Reserved
2905b261ecSmrg
3005b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3105b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3205b261ecSmrgprovided that the above copyright notice appear in all copies and that
3305b261ecSmrgboth that copyright notice and this permission notice appear in
3405b261ecSmrgsupporting documentation, and that the name of Digital not be
3505b261ecSmrgused in advertising or publicity pertaining to distribution of the
3605b261ecSmrgsoftware without specific, written prior permission.
3705b261ecSmrg
3805b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3905b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
4005b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4105b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4205b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4305b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4405b261ecSmrgSOFTWARE.
4505b261ecSmrg
4605b261ecSmrg********************************************************/
4705b261ecSmrg/* The panoramix components contained the following notice */
4805b261ecSmrg/*****************************************************************
4905b261ecSmrg
5005b261ecSmrgCopyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
5105b261ecSmrg
5205b261ecSmrgPermission is hereby granted, free of charge, to any person obtaining a copy
5305b261ecSmrgof this software and associated documentation files (the "Software"), to deal
5405b261ecSmrgin the Software without restriction, including without limitation the rights
5505b261ecSmrgto use, copy, modify, merge, publish, distribute, sublicense, and/or sell
5605b261ecSmrgcopies of the Software.
5705b261ecSmrg
5805b261ecSmrgThe above copyright notice and this permission notice shall be included in
5905b261ecSmrgall copies or substantial portions of the Software.
6005b261ecSmrg
6105b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
6205b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
6305b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
6405b261ecSmrgDIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
6505b261ecSmrgBUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
6605b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
6705b261ecSmrgIN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
6805b261ecSmrg
6905b261ecSmrgExcept as contained in this notice, the name of Digital Equipment Corporation
7005b261ecSmrgshall not be used in advertising or otherwise to promote the sale, use or other
7105b261ecSmrgdealings in this Software without prior written authorization from Digital
7205b261ecSmrgEquipment Corporation.
7305b261ecSmrg
7405b261ecSmrg******************************************************************/
7505b261ecSmrg/* XSERVER_DTRACE additions:
769ace9065Smrg * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved.
7705b261ecSmrg *
7805b261ecSmrg * Permission is hereby granted, free of charge, to any person obtaining a
796747b715Smrg * copy of this software and associated documentation files (the "Software"),
806747b715Smrg * to deal in the Software without restriction, including without limitation
816747b715Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
826747b715Smrg * and/or sell copies of the Software, and to permit persons to whom the
836747b715Smrg * Software is furnished to do so, subject to the following conditions:
846747b715Smrg *
856747b715Smrg * The above copyright notice and this permission notice (including the next
866747b715Smrg * paragraph) shall be included in all copies or substantial portions of the
876747b715Smrg * Software.
886747b715Smrg *
896747b715Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
906747b715Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
916747b715Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
926747b715Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
936747b715Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
946747b715Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
956747b715Smrg * DEALINGS IN THE SOFTWARE.
9605b261ecSmrg */
9705b261ecSmrg
9805b261ecSmrg/*	Routines to manage various kinds of resources:
9905b261ecSmrg *
10005b261ecSmrg *	CreateNewResourceType, CreateNewResourceClass, InitClientResources,
10105b261ecSmrg *	FakeClientID, AddResource, FreeResource, FreeClientResources,
10205b261ecSmrg *	FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange
10305b261ecSmrg */
10405b261ecSmrg
10505b261ecSmrg/*
10605b261ecSmrg *      A resource ID is a 32 bit quantity, the upper 2 bits of which are
10705b261ecSmrg *	off-limits for client-visible resources.  The next 8 bits are
10805b261ecSmrg *      used as client ID, and the low 22 bits come from the client.
10905b261ecSmrg *	A resource ID is "hashed" by extracting and xoring subfields
11005b261ecSmrg *      (varying with the size of the hash table).
11105b261ecSmrg *
11205b261ecSmrg *      It is sometimes necessary for the server to create an ID that looks
11305b261ecSmrg *      like it belongs to a client.  This ID, however,  must not be one
11405b261ecSmrg *      the client actually can create, or we have the potential for conflict.
11505b261ecSmrg *      The 31st bit of the ID is reserved for the server's use for this
11605b261ecSmrg *      purpose.  By setting CLIENT_ID(id) to the client, the SERVER_BIT to
11705b261ecSmrg *      1, and an otherwise arbitrary ID in the low 22 bits, we can create a
11805b261ecSmrg *      resource "owned" by the client.
11905b261ecSmrg */
12005b261ecSmrg
12105b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
12205b261ecSmrg#include <dix-config.h>
12305b261ecSmrg#endif
12405b261ecSmrg
12505b261ecSmrg#include <X11/X.h>
12605b261ecSmrg#include "misc.h"
12705b261ecSmrg#include "os.h"
12805b261ecSmrg#include "resource.h"
12905b261ecSmrg#include "dixstruct.h"
13005b261ecSmrg#include "opaque.h"
13105b261ecSmrg#include "windowstr.h"
13205b261ecSmrg#include "dixfont.h"
13305b261ecSmrg#include "colormap.h"
13405b261ecSmrg#include "inputstr.h"
13505b261ecSmrg#include "dixevents.h"
13605b261ecSmrg#include "dixgrabs.h"
13705b261ecSmrg#include "cursor.h"
13805b261ecSmrg#ifdef PANORAMIX
13905b261ecSmrg#include "panoramiX.h"
14005b261ecSmrg#include "panoramiXsrv.h"
14105b261ecSmrg#endif
14205b261ecSmrg#include "xace.h"
14305b261ecSmrg#include <assert.h>
1446747b715Smrg#include "registry.h"
14505b261ecSmrg
14605b261ecSmrg#ifdef XSERVER_DTRACE
14705b261ecSmrg#include <sys/types.h>
14805b261ecSmrgtypedef const char *string;
14905b261ecSmrg#include "Xserver-dtrace.h"
15005b261ecSmrg
1514642e01fSmrg#define TypeNameString(t) LookupResourceName(t)
15205b261ecSmrg#endif
15305b261ecSmrg
15405b261ecSmrgstatic void RebuildTable(
15505b261ecSmrg    int /*client*/
15605b261ecSmrg);
15705b261ecSmrg
15805b261ecSmrg#define SERVER_MINID 32
15905b261ecSmrg
16005b261ecSmrg#define INITBUCKETS 64
16105b261ecSmrg#define INITHASHSIZE 6
16205b261ecSmrg#define MAXHASHSIZE 11
16305b261ecSmrg
16405b261ecSmrgtypedef struct _Resource {
16505b261ecSmrg    struct _Resource	*next;
16605b261ecSmrg    XID			id;
16705b261ecSmrg    RESTYPE		type;
16805b261ecSmrg    pointer		value;
16905b261ecSmrg} ResourceRec, *ResourcePtr;
17005b261ecSmrg
17105b261ecSmrgtypedef struct _ClientResource {
17205b261ecSmrg    ResourcePtr *resources;
17305b261ecSmrg    int		elements;
17405b261ecSmrg    int		buckets;
17505b261ecSmrg    int		hashsize;	/* log(2)(buckets) */
17605b261ecSmrg    XID		fakeID;
17705b261ecSmrg    XID		endFakeID;
17805b261ecSmrg} ClientResourceRec;
17905b261ecSmrg
1806747b715SmrgRESTYPE lastResourceType;
18105b261ecSmrgstatic RESTYPE lastResourceClass;
1826747b715SmrgRESTYPE TypeMask;
1836747b715Smrg
1846747b715Smrgstruct ResourceType {
1856747b715Smrg    DeleteType deleteFunc;
1866747b715Smrg    int errorValue;
1876747b715Smrg};
1886747b715Smrg
1896747b715Smrgstatic struct ResourceType *resourceTypes;
1906747b715Smrgstatic const struct ResourceType predefTypes[] = {
1916747b715Smrg    [RT_NONE & (RC_LASTPREDEF - 1)] = {
1926747b715Smrg	.deleteFunc = (DeleteType)NoopDDA,
1936747b715Smrg	.errorValue = BadValue,
1946747b715Smrg    },
1956747b715Smrg    [RT_WINDOW & (RC_LASTPREDEF - 1)] = {
1966747b715Smrg	.deleteFunc = DeleteWindow,
1976747b715Smrg	.errorValue = BadWindow,
1986747b715Smrg    },
1996747b715Smrg    [RT_PIXMAP & (RC_LASTPREDEF - 1)] = {
2006747b715Smrg	.deleteFunc = dixDestroyPixmap,
2016747b715Smrg	.errorValue = BadPixmap,
2026747b715Smrg    },
2036747b715Smrg    [RT_GC & (RC_LASTPREDEF - 1)] = {
2046747b715Smrg	.deleteFunc = FreeGC,
2056747b715Smrg	.errorValue = BadGC,
2066747b715Smrg    },
2076747b715Smrg    [RT_FONT & (RC_LASTPREDEF - 1)] = {
2086747b715Smrg	.deleteFunc = CloseFont,
2096747b715Smrg	.errorValue = BadFont,
2106747b715Smrg    },
2116747b715Smrg    [RT_CURSOR & (RC_LASTPREDEF - 1)] = {
2126747b715Smrg	.deleteFunc = FreeCursor,
2136747b715Smrg	.errorValue = BadCursor,
2146747b715Smrg    },
2156747b715Smrg    [RT_COLORMAP & (RC_LASTPREDEF - 1)] = {
2166747b715Smrg	.deleteFunc = FreeColormap,
2176747b715Smrg	.errorValue = BadColor,
2186747b715Smrg    },
2196747b715Smrg    [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = {
2206747b715Smrg	.deleteFunc = FreeClientPixels,
2216747b715Smrg	.errorValue = BadColor,
2226747b715Smrg    },
2236747b715Smrg    [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = {
2246747b715Smrg	.deleteFunc = OtherClientGone,
2256747b715Smrg	.errorValue = BadValue,
2266747b715Smrg    },
2276747b715Smrg    [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = {
2286747b715Smrg	.deleteFunc = DeletePassiveGrab,
2296747b715Smrg	.errorValue = BadValue,
2306747b715Smrg    },
2316747b715Smrg};
2326747b715Smrg
2336747b715SmrgCallbackListPtr ResourceStateCallback;
23405b261ecSmrg
2354642e01fSmrgstatic _X_INLINE void
2364642e01fSmrgCallResourceStateCallback(ResourceState state, ResourceRec *res)
23705b261ecSmrg{
2384642e01fSmrg    if (ResourceStateCallback) {
2394642e01fSmrg	ResourceStateInfoRec rsi = { state, res->id, res->type, res->value };
2404642e01fSmrg	CallCallbacks(&ResourceStateCallback, &rsi);
2414642e01fSmrg    }
24205b261ecSmrg}
24305b261ecSmrg
2446747b715SmrgRESTYPE
2456747b715SmrgCreateNewResourceType(DeleteType deleteFunc, char *name)
24605b261ecSmrg{
24705b261ecSmrg    RESTYPE next = lastResourceType + 1;
2486747b715Smrg    struct ResourceType *types;
24905b261ecSmrg
25005b261ecSmrg    if (next & lastResourceClass)
25105b261ecSmrg	return 0;
2526747b715Smrg    types = realloc(resourceTypes, (next + 1) * sizeof(*resourceTypes));
2536747b715Smrg    if (!types)
2544642e01fSmrg	return 0;
25505b261ecSmrg
25605b261ecSmrg    lastResourceType = next;
2576747b715Smrg    resourceTypes = types;
2586747b715Smrg    resourceTypes[next].deleteFunc = deleteFunc;
2596747b715Smrg    resourceTypes[next].errorValue = BadValue;
2606747b715Smrg
2616747b715Smrg    /* Called even if name is NULL, to remove any previous entry */
2626747b715Smrg    RegisterResourceName(next, name);
2636747b715Smrg
26405b261ecSmrg    return next;
26505b261ecSmrg}
26605b261ecSmrg
2676747b715Smrgvoid
2686747b715SmrgSetResourceTypeErrorValue(RESTYPE type, int errorValue)
2696747b715Smrg{
2706747b715Smrg    resourceTypes[type & TypeMask].errorValue = errorValue;
2716747b715Smrg}
2726747b715Smrg
2736747b715SmrgRESTYPE
27405b261ecSmrgCreateNewResourceClass(void)
27505b261ecSmrg{
27605b261ecSmrg    RESTYPE next = lastResourceClass >> 1;
27705b261ecSmrg
27805b261ecSmrg    if (next & lastResourceType)
27905b261ecSmrg	return 0;
28005b261ecSmrg    lastResourceClass = next;
28105b261ecSmrg    TypeMask = next - 1;
28205b261ecSmrg    return next;
28305b261ecSmrg}
28405b261ecSmrg
28505b261ecSmrgstatic ClientResourceRec clientTable[MAXCLIENTS];
28605b261ecSmrg
28705b261ecSmrg/*****************
28805b261ecSmrg * InitClientResources
28905b261ecSmrg *    When a new client is created, call this to allocate space
29005b261ecSmrg *    in resource table
29105b261ecSmrg *****************/
29205b261ecSmrg
29305b261ecSmrgBool
29405b261ecSmrgInitClientResources(ClientPtr client)
29505b261ecSmrg{
29605b261ecSmrg    int i, j;
29705b261ecSmrg
29805b261ecSmrg    if (client == serverClient)
29905b261ecSmrg    {
30005b261ecSmrg	lastResourceType = RT_LASTPREDEF;
30105b261ecSmrg	lastResourceClass = RC_LASTPREDEF;
30205b261ecSmrg	TypeMask = RC_LASTPREDEF - 1;
3036747b715Smrg	free(resourceTypes);
3046747b715Smrg	resourceTypes = malloc(sizeof(predefTypes));
3056747b715Smrg	if (!resourceTypes)
30605b261ecSmrg	    return FALSE;
3076747b715Smrg	memcpy(resourceTypes, predefTypes, sizeof(predefTypes));
30805b261ecSmrg    }
30905b261ecSmrg    clientTable[i = client->index].resources =
3106747b715Smrg	malloc(INITBUCKETS*sizeof(ResourcePtr));
31105b261ecSmrg    if (!clientTable[i].resources)
31205b261ecSmrg	return FALSE;
31305b261ecSmrg    clientTable[i].buckets = INITBUCKETS;
31405b261ecSmrg    clientTable[i].elements = 0;
31505b261ecSmrg    clientTable[i].hashsize = INITHASHSIZE;
31605b261ecSmrg    /* Many IDs allocated from the server client are visible to clients,
31705b261ecSmrg     * so we don't use the SERVER_BIT for them, but we have to start
31805b261ecSmrg     * past the magic value constants used in the protocol.  For normal
31905b261ecSmrg     * clients, we can start from zero, with SERVER_BIT set.
32005b261ecSmrg     */
32105b261ecSmrg    clientTable[i].fakeID = client->clientAsMask |
32205b261ecSmrg			    (client->index ? SERVER_BIT : SERVER_MINID);
32305b261ecSmrg    clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1;
32405b261ecSmrg    for (j=0; j<INITBUCKETS; j++)
32505b261ecSmrg    {
3269ace9065Smrg        clientTable[i].resources[j] = NULL;
32705b261ecSmrg    }
32805b261ecSmrg    return TRUE;
32905b261ecSmrg}
33005b261ecSmrg
33105b261ecSmrg
33205b261ecSmrgstatic int
33305b261ecSmrgHash(int client, XID id)
33405b261ecSmrg{
33505b261ecSmrg    id &= RESOURCE_ID_MASK;
33605b261ecSmrg    switch (clientTable[client].hashsize)
33705b261ecSmrg    {
33805b261ecSmrg	case 6:
33905b261ecSmrg	    return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12))));
34005b261ecSmrg	case 7:
34105b261ecSmrg	    return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13))));
34205b261ecSmrg	case 8:
34305b261ecSmrg	    return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16))));
34405b261ecSmrg	case 9:
34505b261ecSmrg	    return ((int)(0x1FF & (id ^ (id>>9))));
34605b261ecSmrg	case 10:
34705b261ecSmrg	    return ((int)(0x3FF & (id ^ (id>>10))));
34805b261ecSmrg	case 11:
34905b261ecSmrg	    return ((int)(0x7FF & (id ^ (id>>11))));
35005b261ecSmrg    }
35105b261ecSmrg    return -1;
35205b261ecSmrg}
35305b261ecSmrg
35405b261ecSmrgstatic XID
35505b261ecSmrgAvailableID(
35605b261ecSmrg    int client,
35705b261ecSmrg    XID id,
35805b261ecSmrg    XID maxid,
35905b261ecSmrg    XID goodid)
36005b261ecSmrg{
36105b261ecSmrg    ResourcePtr res;
36205b261ecSmrg
36305b261ecSmrg    if ((goodid >= id) && (goodid <= maxid))
36405b261ecSmrg	return goodid;
36505b261ecSmrg    for (; id <= maxid; id++)
36605b261ecSmrg    {
36705b261ecSmrg	res = clientTable[client].resources[Hash(client, id)];
36805b261ecSmrg	while (res && (res->id != id))
36905b261ecSmrg	    res = res->next;
37005b261ecSmrg	if (!res)
37105b261ecSmrg	    return id;
37205b261ecSmrg    }
37305b261ecSmrg    return 0;
37405b261ecSmrg}
37505b261ecSmrg
3764642e01fSmrgvoid
37705b261ecSmrgGetXIDRange(int client, Bool server, XID *minp, XID *maxp)
37805b261ecSmrg{
37905b261ecSmrg    XID id, maxid;
38005b261ecSmrg    ResourcePtr *resp;
38105b261ecSmrg    ResourcePtr res;
38205b261ecSmrg    int i;
38305b261ecSmrg    XID goodid;
38405b261ecSmrg
38505b261ecSmrg    id = (Mask)client << CLIENTOFFSET;
38605b261ecSmrg    if (server)
38705b261ecSmrg	id |= client ? SERVER_BIT : SERVER_MINID;
38805b261ecSmrg    maxid = id | RESOURCE_ID_MASK;
38905b261ecSmrg    goodid = 0;
39005b261ecSmrg    for (resp = clientTable[client].resources, i = clientTable[client].buckets;
39105b261ecSmrg	 --i >= 0;)
39205b261ecSmrg    {
39305b261ecSmrg	for (res = *resp++; res; res = res->next)
39405b261ecSmrg	{
39505b261ecSmrg	    if ((res->id < id) || (res->id > maxid))
39605b261ecSmrg		continue;
39705b261ecSmrg	    if (((res->id - id) >= (maxid - res->id)) ?
39805b261ecSmrg		(goodid = AvailableID(client, id, res->id - 1, goodid)) :
39905b261ecSmrg		!(goodid = AvailableID(client, res->id + 1, maxid, goodid)))
40005b261ecSmrg		maxid = res->id - 1;
40105b261ecSmrg	    else
40205b261ecSmrg		id = res->id + 1;
40305b261ecSmrg	}
40405b261ecSmrg    }
40505b261ecSmrg    if (id > maxid)
40605b261ecSmrg	id = maxid = 0;
40705b261ecSmrg    *minp = id;
40805b261ecSmrg    *maxp = maxid;
40905b261ecSmrg}
41005b261ecSmrg
41105b261ecSmrg/**
41205b261ecSmrg *  GetXIDList is called by the XC-MISC extension's MiscGetXIDList function.
41305b261ecSmrg *  This function tries to find count unused XIDs for the given client.  It
41405b261ecSmrg *  puts the IDs in the array pids and returns the number found, which should
41505b261ecSmrg *  almost always be the number requested.
41605b261ecSmrg *
41705b261ecSmrg *  The circumstances that lead to a call to this function are very rare.
41805b261ecSmrg *  Xlib must run out of IDs while trying to generate a request that wants
41905b261ecSmrg *  multiple ID's, like the Multi-buffering CreateImageBuffers request.
42005b261ecSmrg *
42105b261ecSmrg *  No rocket science in the implementation; just iterate over all
42205b261ecSmrg *  possible IDs for the given client and pick the first count IDs
42305b261ecSmrg *  that aren't in use.  A more efficient algorithm could probably be
42405b261ecSmrg *  invented, but this will be used so rarely that this should suffice.
42505b261ecSmrg */
42605b261ecSmrg
4274642e01fSmrgunsigned int
42805b261ecSmrgGetXIDList(ClientPtr pClient, unsigned count, XID *pids)
42905b261ecSmrg{
43005b261ecSmrg    unsigned int found = 0;
4316747b715Smrg    XID rc, id = pClient->clientAsMask;
43205b261ecSmrg    XID maxid;
4336747b715Smrg    pointer val;
43405b261ecSmrg
43505b261ecSmrg    maxid = id | RESOURCE_ID_MASK;
43605b261ecSmrg    while ( (found < count) && (id <= maxid) )
43705b261ecSmrg    {
4386747b715Smrg	rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
4396747b715Smrg				      DixGetAttrAccess);
4406747b715Smrg	if (rc == BadValue)
44105b261ecSmrg	{
44205b261ecSmrg	    pids[found++] = id;
44305b261ecSmrg	}
44405b261ecSmrg	id++;
44505b261ecSmrg    }
44605b261ecSmrg    return found;
44705b261ecSmrg}
44805b261ecSmrg
44905b261ecSmrg/*
45005b261ecSmrg * Return the next usable fake client ID.
45105b261ecSmrg *
45205b261ecSmrg * Normally this is just the next one in line, but if we've used the last
45305b261ecSmrg * in the range, we need to find a new range of safe IDs to avoid
45405b261ecSmrg * over-running another client.
45505b261ecSmrg */
45605b261ecSmrg
4576747b715SmrgXID
45805b261ecSmrgFakeClientID(int client)
45905b261ecSmrg{
46005b261ecSmrg    XID id, maxid;
46105b261ecSmrg
46205b261ecSmrg    id = clientTable[client].fakeID++;
46305b261ecSmrg    if (id != clientTable[client].endFakeID)
46405b261ecSmrg	return id;
46505b261ecSmrg    GetXIDRange(client, TRUE, &id, &maxid);
46605b261ecSmrg    if (!id) {
46705b261ecSmrg	if (!client)
46805b261ecSmrg	    FatalError("FakeClientID: server internal ids exhausted\n");
46905b261ecSmrg	MarkClientException(clients[client]);
47005b261ecSmrg	id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3);
47105b261ecSmrg	maxid = id | RESOURCE_ID_MASK;
47205b261ecSmrg    }
47305b261ecSmrg    clientTable[client].fakeID = id + 1;
47405b261ecSmrg    clientTable[client].endFakeID = maxid + 1;
47505b261ecSmrg    return id;
47605b261ecSmrg}
47705b261ecSmrg
4786747b715SmrgBool
47905b261ecSmrgAddResource(XID id, RESTYPE type, pointer value)
48005b261ecSmrg{
48105b261ecSmrg    int client;
48205b261ecSmrg    ClientResourceRec *rrec;
48305b261ecSmrg    ResourcePtr res, *head;
48405b261ecSmrg
48505b261ecSmrg#ifdef XSERVER_DTRACE
48605b261ecSmrg    XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type));
48705b261ecSmrg#endif
48805b261ecSmrg    client = CLIENT_ID(id);
48905b261ecSmrg    rrec = &clientTable[client];
49005b261ecSmrg    if (!rrec->buckets)
49105b261ecSmrg    {
4924642e01fSmrg	ErrorF("[dix] AddResource(%lx, %lx, %lx), client=%d \n",
49305b261ecSmrg		(unsigned long)id, type, (unsigned long)value, client);
49405b261ecSmrg        FatalError("client not in use\n");
49505b261ecSmrg    }
49605b261ecSmrg    if ((rrec->elements >= 4*rrec->buckets) &&
49705b261ecSmrg	(rrec->hashsize < MAXHASHSIZE))
49805b261ecSmrg	RebuildTable(client);
49905b261ecSmrg    head = &rrec->resources[Hash(client, id)];
5006747b715Smrg    res = malloc(sizeof(ResourceRec));
50105b261ecSmrg    if (!res)
50205b261ecSmrg    {
5036747b715Smrg	(*resourceTypes[type & TypeMask].deleteFunc)(value, id);
50405b261ecSmrg	return FALSE;
50505b261ecSmrg    }
50605b261ecSmrg    res->next = *head;
50705b261ecSmrg    res->id = id;
50805b261ecSmrg    res->type = type;
50905b261ecSmrg    res->value = value;
51005b261ecSmrg    *head = res;
51105b261ecSmrg    rrec->elements++;
5124642e01fSmrg    CallResourceStateCallback(ResourceStateAdding, res);
51305b261ecSmrg    return TRUE;
51405b261ecSmrg}
51505b261ecSmrg
51605b261ecSmrgstatic void
51705b261ecSmrgRebuildTable(int client)
51805b261ecSmrg{
51905b261ecSmrg    int j;
52005b261ecSmrg    ResourcePtr res, next;
52105b261ecSmrg    ResourcePtr **tails, *resources;
52205b261ecSmrg    ResourcePtr **tptr, *rptr;
52305b261ecSmrg
52405b261ecSmrg    /*
52505b261ecSmrg     * For now, preserve insertion order, since some ddx layers depend
52605b261ecSmrg     * on resources being free in the opposite order they are added.
52705b261ecSmrg     */
52805b261ecSmrg
52905b261ecSmrg    j = 2 * clientTable[client].buckets;
5306747b715Smrg    tails = malloc(j * sizeof(ResourcePtr *));
53105b261ecSmrg    if (!tails)
53205b261ecSmrg	return;
5336747b715Smrg    resources = malloc(j * sizeof(ResourcePtr));
53405b261ecSmrg    if (!resources)
53505b261ecSmrg    {
5366747b715Smrg	free(tails);
53705b261ecSmrg	return;
53805b261ecSmrg    }
53905b261ecSmrg    for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++)
54005b261ecSmrg    {
5419ace9065Smrg	*rptr = NULL;
54205b261ecSmrg	*tptr = rptr;
54305b261ecSmrg    }
54405b261ecSmrg    clientTable[client].hashsize++;
54505b261ecSmrg    for (j = clientTable[client].buckets,
54605b261ecSmrg	 rptr = clientTable[client].resources;
54705b261ecSmrg	 --j >= 0;
54805b261ecSmrg	 rptr++)
54905b261ecSmrg    {
55005b261ecSmrg	for (res = *rptr; res; res = next)
55105b261ecSmrg	{
55205b261ecSmrg	    next = res->next;
5539ace9065Smrg	    res->next = NULL;
55405b261ecSmrg	    tptr = &tails[Hash(client, res->id)];
55505b261ecSmrg	    **tptr = res;
55605b261ecSmrg	    *tptr = &res->next;
55705b261ecSmrg	}
55805b261ecSmrg    }
5596747b715Smrg    free(tails);
56005b261ecSmrg    clientTable[client].buckets *= 2;
5616747b715Smrg    free(clientTable[client].resources);
56205b261ecSmrg    clientTable[client].resources = resources;
56305b261ecSmrg}
56405b261ecSmrg
5656747b715Smrgvoid
56605b261ecSmrgFreeResource(XID id, RESTYPE skipDeleteFuncType)
56705b261ecSmrg{
56805b261ecSmrg    int		cid;
56905b261ecSmrg    ResourcePtr res;
57005b261ecSmrg    ResourcePtr *prev, *head;
57105b261ecSmrg    int *eltptr;
57205b261ecSmrg    int		elements;
57305b261ecSmrg
57405b261ecSmrg    if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
57505b261ecSmrg    {
57605b261ecSmrg	head = &clientTable[cid].resources[Hash(cid, id)];
57705b261ecSmrg	eltptr = &clientTable[cid].elements;
57805b261ecSmrg
57905b261ecSmrg	prev = head;
58005b261ecSmrg	while ( (res = *prev) )
58105b261ecSmrg	{
58205b261ecSmrg	    if (res->id == id)
58305b261ecSmrg	    {
58405b261ecSmrg		RESTYPE rtype = res->type;
58505b261ecSmrg
58605b261ecSmrg#ifdef XSERVER_DTRACE
58705b261ecSmrg		XSERVER_RESOURCE_FREE(res->id, res->type,
58805b261ecSmrg			      res->value, TypeNameString(res->type));
58905b261ecSmrg#endif
59005b261ecSmrg		*prev = res->next;
59105b261ecSmrg		elements = --*eltptr;
5924642e01fSmrg
5934642e01fSmrg		CallResourceStateCallback(ResourceStateFreeing, res);
5944642e01fSmrg
59505b261ecSmrg		if (rtype != skipDeleteFuncType)
5966747b715Smrg		    (*resourceTypes[rtype & TypeMask].deleteFunc)(res->value, res->id);
5976747b715Smrg		free(res);
59805b261ecSmrg		if (*eltptr != elements)
59905b261ecSmrg		    prev = head; /* prev may no longer be valid */
60005b261ecSmrg	    }
60105b261ecSmrg	    else
60205b261ecSmrg		prev = &res->next;
60305b261ecSmrg        }
60405b261ecSmrg    }
60505b261ecSmrg}
60605b261ecSmrg
60705b261ecSmrg
6086747b715Smrgvoid
60905b261ecSmrgFreeResourceByType(XID id, RESTYPE type, Bool skipFree)
61005b261ecSmrg{
61105b261ecSmrg    int		cid;
61205b261ecSmrg    ResourcePtr res;
61305b261ecSmrg    ResourcePtr *prev, *head;
61405b261ecSmrg    if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
61505b261ecSmrg    {
61605b261ecSmrg	head = &clientTable[cid].resources[Hash(cid, id)];
61705b261ecSmrg
61805b261ecSmrg	prev = head;
61905b261ecSmrg	while ( (res = *prev) )
62005b261ecSmrg	{
62105b261ecSmrg	    if (res->id == id && res->type == type)
62205b261ecSmrg	    {
62305b261ecSmrg#ifdef XSERVER_DTRACE
62405b261ecSmrg		XSERVER_RESOURCE_FREE(res->id, res->type,
62505b261ecSmrg			      res->value, TypeNameString(res->type));
62605b261ecSmrg#endif
62705b261ecSmrg		*prev = res->next;
6286747b715Smrg		clientTable[cid].elements--;
6294642e01fSmrg
6304642e01fSmrg		CallResourceStateCallback(ResourceStateFreeing, res);
6314642e01fSmrg
63205b261ecSmrg		if (!skipFree)
6336747b715Smrg		    (*resourceTypes[type & TypeMask].deleteFunc)(res->value, res->id);
6346747b715Smrg		free(res);
63505b261ecSmrg		break;
63605b261ecSmrg	    }
63705b261ecSmrg	    else
63805b261ecSmrg		prev = &res->next;
63905b261ecSmrg        }
64005b261ecSmrg    }
64105b261ecSmrg}
64205b261ecSmrg
64305b261ecSmrg/*
64405b261ecSmrg * Change the value associated with a resource id.  Caller
64505b261ecSmrg * is responsible for "doing the right thing" with the old
64605b261ecSmrg * data
64705b261ecSmrg */
64805b261ecSmrg
6496747b715SmrgBool
65005b261ecSmrgChangeResourceValue (XID id, RESTYPE rtype, pointer value)
65105b261ecSmrg{
65205b261ecSmrg    int    cid;
65305b261ecSmrg    ResourcePtr res;
65405b261ecSmrg
65505b261ecSmrg    if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
65605b261ecSmrg    {
65705b261ecSmrg	res = clientTable[cid].resources[Hash(cid, id)];
65805b261ecSmrg
65905b261ecSmrg	for (; res; res = res->next)
66005b261ecSmrg	    if ((res->id == id) && (res->type == rtype))
66105b261ecSmrg	    {
66205b261ecSmrg		res->value = value;
66305b261ecSmrg		return TRUE;
66405b261ecSmrg	    }
66505b261ecSmrg    }
66605b261ecSmrg    return FALSE;
66705b261ecSmrg}
66805b261ecSmrg
66905b261ecSmrg/* Note: if func adds or deletes resources, then func can get called
67005b261ecSmrg * more than once for some resources.  If func adds new resources,
67105b261ecSmrg * func might or might not get called for them.  func cannot both
67205b261ecSmrg * add and delete an equal number of resources!
67305b261ecSmrg */
67405b261ecSmrg
6756747b715Smrgvoid
67605b261ecSmrgFindClientResourcesByType(
67705b261ecSmrg    ClientPtr client,
67805b261ecSmrg    RESTYPE type,
67905b261ecSmrg    FindResType func,
68005b261ecSmrg    pointer cdata
68105b261ecSmrg){
68205b261ecSmrg    ResourcePtr *resources;
68305b261ecSmrg    ResourcePtr this, next;
68405b261ecSmrg    int i, elements;
68505b261ecSmrg    int *eltptr;
68605b261ecSmrg
68705b261ecSmrg    if (!client)
68805b261ecSmrg	client = serverClient;
68905b261ecSmrg
69005b261ecSmrg    resources = clientTable[client->index].resources;
69105b261ecSmrg    eltptr = &clientTable[client->index].elements;
69205b261ecSmrg    for (i = 0; i < clientTable[client->index].buckets; i++)
69305b261ecSmrg    {
69405b261ecSmrg        for (this = resources[i]; this; this = next)
69505b261ecSmrg	{
69605b261ecSmrg	    next = this->next;
69705b261ecSmrg	    if (!type || this->type == type) {
69805b261ecSmrg		elements = *eltptr;
69905b261ecSmrg		(*func)(this->value, this->id, cdata);
70005b261ecSmrg		if (*eltptr != elements)
70105b261ecSmrg		    next = resources[i]; /* start over */
70205b261ecSmrg	    }
70305b261ecSmrg	}
70405b261ecSmrg    }
70505b261ecSmrg}
70605b261ecSmrg
7076747b715Smrgvoid
70805b261ecSmrgFindAllClientResources(
70905b261ecSmrg    ClientPtr client,
71005b261ecSmrg    FindAllRes func,
71105b261ecSmrg    pointer cdata
71205b261ecSmrg){
71305b261ecSmrg    ResourcePtr *resources;
71405b261ecSmrg    ResourcePtr this, next;
71505b261ecSmrg    int i, elements;
71605b261ecSmrg    int *eltptr;
71705b261ecSmrg
71805b261ecSmrg    if (!client)
71905b261ecSmrg        client = serverClient;
72005b261ecSmrg
72105b261ecSmrg    resources = clientTable[client->index].resources;
72205b261ecSmrg    eltptr = &clientTable[client->index].elements;
72305b261ecSmrg    for (i = 0; i < clientTable[client->index].buckets; i++)
72405b261ecSmrg    {
72505b261ecSmrg        for (this = resources[i]; this; this = next)
72605b261ecSmrg        {
72705b261ecSmrg            next = this->next;
72805b261ecSmrg            elements = *eltptr;
72905b261ecSmrg            (*func)(this->value, this->id, this->type, cdata);
73005b261ecSmrg            if (*eltptr != elements)
73105b261ecSmrg                next = resources[i]; /* start over */
73205b261ecSmrg        }
73305b261ecSmrg    }
73405b261ecSmrg}
73505b261ecSmrg
73605b261ecSmrg
73705b261ecSmrgpointer
73805b261ecSmrgLookupClientResourceComplex(
73905b261ecSmrg    ClientPtr client,
74005b261ecSmrg    RESTYPE type,
74105b261ecSmrg    FindComplexResType func,
74205b261ecSmrg    pointer cdata
74305b261ecSmrg){
74405b261ecSmrg    ResourcePtr *resources;
7456747b715Smrg    ResourcePtr this, next;
7466747b715Smrg    pointer value;
74705b261ecSmrg    int i;
74805b261ecSmrg
74905b261ecSmrg    if (!client)
75005b261ecSmrg	client = serverClient;
75105b261ecSmrg
75205b261ecSmrg    resources = clientTable[client->index].resources;
75305b261ecSmrg    for (i = 0; i < clientTable[client->index].buckets; i++) {
7546747b715Smrg        for (this = resources[i]; this; this = next) {
7556747b715Smrg	    next = this->next;
75605b261ecSmrg	    if (!type || this->type == type) {
7576747b715Smrg		/* workaround func freeing the type as DRI1 does */
7586747b715Smrg		value = this->value;
7596747b715Smrg		if((*func)(value, this->id, cdata))
7606747b715Smrg		    return value;
76105b261ecSmrg	    }
76205b261ecSmrg	}
76305b261ecSmrg    }
76405b261ecSmrg    return NULL;
76505b261ecSmrg}
76605b261ecSmrg
76705b261ecSmrg
76805b261ecSmrgvoid
76905b261ecSmrgFreeClientNeverRetainResources(ClientPtr client)
77005b261ecSmrg{
77105b261ecSmrg    ResourcePtr *resources;
77205b261ecSmrg    ResourcePtr this;
77305b261ecSmrg    ResourcePtr *prev;
7746747b715Smrg    int j, elements;
7756747b715Smrg    int *eltptr;
77605b261ecSmrg
77705b261ecSmrg    if (!client)
77805b261ecSmrg	return;
77905b261ecSmrg
78005b261ecSmrg    resources = clientTable[client->index].resources;
7816747b715Smrg    eltptr = &clientTable[client->index].elements;
78205b261ecSmrg    for (j=0; j < clientTable[client->index].buckets; j++)
78305b261ecSmrg    {
78405b261ecSmrg	prev = &resources[j];
78505b261ecSmrg        while ( (this = *prev) )
78605b261ecSmrg	{
78705b261ecSmrg	    RESTYPE rtype = this->type;
78805b261ecSmrg	    if (rtype & RC_NEVERRETAIN)
78905b261ecSmrg	    {
79005b261ecSmrg#ifdef XSERVER_DTRACE
79105b261ecSmrg		XSERVER_RESOURCE_FREE(this->id, this->type,
79205b261ecSmrg			      this->value, TypeNameString(this->type));
79305b261ecSmrg#endif
79405b261ecSmrg		*prev = this->next;
7956747b715Smrg		clientTable[client->index].elements--;
7964642e01fSmrg
7974642e01fSmrg		CallResourceStateCallback(ResourceStateFreeing, this);
7984642e01fSmrg
7996747b715Smrg		elements = *eltptr;
8006747b715Smrg		(*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id);
8016747b715Smrg		free(this);
8026747b715Smrg		if (*eltptr != elements)
8036747b715Smrg		    prev = &resources[j]; /* prev may no longer be valid */
80405b261ecSmrg	    }
80505b261ecSmrg	    else
80605b261ecSmrg		prev = &this->next;
80705b261ecSmrg	}
80805b261ecSmrg    }
80905b261ecSmrg}
81005b261ecSmrg
81105b261ecSmrgvoid
81205b261ecSmrgFreeClientResources(ClientPtr client)
81305b261ecSmrg{
81405b261ecSmrg    ResourcePtr *resources;
81505b261ecSmrg    ResourcePtr this;
81605b261ecSmrg    int j;
81705b261ecSmrg
81805b261ecSmrg    /* This routine shouldn't be called with a null client, but just in
81905b261ecSmrg	case ... */
82005b261ecSmrg
82105b261ecSmrg    if (!client)
82205b261ecSmrg	return;
82305b261ecSmrg
82405b261ecSmrg    HandleSaveSet(client);
82505b261ecSmrg
82605b261ecSmrg    resources = clientTable[client->index].resources;
82705b261ecSmrg    for (j=0; j < clientTable[client->index].buckets; j++)
82805b261ecSmrg    {
82905b261ecSmrg        /* It may seem silly to update the head of this resource list as
83005b261ecSmrg	we delete the members, since the entire list will be deleted any way,
83105b261ecSmrg	but there are some resource deletion functions "FreeClientPixels" for
83205b261ecSmrg	one which do a LookupID on another resource id (a Colormap id in this
83305b261ecSmrg	case), so the resource list must be kept valid up to the point that
83405b261ecSmrg	it is deleted, so every time we delete a resource, we must update the
83505b261ecSmrg	head, just like in FreeResource. I hope that this doesn't slow down
83605b261ecSmrg	mass deletion appreciably. PRH */
83705b261ecSmrg
83805b261ecSmrg	ResourcePtr *head;
83905b261ecSmrg
84005b261ecSmrg	head = &resources[j];
84105b261ecSmrg
84205b261ecSmrg        for (this = *head; this; this = *head)
84305b261ecSmrg	{
84405b261ecSmrg	    RESTYPE rtype = this->type;
84505b261ecSmrg#ifdef XSERVER_DTRACE
84605b261ecSmrg	    XSERVER_RESOURCE_FREE(this->id, this->type,
84705b261ecSmrg			  this->value, TypeNameString(this->type));
84805b261ecSmrg#endif
84905b261ecSmrg	    *head = this->next;
8506747b715Smrg	    clientTable[client->index].elements--;
8514642e01fSmrg
8524642e01fSmrg	    CallResourceStateCallback(ResourceStateFreeing, this);
8534642e01fSmrg
8546747b715Smrg	    (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id);
8556747b715Smrg	    free(this);
85605b261ecSmrg	}
85705b261ecSmrg    }
8586747b715Smrg    free(clientTable[client->index].resources);
85905b261ecSmrg    clientTable[client->index].resources = NULL;
86005b261ecSmrg    clientTable[client->index].buckets = 0;
86105b261ecSmrg}
86205b261ecSmrg
86305b261ecSmrgvoid
86405b261ecSmrgFreeAllResources(void)
86505b261ecSmrg{
86605b261ecSmrg    int	i;
86705b261ecSmrg
86805b261ecSmrg    for (i = currentMaxClients; --i >= 0; )
86905b261ecSmrg    {
87005b261ecSmrg        if (clientTable[i].buckets)
87105b261ecSmrg	    FreeClientResources(clients[i]);
87205b261ecSmrg    }
87305b261ecSmrg}
87405b261ecSmrg
8756747b715SmrgBool
87605b261ecSmrgLegalNewID(XID id, ClientPtr client)
87705b261ecSmrg{
8786747b715Smrg    pointer val;
8796747b715Smrg    int rc;
88005b261ecSmrg
88105b261ecSmrg#ifdef PANORAMIX
88205b261ecSmrg    XID 	minid, maxid;
88305b261ecSmrg
8849ace9065Smrg    if (!noPanoramiXExtension) {
8859ace9065Smrg        minid = client->clientAsMask | (client->index ?
8869ace9065Smrg                                        SERVER_BIT : SERVER_MINID);
8879ace9065Smrg        maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1;
8889ace9065Smrg        if ((id >= minid) && (id <= maxid))
8899ace9065Smrg            return TRUE;
8909ace9065Smrg    }
89105b261ecSmrg#endif /* PANORAMIX */
8929ace9065Smrg    if (client->clientAsMask == (id & ~RESOURCE_ID_MASK))
8939ace9065Smrg    {
8949ace9065Smrg        rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
8959ace9065Smrg                                      DixGetAttrAccess);
8969ace9065Smrg        return rc == BadValue;
8979ace9065Smrg    }
8989ace9065Smrg    return FALSE;
89905b261ecSmrg}
90005b261ecSmrg
9016747b715Smrgint
902b86d567bSmrgdixLookupResourceByType(pointer *result, XID id, RESTYPE rtype,
903b86d567bSmrg			ClientPtr client, Mask mode)
90405b261ecSmrg{
9054642e01fSmrg    int cid = CLIENT_ID(id);
90605b261ecSmrg    ResourcePtr res = NULL;
90705b261ecSmrg
9084642e01fSmrg    *result = NULL;
9096747b715Smrg    if ((rtype & TypeMask) > lastResourceType)
9106747b715Smrg	return BadImplementation;
9114642e01fSmrg
9124642e01fSmrg    if ((cid < MAXCLIENTS) && clientTable[cid].buckets) {
91305b261ecSmrg	res = clientTable[cid].resources[Hash(cid, id)];
91405b261ecSmrg
91505b261ecSmrg	for (; res; res = res->next)
916b86d567bSmrg	    if (res->id == id && res->type == rtype)
917b86d567bSmrg		break;
918b86d567bSmrg    }
919b86d567bSmrg    if (!res)
9206747b715Smrg	return resourceTypes[rtype & TypeMask].errorValue;
921b86d567bSmrg
922b86d567bSmrg    if (client) {
923b86d567bSmrg	client->errorValue = id;
924b86d567bSmrg	cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
925b86d567bSmrg		       res->value, RT_NONE, NULL, mode);
9266747b715Smrg	if (cid == BadValue)
9276747b715Smrg	    return resourceTypes[rtype & TypeMask].errorValue;
928b86d567bSmrg	if (cid != Success)
929b86d567bSmrg	    return cid;
930b86d567bSmrg    }
931b86d567bSmrg
932b86d567bSmrg    *result = res->value;
933b86d567bSmrg    return Success;
934b86d567bSmrg}
935b86d567bSmrg
9366747b715Smrgint
937b86d567bSmrgdixLookupResourceByClass(pointer *result, XID id, RESTYPE rclass,
938b86d567bSmrg			 ClientPtr client, Mask mode)
939b86d567bSmrg{
940b86d567bSmrg    int cid = CLIENT_ID(id);
941b86d567bSmrg    ResourcePtr res = NULL;
942b86d567bSmrg
943b86d567bSmrg    *result = NULL;
944b86d567bSmrg
945b86d567bSmrg    if ((cid < MAXCLIENTS) && clientTable[cid].buckets) {
946b86d567bSmrg	res = clientTable[cid].resources[Hash(cid, id)];
947b86d567bSmrg
948b86d567bSmrg	for (; res; res = res->next)
949b86d567bSmrg	    if (res->id == id && (res->type & rclass))
95005b261ecSmrg		break;
95105b261ecSmrg    }
9524642e01fSmrg    if (!res)
9534642e01fSmrg	return BadValue;
9544642e01fSmrg
9554642e01fSmrg    if (client) {
9564642e01fSmrg	client->errorValue = id;
9574642e01fSmrg	cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
9584642e01fSmrg		       res->value, RT_NONE, NULL, mode);
9594642e01fSmrg	if (cid != Success)
9604642e01fSmrg	    return cid;
9614642e01fSmrg    }
96205b261ecSmrg
9634642e01fSmrg    *result = res->value;
9644642e01fSmrg    return Success;
96505b261ecSmrg}
966