resource.c revision 6747b715
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 2005-2006 Sun Microsystems, Inc.  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#define NullResource ((ResourcePtr)NULL)
171
172typedef struct _ClientResource {
173    ResourcePtr *resources;
174    int		elements;
175    int		buckets;
176    int		hashsize;	/* log(2)(buckets) */
177    XID		fakeID;
178    XID		endFakeID;
179    XID		expectID;
180} ClientResourceRec;
181
182RESTYPE lastResourceType;
183static RESTYPE lastResourceClass;
184RESTYPE TypeMask;
185
186struct ResourceType {
187    DeleteType deleteFunc;
188    int errorValue;
189};
190
191static struct ResourceType *resourceTypes;
192static const struct ResourceType predefTypes[] = {
193    [RT_NONE & (RC_LASTPREDEF - 1)] = {
194	.deleteFunc = (DeleteType)NoopDDA,
195	.errorValue = BadValue,
196    },
197    [RT_WINDOW & (RC_LASTPREDEF - 1)] = {
198	.deleteFunc = DeleteWindow,
199	.errorValue = BadWindow,
200    },
201    [RT_PIXMAP & (RC_LASTPREDEF - 1)] = {
202	.deleteFunc = dixDestroyPixmap,
203	.errorValue = BadPixmap,
204    },
205    [RT_GC & (RC_LASTPREDEF - 1)] = {
206	.deleteFunc = FreeGC,
207	.errorValue = BadGC,
208    },
209    [RT_FONT & (RC_LASTPREDEF - 1)] = {
210	.deleteFunc = CloseFont,
211	.errorValue = BadFont,
212    },
213    [RT_CURSOR & (RC_LASTPREDEF - 1)] = {
214	.deleteFunc = FreeCursor,
215	.errorValue = BadCursor,
216    },
217    [RT_COLORMAP & (RC_LASTPREDEF - 1)] = {
218	.deleteFunc = FreeColormap,
219	.errorValue = BadColor,
220    },
221    [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = {
222	.deleteFunc = FreeClientPixels,
223	.errorValue = BadColor,
224    },
225    [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = {
226	.deleteFunc = OtherClientGone,
227	.errorValue = BadValue,
228    },
229    [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = {
230	.deleteFunc = DeletePassiveGrab,
231	.errorValue = BadValue,
232    },
233};
234
235CallbackListPtr ResourceStateCallback;
236
237static _X_INLINE void
238CallResourceStateCallback(ResourceState state, ResourceRec *res)
239{
240    if (ResourceStateCallback) {
241	ResourceStateInfoRec rsi = { state, res->id, res->type, res->value };
242	CallCallbacks(&ResourceStateCallback, &rsi);
243    }
244}
245
246RESTYPE
247CreateNewResourceType(DeleteType deleteFunc, char *name)
248{
249    RESTYPE next = lastResourceType + 1;
250    struct ResourceType *types;
251
252    if (next & lastResourceClass)
253	return 0;
254    types = realloc(resourceTypes, (next + 1) * sizeof(*resourceTypes));
255    if (!types)
256	return 0;
257
258    lastResourceType = next;
259    resourceTypes = types;
260    resourceTypes[next].deleteFunc = deleteFunc;
261    resourceTypes[next].errorValue = BadValue;
262
263    /* Called even if name is NULL, to remove any previous entry */
264    RegisterResourceName(next, name);
265
266    return next;
267}
268
269void
270SetResourceTypeErrorValue(RESTYPE type, int errorValue)
271{
272    resourceTypes[type & TypeMask].errorValue = errorValue;
273}
274
275RESTYPE
276CreateNewResourceClass(void)
277{
278    RESTYPE next = lastResourceClass >> 1;
279
280    if (next & lastResourceType)
281	return 0;
282    lastResourceClass = next;
283    TypeMask = next - 1;
284    return next;
285}
286
287static ClientResourceRec clientTable[MAXCLIENTS];
288
289/*****************
290 * InitClientResources
291 *    When a new client is created, call this to allocate space
292 *    in resource table
293 *****************/
294
295Bool
296InitClientResources(ClientPtr client)
297{
298    int i, j;
299
300    if (client == serverClient)
301    {
302	lastResourceType = RT_LASTPREDEF;
303	lastResourceClass = RC_LASTPREDEF;
304	TypeMask = RC_LASTPREDEF - 1;
305	free(resourceTypes);
306	resourceTypes = malloc(sizeof(predefTypes));
307	if (!resourceTypes)
308	    return FALSE;
309	memcpy(resourceTypes, predefTypes, sizeof(predefTypes));
310    }
311    clientTable[i = client->index].resources =
312	malloc(INITBUCKETS*sizeof(ResourcePtr));
313    if (!clientTable[i].resources)
314	return FALSE;
315    clientTable[i].buckets = INITBUCKETS;
316    clientTable[i].elements = 0;
317    clientTable[i].hashsize = INITHASHSIZE;
318    /* Many IDs allocated from the server client are visible to clients,
319     * so we don't use the SERVER_BIT for them, but we have to start
320     * past the magic value constants used in the protocol.  For normal
321     * clients, we can start from zero, with SERVER_BIT set.
322     */
323    clientTable[i].fakeID = client->clientAsMask |
324			    (client->index ? SERVER_BIT : SERVER_MINID);
325    clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1;
326    clientTable[i].expectID = client->clientAsMask;
327    for (j=0; j<INITBUCKETS; j++)
328    {
329        clientTable[i].resources[j] = NullResource;
330    }
331    return TRUE;
332}
333
334
335static int
336Hash(int client, XID id)
337{
338    id &= RESOURCE_ID_MASK;
339    switch (clientTable[client].hashsize)
340    {
341	case 6:
342	    return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12))));
343	case 7:
344	    return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13))));
345	case 8:
346	    return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16))));
347	case 9:
348	    return ((int)(0x1FF & (id ^ (id>>9))));
349	case 10:
350	    return ((int)(0x3FF & (id ^ (id>>10))));
351	case 11:
352	    return ((int)(0x7FF & (id ^ (id>>11))));
353    }
354    return -1;
355}
356
357static XID
358AvailableID(
359    int client,
360    XID id,
361    XID maxid,
362    XID goodid)
363{
364    ResourcePtr res;
365
366    if ((goodid >= id) && (goodid <= maxid))
367	return goodid;
368    for (; id <= maxid; id++)
369    {
370	res = clientTable[client].resources[Hash(client, id)];
371	while (res && (res->id != id))
372	    res = res->next;
373	if (!res)
374	    return id;
375    }
376    return 0;
377}
378
379void
380GetXIDRange(int client, Bool server, XID *minp, XID *maxp)
381{
382    XID id, maxid;
383    ResourcePtr *resp;
384    ResourcePtr res;
385    int i;
386    XID goodid;
387
388    id = (Mask)client << CLIENTOFFSET;
389    if (server)
390	id |= client ? SERVER_BIT : SERVER_MINID;
391    maxid = id | RESOURCE_ID_MASK;
392    goodid = 0;
393    for (resp = clientTable[client].resources, i = clientTable[client].buckets;
394	 --i >= 0;)
395    {
396	for (res = *resp++; res; res = res->next)
397	{
398	    if ((res->id < id) || (res->id > maxid))
399		continue;
400	    if (((res->id - id) >= (maxid - res->id)) ?
401		(goodid = AvailableID(client, id, res->id - 1, goodid)) :
402		!(goodid = AvailableID(client, res->id + 1, maxid, goodid)))
403		maxid = res->id - 1;
404	    else
405		id = res->id + 1;
406	}
407    }
408    if (id > maxid)
409	id = maxid = 0;
410    *minp = id;
411    *maxp = maxid;
412}
413
414/**
415 *  GetXIDList is called by the XC-MISC extension's MiscGetXIDList function.
416 *  This function tries to find count unused XIDs for the given client.  It
417 *  puts the IDs in the array pids and returns the number found, which should
418 *  almost always be the number requested.
419 *
420 *  The circumstances that lead to a call to this function are very rare.
421 *  Xlib must run out of IDs while trying to generate a request that wants
422 *  multiple ID's, like the Multi-buffering CreateImageBuffers request.
423 *
424 *  No rocket science in the implementation; just iterate over all
425 *  possible IDs for the given client and pick the first count IDs
426 *  that aren't in use.  A more efficient algorithm could probably be
427 *  invented, but this will be used so rarely that this should suffice.
428 */
429
430unsigned int
431GetXIDList(ClientPtr pClient, unsigned count, XID *pids)
432{
433    unsigned int found = 0;
434    XID rc, id = pClient->clientAsMask;
435    XID maxid;
436    pointer val;
437
438    maxid = id | RESOURCE_ID_MASK;
439    while ( (found < count) && (id <= maxid) )
440    {
441	rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
442				      DixGetAttrAccess);
443	if (rc == BadValue)
444	{
445	    pids[found++] = id;
446	}
447	id++;
448    }
449    return found;
450}
451
452/*
453 * Return the next usable fake client ID.
454 *
455 * Normally this is just the next one in line, but if we've used the last
456 * in the range, we need to find a new range of safe IDs to avoid
457 * over-running another client.
458 */
459
460XID
461FakeClientID(int client)
462{
463    XID id, maxid;
464
465    id = clientTable[client].fakeID++;
466    if (id != clientTable[client].endFakeID)
467	return id;
468    GetXIDRange(client, TRUE, &id, &maxid);
469    if (!id) {
470	if (!client)
471	    FatalError("FakeClientID: server internal ids exhausted\n");
472	MarkClientException(clients[client]);
473	id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3);
474	maxid = id | RESOURCE_ID_MASK;
475    }
476    clientTable[client].fakeID = id + 1;
477    clientTable[client].endFakeID = maxid + 1;
478    return id;
479}
480
481Bool
482AddResource(XID id, RESTYPE type, pointer value)
483{
484    int client;
485    ClientResourceRec *rrec;
486    ResourcePtr res, *head;
487
488#ifdef XSERVER_DTRACE
489    XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type));
490#endif
491    client = CLIENT_ID(id);
492    rrec = &clientTable[client];
493    if (!rrec->buckets)
494    {
495	ErrorF("[dix] AddResource(%lx, %lx, %lx), client=%d \n",
496		(unsigned long)id, type, (unsigned long)value, client);
497        FatalError("client not in use\n");
498    }
499    if ((rrec->elements >= 4*rrec->buckets) &&
500	(rrec->hashsize < MAXHASHSIZE))
501	RebuildTable(client);
502    head = &rrec->resources[Hash(client, id)];
503    res = malloc(sizeof(ResourceRec));
504    if (!res)
505    {
506	(*resourceTypes[type & TypeMask].deleteFunc)(value, id);
507	return FALSE;
508    }
509    res->next = *head;
510    res->id = id;
511    res->type = type;
512    res->value = value;
513    *head = res;
514    rrec->elements++;
515    if (!(id & SERVER_BIT) && (id >= rrec->expectID))
516	rrec->expectID = id + 1;
517    CallResourceStateCallback(ResourceStateAdding, res);
518    return TRUE;
519}
520
521static void
522RebuildTable(int client)
523{
524    int j;
525    ResourcePtr res, next;
526    ResourcePtr **tails, *resources;
527    ResourcePtr **tptr, *rptr;
528
529    /*
530     * For now, preserve insertion order, since some ddx layers depend
531     * on resources being free in the opposite order they are added.
532     */
533
534    j = 2 * clientTable[client].buckets;
535    tails = malloc(j * sizeof(ResourcePtr *));
536    if (!tails)
537	return;
538    resources = malloc(j * sizeof(ResourcePtr));
539    if (!resources)
540    {
541	free(tails);
542	return;
543    }
544    for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++)
545    {
546	*rptr = NullResource;
547	*tptr = rptr;
548    }
549    clientTable[client].hashsize++;
550    for (j = clientTable[client].buckets,
551	 rptr = clientTable[client].resources;
552	 --j >= 0;
553	 rptr++)
554    {
555	for (res = *rptr; res; res = next)
556	{
557	    next = res->next;
558	    res->next = NullResource;
559	    tptr = &tails[Hash(client, res->id)];
560	    **tptr = res;
561	    *tptr = &res->next;
562	}
563    }
564    free(tails);
565    clientTable[client].buckets *= 2;
566    free(clientTable[client].resources);
567    clientTable[client].resources = resources;
568}
569
570void
571FreeResource(XID id, RESTYPE skipDeleteFuncType)
572{
573    int		cid;
574    ResourcePtr res;
575    ResourcePtr *prev, *head;
576    int *eltptr;
577    int		elements;
578
579    if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
580    {
581	head = &clientTable[cid].resources[Hash(cid, id)];
582	eltptr = &clientTable[cid].elements;
583
584	prev = head;
585	while ( (res = *prev) )
586	{
587	    if (res->id == id)
588	    {
589		RESTYPE rtype = res->type;
590
591#ifdef XSERVER_DTRACE
592		XSERVER_RESOURCE_FREE(res->id, res->type,
593			      res->value, TypeNameString(res->type));
594#endif
595		*prev = res->next;
596		elements = --*eltptr;
597
598		CallResourceStateCallback(ResourceStateFreeing, res);
599
600		if (rtype != skipDeleteFuncType)
601		    (*resourceTypes[rtype & TypeMask].deleteFunc)(res->value, res->id);
602		free(res);
603		if (*eltptr != elements)
604		    prev = head; /* prev may no longer be valid */
605	    }
606	    else
607		prev = &res->next;
608        }
609    }
610}
611
612
613void
614FreeResourceByType(XID id, RESTYPE type, Bool skipFree)
615{
616    int		cid;
617    ResourcePtr res;
618    ResourcePtr *prev, *head;
619    if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
620    {
621	head = &clientTable[cid].resources[Hash(cid, id)];
622
623	prev = head;
624	while ( (res = *prev) )
625	{
626	    if (res->id == id && res->type == type)
627	    {
628#ifdef XSERVER_DTRACE
629		XSERVER_RESOURCE_FREE(res->id, res->type,
630			      res->value, TypeNameString(res->type));
631#endif
632		*prev = res->next;
633		clientTable[cid].elements--;
634
635		CallResourceStateCallback(ResourceStateFreeing, res);
636
637		if (!skipFree)
638		    (*resourceTypes[type & TypeMask].deleteFunc)(res->value, res->id);
639		free(res);
640		break;
641	    }
642	    else
643		prev = &res->next;
644        }
645    }
646}
647
648/*
649 * Change the value associated with a resource id.  Caller
650 * is responsible for "doing the right thing" with the old
651 * data
652 */
653
654Bool
655ChangeResourceValue (XID id, RESTYPE rtype, pointer value)
656{
657    int    cid;
658    ResourcePtr res;
659
660    if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
661    {
662	res = clientTable[cid].resources[Hash(cid, id)];
663
664	for (; res; res = res->next)
665	    if ((res->id == id) && (res->type == rtype))
666	    {
667		res->value = value;
668		return TRUE;
669	    }
670    }
671    return FALSE;
672}
673
674/* Note: if func adds or deletes resources, then func can get called
675 * more than once for some resources.  If func adds new resources,
676 * func might or might not get called for them.  func cannot both
677 * add and delete an equal number of resources!
678 */
679
680void
681FindClientResourcesByType(
682    ClientPtr client,
683    RESTYPE type,
684    FindResType func,
685    pointer cdata
686){
687    ResourcePtr *resources;
688    ResourcePtr this, next;
689    int i, elements;
690    int *eltptr;
691
692    if (!client)
693	client = serverClient;
694
695    resources = clientTable[client->index].resources;
696    eltptr = &clientTable[client->index].elements;
697    for (i = 0; i < clientTable[client->index].buckets; i++)
698    {
699        for (this = resources[i]; this; this = next)
700	{
701	    next = this->next;
702	    if (!type || this->type == type) {
703		elements = *eltptr;
704		(*func)(this->value, this->id, cdata);
705		if (*eltptr != elements)
706		    next = resources[i]; /* start over */
707	    }
708	}
709    }
710}
711
712void
713FindAllClientResources(
714    ClientPtr client,
715    FindAllRes func,
716    pointer cdata
717){
718    ResourcePtr *resources;
719    ResourcePtr this, next;
720    int i, elements;
721    int *eltptr;
722
723    if (!client)
724        client = serverClient;
725
726    resources = clientTable[client->index].resources;
727    eltptr = &clientTable[client->index].elements;
728    for (i = 0; i < clientTable[client->index].buckets; i++)
729    {
730        for (this = resources[i]; this; this = next)
731        {
732            next = this->next;
733            elements = *eltptr;
734            (*func)(this->value, this->id, this->type, cdata);
735            if (*eltptr != elements)
736                next = resources[i]; /* start over */
737        }
738    }
739}
740
741
742pointer
743LookupClientResourceComplex(
744    ClientPtr client,
745    RESTYPE type,
746    FindComplexResType func,
747    pointer cdata
748){
749    ResourcePtr *resources;
750    ResourcePtr this, next;
751    pointer value;
752    int i;
753
754    if (!client)
755	client = serverClient;
756
757    resources = clientTable[client->index].resources;
758    for (i = 0; i < clientTable[client->index].buckets; i++) {
759        for (this = resources[i]; this; this = next) {
760	    next = this->next;
761	    if (!type || this->type == type) {
762		/* workaround func freeing the type as DRI1 does */
763		value = this->value;
764		if((*func)(value, this->id, cdata))
765		    return value;
766	    }
767	}
768    }
769    return NULL;
770}
771
772
773void
774FreeClientNeverRetainResources(ClientPtr client)
775{
776    ResourcePtr *resources;
777    ResourcePtr this;
778    ResourcePtr *prev;
779    int j, elements;
780    int *eltptr;
781
782    if (!client)
783	return;
784
785    resources = clientTable[client->index].resources;
786    eltptr = &clientTable[client->index].elements;
787    for (j=0; j < clientTable[client->index].buckets; j++)
788    {
789	prev = &resources[j];
790        while ( (this = *prev) )
791	{
792	    RESTYPE rtype = this->type;
793	    if (rtype & RC_NEVERRETAIN)
794	    {
795#ifdef XSERVER_DTRACE
796		XSERVER_RESOURCE_FREE(this->id, this->type,
797			      this->value, TypeNameString(this->type));
798#endif
799		*prev = this->next;
800		clientTable[client->index].elements--;
801
802		CallResourceStateCallback(ResourceStateFreeing, this);
803
804		elements = *eltptr;
805		(*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id);
806		free(this);
807		if (*eltptr != elements)
808		    prev = &resources[j]; /* prev may no longer be valid */
809	    }
810	    else
811		prev = &this->next;
812	}
813    }
814}
815
816void
817FreeClientResources(ClientPtr client)
818{
819    ResourcePtr *resources;
820    ResourcePtr this;
821    int j;
822
823    /* This routine shouldn't be called with a null client, but just in
824	case ... */
825
826    if (!client)
827	return;
828
829    HandleSaveSet(client);
830
831    resources = clientTable[client->index].resources;
832    for (j=0; j < clientTable[client->index].buckets; j++)
833    {
834        /* It may seem silly to update the head of this resource list as
835	we delete the members, since the entire list will be deleted any way,
836	but there are some resource deletion functions "FreeClientPixels" for
837	one which do a LookupID on another resource id (a Colormap id in this
838	case), so the resource list must be kept valid up to the point that
839	it is deleted, so every time we delete a resource, we must update the
840	head, just like in FreeResource. I hope that this doesn't slow down
841	mass deletion appreciably. PRH */
842
843	ResourcePtr *head;
844
845	head = &resources[j];
846
847        for (this = *head; this; this = *head)
848	{
849	    RESTYPE rtype = this->type;
850#ifdef XSERVER_DTRACE
851	    XSERVER_RESOURCE_FREE(this->id, this->type,
852			  this->value, TypeNameString(this->type));
853#endif
854	    *head = this->next;
855	    clientTable[client->index].elements--;
856
857	    CallResourceStateCallback(ResourceStateFreeing, this);
858
859	    (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id);
860	    free(this);
861	}
862    }
863    free(clientTable[client->index].resources);
864    clientTable[client->index].resources = NULL;
865    clientTable[client->index].buckets = 0;
866}
867
868void
869FreeAllResources(void)
870{
871    int	i;
872
873    for (i = currentMaxClients; --i >= 0; )
874    {
875        if (clientTable[i].buckets)
876	    FreeClientResources(clients[i]);
877    }
878}
879
880Bool
881LegalNewID(XID id, ClientPtr client)
882{
883    pointer val;
884    int rc;
885
886#ifdef PANORAMIX
887    XID 	minid, maxid;
888
889	if (!noPanoramiXExtension) {
890	    minid = client->clientAsMask | (client->index ?
891			                    SERVER_BIT : SERVER_MINID);
892	    maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1;
893            if ((id >= minid) && (id <= maxid))
894	        return TRUE;
895	}
896#endif /* PANORAMIX */
897	if (client->clientAsMask == (id & ~RESOURCE_ID_MASK))
898	{
899	    if (clientTable[client->index].expectID <= id)
900		return TRUE;
901
902	    rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
903					  DixGetAttrAccess);
904	    return rc == BadValue;
905	}
906	return FALSE;
907}
908
909int
910dixLookupResourceByType(pointer *result, XID id, RESTYPE rtype,
911			ClientPtr client, Mask mode)
912{
913    int cid = CLIENT_ID(id);
914    ResourcePtr res = NULL;
915
916    *result = NULL;
917    if ((rtype & TypeMask) > lastResourceType)
918	return BadImplementation;
919
920    if ((cid < MAXCLIENTS) && clientTable[cid].buckets) {
921	res = clientTable[cid].resources[Hash(cid, id)];
922
923	for (; res; res = res->next)
924	    if (res->id == id && res->type == rtype)
925		break;
926    }
927    if (!res)
928	return resourceTypes[rtype & TypeMask].errorValue;
929
930    if (client) {
931	client->errorValue = id;
932	cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
933		       res->value, RT_NONE, NULL, mode);
934	if (cid == BadValue)
935	    return resourceTypes[rtype & TypeMask].errorValue;
936	if (cid != Success)
937	    return cid;
938    }
939
940    *result = res->value;
941    return Success;
942}
943
944int
945dixLookupResourceByClass(pointer *result, XID id, RESTYPE rclass,
946			 ClientPtr client, Mask mode)
947{
948    int cid = CLIENT_ID(id);
949    ResourcePtr res = NULL;
950
951    *result = NULL;
952
953    if ((cid < MAXCLIENTS) && clientTable[cid].buckets) {
954	res = clientTable[cid].resources[Hash(cid, id)];
955
956	for (; res; res = res->next)
957	    if (res->id == id && (res->type & rclass))
958		break;
959    }
960    if (!res)
961	return BadValue;
962
963    if (client) {
964	client->errorValue = id;
965	cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
966		       res->value, RT_NONE, NULL, mode);
967	if (cid != Success)
968	    return cid;
969    }
970
971    *result = res->value;
972    return Success;
973}
974