resource.c revision 706f2543
1/************************************************************
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25
26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
27
28                        All Rights Reserved
29
30Permission to use, copy, modify, and distribute this software and its
31documentation for any purpose and without fee is hereby granted,
32provided that the above copyright notice appear in all copies and that
33both that copyright notice and this permission notice appear in
34supporting documentation, and that the name of Digital not be
35used in advertising or publicity pertaining to distribution of the
36software without specific, written prior permission.
37
38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44SOFTWARE.
45
46********************************************************/
47/* The panoramix components contained the following notice */
48/*****************************************************************
49
50Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
51
52Permission is hereby granted, free of charge, to any person obtaining a copy
53of this software and associated documentation files (the "Software"), to deal
54in the Software without restriction, including without limitation the rights
55to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
56copies of the Software.
57
58The above copyright notice and this permission notice shall be included in
59all copies or substantial portions of the Software.
60
61THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
64DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
65BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
66WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
67IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
68
69Except as contained in this notice, the name of Digital Equipment Corporation
70shall not be used in advertising or otherwise to promote the sale, use or other
71dealings in this Software without prior written authorization from Digital
72Equipment Corporation.
73
74******************************************************************/
75/* XSERVER_DTRACE additions:
76 * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved.
77 *
78 * Permission is hereby granted, free of charge, to any person obtaining a
79 * copy of this software and associated documentation files (the "Software"),
80 * to deal in the Software without restriction, including without limitation
81 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
82 * and/or sell copies of the Software, and to permit persons to whom the
83 * Software is furnished to do so, subject to the following conditions:
84 *
85 * The above copyright notice and this permission notice (including the next
86 * paragraph) shall be included in all copies or substantial portions of the
87 * Software.
88 *
89 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
90 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
91 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
92 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
93 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
94 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
95 * DEALINGS IN THE SOFTWARE.
96 */
97
98/*	Routines to manage various kinds of resources:
99 *
100 *	CreateNewResourceType, CreateNewResourceClass, InitClientResources,
101 *	FakeClientID, AddResource, FreeResource, FreeClientResources,
102 *	FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange
103 */
104
105/*
106 *      A resource ID is a 32 bit quantity, the upper 2 bits of which are
107 *	off-limits for client-visible resources.  The next 8 bits are
108 *      used as client ID, and the low 22 bits come from the client.
109 *	A resource ID is "hashed" by extracting and xoring subfields
110 *      (varying with the size of the hash table).
111 *
112 *      It is sometimes necessary for the server to create an ID that looks
113 *      like it belongs to a client.  This ID, however,  must not be one
114 *      the client actually can create, or we have the potential for conflict.
115 *      The 31st bit of the ID is reserved for the server's use for this
116 *      purpose.  By setting CLIENT_ID(id) to the client, the SERVER_BIT to
117 *      1, and an otherwise arbitrary ID in the low 22 bits, we can create a
118 *      resource "owned" by the client.
119 */
120
121#ifdef HAVE_DIX_CONFIG_H
122#include <dix-config.h>
123#endif
124
125#include <X11/X.h>
126#include "misc.h"
127#include "os.h"
128#include "resource.h"
129#include "dixstruct.h"
130#include "opaque.h"
131#include "windowstr.h"
132#include "dixfont.h"
133#include "colormap.h"
134#include "inputstr.h"
135#include "dixevents.h"
136#include "dixgrabs.h"
137#include "cursor.h"
138#ifdef PANORAMIX
139#include "panoramiX.h"
140#include "panoramiXsrv.h"
141#endif
142#include "xace.h"
143#include <assert.h>
144#include "registry.h"
145
146#ifdef XSERVER_DTRACE
147#include <sys/types.h>
148typedef const char *string;
149#include "Xserver-dtrace.h"
150
151#define TypeNameString(t) LookupResourceName(t)
152#endif
153
154static void RebuildTable(
155    int /*client*/
156);
157
158#define SERVER_MINID 32
159
160#define INITBUCKETS 64
161#define INITHASHSIZE 6
162#define MAXHASHSIZE 11
163
164typedef struct _Resource {
165    struct _Resource	*next;
166    XID			id;
167    RESTYPE		type;
168    pointer		value;
169} ResourceRec, *ResourcePtr;
170
171typedef struct _ClientResource {
172    ResourcePtr *resources;
173    int		elements;
174    int		buckets;
175    int		hashsize;	/* log(2)(buckets) */
176    XID		fakeID;
177    XID		endFakeID;
178} ClientResourceRec;
179
180RESTYPE lastResourceType;
181static RESTYPE lastResourceClass;
182RESTYPE TypeMask;
183
184struct ResourceType {
185    DeleteType deleteFunc;
186    int errorValue;
187};
188
189static struct ResourceType *resourceTypes;
190static const struct ResourceType predefTypes[] = {
191    [RT_NONE & (RC_LASTPREDEF - 1)] = {
192	.deleteFunc = (DeleteType)NoopDDA,
193	.errorValue = BadValue,
194    },
195    [RT_WINDOW & (RC_LASTPREDEF - 1)] = {
196	.deleteFunc = DeleteWindow,
197	.errorValue = BadWindow,
198    },
199    [RT_PIXMAP & (RC_LASTPREDEF - 1)] = {
200	.deleteFunc = dixDestroyPixmap,
201	.errorValue = BadPixmap,
202    },
203    [RT_GC & (RC_LASTPREDEF - 1)] = {
204	.deleteFunc = FreeGC,
205	.errorValue = BadGC,
206    },
207    [RT_FONT & (RC_LASTPREDEF - 1)] = {
208	.deleteFunc = CloseFont,
209	.errorValue = BadFont,
210    },
211    [RT_CURSOR & (RC_LASTPREDEF - 1)] = {
212	.deleteFunc = FreeCursor,
213	.errorValue = BadCursor,
214    },
215    [RT_COLORMAP & (RC_LASTPREDEF - 1)] = {
216	.deleteFunc = FreeColormap,
217	.errorValue = BadColor,
218    },
219    [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = {
220	.deleteFunc = FreeClientPixels,
221	.errorValue = BadColor,
222    },
223    [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = {
224	.deleteFunc = OtherClientGone,
225	.errorValue = BadValue,
226    },
227    [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = {
228	.deleteFunc = DeletePassiveGrab,
229	.errorValue = BadValue,
230    },
231};
232
233CallbackListPtr ResourceStateCallback;
234
235static _X_INLINE void
236CallResourceStateCallback(ResourceState state, ResourceRec *res)
237{
238    if (ResourceStateCallback) {
239	ResourceStateInfoRec rsi = { state, res->id, res->type, res->value };
240	CallCallbacks(&ResourceStateCallback, &rsi);
241    }
242}
243
244RESTYPE
245CreateNewResourceType(DeleteType deleteFunc, char *name)
246{
247    RESTYPE next = lastResourceType + 1;
248    struct ResourceType *types;
249
250    if (next & lastResourceClass)
251	return 0;
252    types = realloc(resourceTypes, (next + 1) * sizeof(*resourceTypes));
253    if (!types)
254	return 0;
255
256    lastResourceType = next;
257    resourceTypes = types;
258    resourceTypes[next].deleteFunc = deleteFunc;
259    resourceTypes[next].errorValue = BadValue;
260
261    /* Called even if name is NULL, to remove any previous entry */
262    RegisterResourceName(next, name);
263
264    return next;
265}
266
267void
268SetResourceTypeErrorValue(RESTYPE type, int errorValue)
269{
270    resourceTypes[type & TypeMask].errorValue = errorValue;
271}
272
273RESTYPE
274CreateNewResourceClass(void)
275{
276    RESTYPE next = lastResourceClass >> 1;
277
278    if (next & lastResourceType)
279	return 0;
280    lastResourceClass = next;
281    TypeMask = next - 1;
282    return next;
283}
284
285static ClientResourceRec clientTable[MAXCLIENTS];
286
287/*****************
288 * InitClientResources
289 *    When a new client is created, call this to allocate space
290 *    in resource table
291 *****************/
292
293Bool
294InitClientResources(ClientPtr client)
295{
296    int i, j;
297
298    if (client == serverClient)
299    {
300	lastResourceType = RT_LASTPREDEF;
301	lastResourceClass = RC_LASTPREDEF;
302	TypeMask = RC_LASTPREDEF - 1;
303	free(resourceTypes);
304	resourceTypes = malloc(sizeof(predefTypes));
305	if (!resourceTypes)
306	    return FALSE;
307	memcpy(resourceTypes, predefTypes, sizeof(predefTypes));
308    }
309    clientTable[i = client->index].resources =
310	malloc(INITBUCKETS*sizeof(ResourcePtr));
311    if (!clientTable[i].resources)
312	return FALSE;
313    clientTable[i].buckets = INITBUCKETS;
314    clientTable[i].elements = 0;
315    clientTable[i].hashsize = INITHASHSIZE;
316    /* Many IDs allocated from the server client are visible to clients,
317     * so we don't use the SERVER_BIT for them, but we have to start
318     * past the magic value constants used in the protocol.  For normal
319     * clients, we can start from zero, with SERVER_BIT set.
320     */
321    clientTable[i].fakeID = client->clientAsMask |
322			    (client->index ? SERVER_BIT : SERVER_MINID);
323    clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1;
324    for (j=0; j<INITBUCKETS; j++)
325    {
326        clientTable[i].resources[j] = NULL;
327    }
328    return TRUE;
329}
330
331
332static int
333Hash(int client, XID id)
334{
335    id &= RESOURCE_ID_MASK;
336    switch (clientTable[client].hashsize)
337    {
338	case 6:
339	    return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12))));
340	case 7:
341	    return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13))));
342	case 8:
343	    return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16))));
344	case 9:
345	    return ((int)(0x1FF & (id ^ (id>>9))));
346	case 10:
347	    return ((int)(0x3FF & (id ^ (id>>10))));
348	case 11:
349	    return ((int)(0x7FF & (id ^ (id>>11))));
350    }
351    return -1;
352}
353
354static XID
355AvailableID(
356    int client,
357    XID id,
358    XID maxid,
359    XID goodid)
360{
361    ResourcePtr res;
362
363    if ((goodid >= id) && (goodid <= maxid))
364	return goodid;
365    for (; id <= maxid; id++)
366    {
367	res = clientTable[client].resources[Hash(client, id)];
368	while (res && (res->id != id))
369	    res = res->next;
370	if (!res)
371	    return id;
372    }
373    return 0;
374}
375
376void
377GetXIDRange(int client, Bool server, XID *minp, XID *maxp)
378{
379    XID id, maxid;
380    ResourcePtr *resp;
381    ResourcePtr res;
382    int i;
383    XID goodid;
384
385    id = (Mask)client << CLIENTOFFSET;
386    if (server)
387	id |= client ? SERVER_BIT : SERVER_MINID;
388    maxid = id | RESOURCE_ID_MASK;
389    goodid = 0;
390    for (resp = clientTable[client].resources, i = clientTable[client].buckets;
391	 --i >= 0;)
392    {
393	for (res = *resp++; res; res = res->next)
394	{
395	    if ((res->id < id) || (res->id > maxid))
396		continue;
397	    if (((res->id - id) >= (maxid - res->id)) ?
398		(goodid = AvailableID(client, id, res->id - 1, goodid)) :
399		!(goodid = AvailableID(client, res->id + 1, maxid, goodid)))
400		maxid = res->id - 1;
401	    else
402		id = res->id + 1;
403	}
404    }
405    if (id > maxid)
406	id = maxid = 0;
407    *minp = id;
408    *maxp = maxid;
409}
410
411/**
412 *  GetXIDList is called by the XC-MISC extension's MiscGetXIDList function.
413 *  This function tries to find count unused XIDs for the given client.  It
414 *  puts the IDs in the array pids and returns the number found, which should
415 *  almost always be the number requested.
416 *
417 *  The circumstances that lead to a call to this function are very rare.
418 *  Xlib must run out of IDs while trying to generate a request that wants
419 *  multiple ID's, like the Multi-buffering CreateImageBuffers request.
420 *
421 *  No rocket science in the implementation; just iterate over all
422 *  possible IDs for the given client and pick the first count IDs
423 *  that aren't in use.  A more efficient algorithm could probably be
424 *  invented, but this will be used so rarely that this should suffice.
425 */
426
427unsigned int
428GetXIDList(ClientPtr pClient, unsigned count, XID *pids)
429{
430    unsigned int found = 0;
431    XID rc, id = pClient->clientAsMask;
432    XID maxid;
433    pointer val;
434
435    maxid = id | RESOURCE_ID_MASK;
436    while ( (found < count) && (id <= maxid) )
437    {
438	rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
439				      DixGetAttrAccess);
440	if (rc == BadValue)
441	{
442	    pids[found++] = id;
443	}
444	id++;
445    }
446    return found;
447}
448
449/*
450 * Return the next usable fake client ID.
451 *
452 * Normally this is just the next one in line, but if we've used the last
453 * in the range, we need to find a new range of safe IDs to avoid
454 * over-running another client.
455 */
456
457XID
458FakeClientID(int client)
459{
460    XID id, maxid;
461
462    id = clientTable[client].fakeID++;
463    if (id != clientTable[client].endFakeID)
464	return id;
465    GetXIDRange(client, TRUE, &id, &maxid);
466    if (!id) {
467	if (!client)
468	    FatalError("FakeClientID: server internal ids exhausted\n");
469	MarkClientException(clients[client]);
470	id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3);
471	maxid = id | RESOURCE_ID_MASK;
472    }
473    clientTable[client].fakeID = id + 1;
474    clientTable[client].endFakeID = maxid + 1;
475    return id;
476}
477
478Bool
479AddResource(XID id, RESTYPE type, pointer value)
480{
481    int client;
482    ClientResourceRec *rrec;
483    ResourcePtr res, *head;
484
485#ifdef XSERVER_DTRACE
486    XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type));
487#endif
488    client = CLIENT_ID(id);
489    rrec = &clientTable[client];
490    if (!rrec->buckets)
491    {
492	ErrorF("[dix] AddResource(%lx, %lx, %lx), client=%d \n",
493		(unsigned long)id, type, (unsigned long)value, client);
494        FatalError("client not in use\n");
495    }
496    if ((rrec->elements >= 4*rrec->buckets) &&
497	(rrec->hashsize < MAXHASHSIZE))
498	RebuildTable(client);
499    head = &rrec->resources[Hash(client, id)];
500    res = malloc(sizeof(ResourceRec));
501    if (!res)
502    {
503	(*resourceTypes[type & TypeMask].deleteFunc)(value, id);
504	return FALSE;
505    }
506    res->next = *head;
507    res->id = id;
508    res->type = type;
509    res->value = value;
510    *head = res;
511    rrec->elements++;
512    CallResourceStateCallback(ResourceStateAdding, res);
513    return TRUE;
514}
515
516static void
517RebuildTable(int client)
518{
519    int j;
520    ResourcePtr res, next;
521    ResourcePtr **tails, *resources;
522    ResourcePtr **tptr, *rptr;
523
524    /*
525     * For now, preserve insertion order, since some ddx layers depend
526     * on resources being free in the opposite order they are added.
527     */
528
529    j = 2 * clientTable[client].buckets;
530    tails = malloc(j * sizeof(ResourcePtr *));
531    if (!tails)
532	return;
533    resources = malloc(j * sizeof(ResourcePtr));
534    if (!resources)
535    {
536	free(tails);
537	return;
538    }
539    for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++)
540    {
541	*rptr = NULL;
542	*tptr = rptr;
543    }
544    clientTable[client].hashsize++;
545    for (j = clientTable[client].buckets,
546	 rptr = clientTable[client].resources;
547	 --j >= 0;
548	 rptr++)
549    {
550	for (res = *rptr; res; res = next)
551	{
552	    next = res->next;
553	    res->next = NULL;
554	    tptr = &tails[Hash(client, res->id)];
555	    **tptr = res;
556	    *tptr = &res->next;
557	}
558    }
559    free(tails);
560    clientTable[client].buckets *= 2;
561    free(clientTable[client].resources);
562    clientTable[client].resources = resources;
563}
564
565void
566FreeResource(XID id, RESTYPE skipDeleteFuncType)
567{
568    int		cid;
569    ResourcePtr res;
570    ResourcePtr *prev, *head;
571    int *eltptr;
572    int		elements;
573
574    if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
575    {
576	head = &clientTable[cid].resources[Hash(cid, id)];
577	eltptr = &clientTable[cid].elements;
578
579	prev = head;
580	while ( (res = *prev) )
581	{
582	    if (res->id == id)
583	    {
584		RESTYPE rtype = res->type;
585
586#ifdef XSERVER_DTRACE
587		XSERVER_RESOURCE_FREE(res->id, res->type,
588			      res->value, TypeNameString(res->type));
589#endif
590		*prev = res->next;
591		elements = --*eltptr;
592
593		CallResourceStateCallback(ResourceStateFreeing, res);
594
595		if (rtype != skipDeleteFuncType)
596		    (*resourceTypes[rtype & TypeMask].deleteFunc)(res->value, res->id);
597		free(res);
598		if (*eltptr != elements)
599		    prev = head; /* prev may no longer be valid */
600	    }
601	    else
602		prev = &res->next;
603        }
604    }
605}
606
607
608void
609FreeResourceByType(XID id, RESTYPE type, Bool skipFree)
610{
611    int		cid;
612    ResourcePtr res;
613    ResourcePtr *prev, *head;
614    if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
615    {
616	head = &clientTable[cid].resources[Hash(cid, id)];
617
618	prev = head;
619	while ( (res = *prev) )
620	{
621	    if (res->id == id && res->type == type)
622	    {
623#ifdef XSERVER_DTRACE
624		XSERVER_RESOURCE_FREE(res->id, res->type,
625			      res->value, TypeNameString(res->type));
626#endif
627		*prev = res->next;
628		clientTable[cid].elements--;
629
630		CallResourceStateCallback(ResourceStateFreeing, res);
631
632		if (!skipFree)
633		    (*resourceTypes[type & TypeMask].deleteFunc)(res->value, res->id);
634		free(res);
635		break;
636	    }
637	    else
638		prev = &res->next;
639        }
640    }
641}
642
643/*
644 * Change the value associated with a resource id.  Caller
645 * is responsible for "doing the right thing" with the old
646 * data
647 */
648
649Bool
650ChangeResourceValue (XID id, RESTYPE rtype, pointer value)
651{
652    int    cid;
653    ResourcePtr res;
654
655    if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
656    {
657	res = clientTable[cid].resources[Hash(cid, id)];
658
659	for (; res; res = res->next)
660	    if ((res->id == id) && (res->type == rtype))
661	    {
662		res->value = value;
663		return TRUE;
664	    }
665    }
666    return FALSE;
667}
668
669/* Note: if func adds or deletes resources, then func can get called
670 * more than once for some resources.  If func adds new resources,
671 * func might or might not get called for them.  func cannot both
672 * add and delete an equal number of resources!
673 */
674
675void
676FindClientResourcesByType(
677    ClientPtr client,
678    RESTYPE type,
679    FindResType func,
680    pointer cdata
681){
682    ResourcePtr *resources;
683    ResourcePtr this, next;
684    int i, elements;
685    int *eltptr;
686
687    if (!client)
688	client = serverClient;
689
690    resources = clientTable[client->index].resources;
691    eltptr = &clientTable[client->index].elements;
692    for (i = 0; i < clientTable[client->index].buckets; i++)
693    {
694        for (this = resources[i]; this; this = next)
695	{
696	    next = this->next;
697	    if (!type || this->type == type) {
698		elements = *eltptr;
699		(*func)(this->value, this->id, cdata);
700		if (*eltptr != elements)
701		    next = resources[i]; /* start over */
702	    }
703	}
704    }
705}
706
707void
708FindAllClientResources(
709    ClientPtr client,
710    FindAllRes func,
711    pointer cdata
712){
713    ResourcePtr *resources;
714    ResourcePtr this, next;
715    int i, elements;
716    int *eltptr;
717
718    if (!client)
719        client = serverClient;
720
721    resources = clientTable[client->index].resources;
722    eltptr = &clientTable[client->index].elements;
723    for (i = 0; i < clientTable[client->index].buckets; i++)
724    {
725        for (this = resources[i]; this; this = next)
726        {
727            next = this->next;
728            elements = *eltptr;
729            (*func)(this->value, this->id, this->type, cdata);
730            if (*eltptr != elements)
731                next = resources[i]; /* start over */
732        }
733    }
734}
735
736
737pointer
738LookupClientResourceComplex(
739    ClientPtr client,
740    RESTYPE type,
741    FindComplexResType func,
742    pointer cdata
743){
744    ResourcePtr *resources;
745    ResourcePtr this, next;
746    pointer value;
747    int i;
748
749    if (!client)
750	client = serverClient;
751
752    resources = clientTable[client->index].resources;
753    for (i = 0; i < clientTable[client->index].buckets; i++) {
754        for (this = resources[i]; this; this = next) {
755	    next = this->next;
756	    if (!type || this->type == type) {
757		/* workaround func freeing the type as DRI1 does */
758		value = this->value;
759		if((*func)(value, this->id, cdata))
760		    return value;
761	    }
762	}
763    }
764    return NULL;
765}
766
767
768void
769FreeClientNeverRetainResources(ClientPtr client)
770{
771    ResourcePtr *resources;
772    ResourcePtr this;
773    ResourcePtr *prev;
774    int j, elements;
775    int *eltptr;
776
777    if (!client)
778	return;
779
780    resources = clientTable[client->index].resources;
781    eltptr = &clientTable[client->index].elements;
782    for (j=0; j < clientTable[client->index].buckets; j++)
783    {
784	prev = &resources[j];
785        while ( (this = *prev) )
786	{
787	    RESTYPE rtype = this->type;
788	    if (rtype & RC_NEVERRETAIN)
789	    {
790#ifdef XSERVER_DTRACE
791		XSERVER_RESOURCE_FREE(this->id, this->type,
792			      this->value, TypeNameString(this->type));
793#endif
794		*prev = this->next;
795		clientTable[client->index].elements--;
796
797		CallResourceStateCallback(ResourceStateFreeing, this);
798
799		elements = *eltptr;
800		(*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id);
801		free(this);
802		if (*eltptr != elements)
803		    prev = &resources[j]; /* prev may no longer be valid */
804	    }
805	    else
806		prev = &this->next;
807	}
808    }
809}
810
811void
812FreeClientResources(ClientPtr client)
813{
814    ResourcePtr *resources;
815    ResourcePtr this;
816    int j;
817
818    /* This routine shouldn't be called with a null client, but just in
819	case ... */
820
821    if (!client)
822	return;
823
824    HandleSaveSet(client);
825
826    resources = clientTable[client->index].resources;
827    for (j=0; j < clientTable[client->index].buckets; j++)
828    {
829        /* It may seem silly to update the head of this resource list as
830	we delete the members, since the entire list will be deleted any way,
831	but there are some resource deletion functions "FreeClientPixels" for
832	one which do a LookupID on another resource id (a Colormap id in this
833	case), so the resource list must be kept valid up to the point that
834	it is deleted, so every time we delete a resource, we must update the
835	head, just like in FreeResource. I hope that this doesn't slow down
836	mass deletion appreciably. PRH */
837
838	ResourcePtr *head;
839
840	head = &resources[j];
841
842        for (this = *head; this; this = *head)
843	{
844	    RESTYPE rtype = this->type;
845#ifdef XSERVER_DTRACE
846	    XSERVER_RESOURCE_FREE(this->id, this->type,
847			  this->value, TypeNameString(this->type));
848#endif
849	    *head = this->next;
850	    clientTable[client->index].elements--;
851
852	    CallResourceStateCallback(ResourceStateFreeing, this);
853
854	    (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id);
855	    free(this);
856	}
857    }
858    free(clientTable[client->index].resources);
859    clientTable[client->index].resources = NULL;
860    clientTable[client->index].buckets = 0;
861}
862
863void
864FreeAllResources(void)
865{
866    int	i;
867
868    for (i = currentMaxClients; --i >= 0; )
869    {
870        if (clientTable[i].buckets)
871	    FreeClientResources(clients[i]);
872    }
873}
874
875Bool
876LegalNewID(XID id, ClientPtr client)
877{
878    pointer val;
879    int rc;
880
881#ifdef PANORAMIX
882    XID 	minid, maxid;
883
884    if (!noPanoramiXExtension) {
885        minid = client->clientAsMask | (client->index ?
886                                        SERVER_BIT : SERVER_MINID);
887        maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1;
888        if ((id >= minid) && (id <= maxid))
889            return TRUE;
890    }
891#endif /* PANORAMIX */
892    if (client->clientAsMask == (id & ~RESOURCE_ID_MASK))
893    {
894        rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
895                                      DixGetAttrAccess);
896        return rc == BadValue;
897    }
898    return FALSE;
899}
900
901int
902dixLookupResourceByType(pointer *result, XID id, RESTYPE rtype,
903			ClientPtr client, Mask mode)
904{
905    int cid = CLIENT_ID(id);
906    ResourcePtr res = NULL;
907
908    *result = NULL;
909    if ((rtype & TypeMask) > lastResourceType)
910	return BadImplementation;
911
912    if ((cid < MAXCLIENTS) && clientTable[cid].buckets) {
913	res = clientTable[cid].resources[Hash(cid, id)];
914
915	for (; res; res = res->next)
916	    if (res->id == id && res->type == rtype)
917		break;
918    }
919    if (!res)
920	return resourceTypes[rtype & TypeMask].errorValue;
921
922    if (client) {
923	client->errorValue = id;
924	cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
925		       res->value, RT_NONE, NULL, mode);
926	if (cid == BadValue)
927	    return resourceTypes[rtype & TypeMask].errorValue;
928	if (cid != Success)
929	    return cid;
930    }
931
932    *result = res->value;
933    return Success;
934}
935
936int
937dixLookupResourceByClass(pointer *result, XID id, RESTYPE rclass,
938			 ClientPtr client, Mask mode)
939{
940    int cid = CLIENT_ID(id);
941    ResourcePtr res = NULL;
942
943    *result = NULL;
944
945    if ((cid < MAXCLIENTS) && clientTable[cid].buckets) {
946	res = clientTable[cid].resources[Hash(cid, id)];
947
948	for (; res; res = res->next)
949	    if (res->id == id && (res->type & rclass))
950		break;
951    }
952    if (!res)
953	return BadValue;
954
955    if (client) {
956	client->errorValue = id;
957	cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
958		       res->value, RT_NONE, NULL, mode);
959	if (cid != Success)
960	    return cid;
961    }
962
963    *result = res->value;
964    return Success;
965}
966