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