resource.c revision a1e1cf94
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
25Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27                        All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45********************************************************/
46/* The panoramix components contained the following notice */
47/*****************************************************************
48
49Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
50
51Permission is hereby granted, free of charge, to any person obtaining a copy
52of this software and associated documentation files (the "Software"), to deal
53in the Software without restriction, including without limitation the rights
54to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
55copies of the Software.
56
57The above copyright notice and this permission notice shall be included in
58all copies or substantial portions of the Software.
59
60THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
63DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
64BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
65WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
66IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
67
68Except as contained in this notice, the name of Digital Equipment Corporation
69shall not be used in advertising or otherwise to promote the sale, use or other
70dealings in this Software without prior written authorization from Digital
71Equipment Corporation.
72
73******************************************************************/
74/* XSERVER_DTRACE additions:
75 * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved.
76 *
77 * Permission is hereby granted, free of charge, to any person obtaining a
78 * copy of this software and associated documentation files (the "Software"),
79 * to deal in the Software without restriction, including without limitation
80 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
81 * and/or sell copies of the Software, and to permit persons to whom the
82 * Software is furnished to do so, subject to the following conditions:
83 *
84 * The above copyright notice and this permission notice (including the next
85 * paragraph) shall be included in all copies or substantial portions of the
86 * Software.
87 *
88 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
89 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
90 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
91 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
92 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
93 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
94 * DEALINGS IN THE SOFTWARE.
95 */
96
97/*	Routines to manage various kinds of resources:
98 *
99 *	CreateNewResourceType, CreateNewResourceClass, InitClientResources,
100 *	FakeClientID, AddResource, FreeResource, FreeClientResources,
101 *	FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange
102 */
103
104/*
105 *      A resource ID is a 32 bit quantity, the upper 2 bits of which are
106 *	off-limits for client-visible resources.  The next 8 bits are
107 *      used as client ID, and the low 22 bits come from the client.
108 *	A resource ID is "hashed" by extracting and xoring subfields
109 *      (varying with the size of the hash table).
110 *
111 *      It is sometimes necessary for the server to create an ID that looks
112 *      like it belongs to a client.  This ID, however,  must not be one
113 *      the client actually can create, or we have the potential for conflict.
114 *      The 31st bit of the ID is reserved for the server's use for this
115 *      purpose.  By setting CLIENT_ID(id) to the client, the SERVER_BIT to
116 *      1, and an otherwise arbitrary ID in the low 22 bits, we can create a
117 *      resource "owned" by the client.
118 */
119
120#ifdef HAVE_DIX_CONFIG_H
121#include <dix-config.h>
122#endif
123
124#include <X11/X.h>
125#include "misc.h"
126#include "os.h"
127#include "resource.h"
128#include "dixstruct.h"
129#include "opaque.h"
130#include "windowstr.h"
131#include "dixfont.h"
132#include "colormap.h"
133#include "inputstr.h"
134#include "dixevents.h"
135#include "dixgrabs.h"
136#include "cursor.h"
137#ifdef PANORAMIX
138#include "panoramiX.h"
139#include "panoramiXsrv.h"
140#endif
141#include "xace.h"
142#include <assert.h>
143#include "registry.h"
144#include "gcstruct.h"
145
146#ifdef XSERVER_DTRACE
147#include "probes.h"
148
149#define TypeNameString(t) LookupResourceName(t)
150#endif
151
152static void RebuildTable(int    /*client */
153    );
154
155#define SERVER_MINID 32
156
157#define INITBUCKETS 64
158#define INITHASHSIZE 6
159#define MAXHASHSIZE 16
160
161typedef struct _Resource {
162    struct _Resource *next;
163    XID id;
164    RESTYPE type;
165    void *value;
166} ResourceRec, *ResourcePtr;
167
168typedef struct _ClientResource {
169    ResourcePtr *resources;
170    int elements;
171    int buckets;
172    int hashsize;               /* log(2)(buckets) */
173    XID fakeID;
174    XID endFakeID;
175} ClientResourceRec;
176
177RESTYPE lastResourceType;
178static RESTYPE lastResourceClass;
179RESTYPE TypeMask;
180
181struct ResourceType {
182    DeleteType deleteFunc;
183    SizeType sizeFunc;
184    FindTypeSubResources findSubResFunc;
185    int errorValue;
186};
187
188/**
189 * Used by all resources that don't specify a function to calculate
190 * resource size. Currently this is used for all resources with
191 * insignificant memory usage.
192 *
193 * @see GetResourceTypeSizeFunc, SetResourceTypeSizeFunc
194 *
195 * @param[in] value Pointer to resource object.
196 *
197 * @param[in] id Resource ID for the object.
198 *
199 * @param[out] size Fill all fields to zero to indicate that size of
200 *                  resource can't be determined.
201 */
202static void
203GetDefaultBytes(void *value, XID id, ResourceSizePtr size)
204{
205    size->resourceSize = 0;
206    size->pixmapRefSize = 0;
207    size->refCnt = 1;
208}
209
210/**
211 * Used by all resources that don't specify a function to iterate
212 * through subresources. Currently this is used for all resources with
213 * insignificant memory usage.
214 *
215 * @see FindSubResources, SetResourceTypeFindSubResFunc
216 *
217 * @param[in] value Pointer to resource object.
218 *
219 * @param[in] func Function to call for each subresource.
220
221 * @param[out] cdata Pointer to opaque data.
222 */
223static void
224DefaultFindSubRes(void *value, FindAllRes func, void *cdata)
225{
226    /* do nothing */
227}
228
229/**
230 * Calculate drawable size in bytes. Reference counting is not taken
231 * into account.
232 *
233 * @param[in] drawable Pointer to a drawable.
234 *
235 * @return Estimate of total memory usage for the drawable.
236 */
237static unsigned long
238GetDrawableBytes(DrawablePtr drawable)
239{
240    int bytes = 0;
241
242    if (drawable)
243    {
244        int bytesPerPixel = drawable->bitsPerPixel >> 3;
245        int numberOfPixels = drawable->width * drawable->height;
246        bytes = numberOfPixels * bytesPerPixel;
247    }
248
249    return bytes;
250}
251
252/**
253 * Calculate pixmap size in bytes. Reference counting is taken into
254 * account. Any extra data attached by extensions and drivers is not
255 * taken into account. The purpose of this function is to estimate
256 * memory usage that can be attributed to single reference of the
257 * pixmap.
258 *
259 * @param[in] value Pointer to a pixmap.
260 *
261 * @param[in] id Resource ID of pixmap. If the pixmap hasn't been
262 *               added as resource, just pass value->drawable.id.
263 *
264 * @param[out] size Estimate of memory usage attributed to a single
265 *                  pixmap reference.
266 */
267static void
268GetPixmapBytes(void *value, XID id, ResourceSizePtr size)
269{
270    PixmapPtr pixmap = value;
271
272    size->resourceSize = 0;
273    size->pixmapRefSize = 0;
274    size->refCnt = pixmap->refcnt;
275
276    if (pixmap && pixmap->refcnt)
277    {
278        DrawablePtr drawable = &pixmap->drawable;
279        size->resourceSize = GetDrawableBytes(drawable);
280        size->pixmapRefSize = size->resourceSize / pixmap->refcnt;
281    }
282}
283
284/**
285 * Calculate window size in bytes. The purpose of this function is to
286 * estimate memory usage that can be attributed to all pixmap
287 * references of the window.
288 *
289 * @param[in] value Pointer to a window.
290 *
291 * @param[in] id Resource ID of window.
292 *
293 * @param[out] size Estimate of memory usage attributed to a all
294 *                  pixmap references of a window.
295 */
296static void
297GetWindowBytes(void *value, XID id, ResourceSizePtr size)
298{
299    SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
300    ResourceSizeRec pixmapSize = { 0, 0, 0 };
301    WindowPtr window = value;
302
303    /* Currently only pixmap bytes are reported to clients. */
304    size->resourceSize = 0;
305
306    /* Calculate pixmap reference sizes. */
307    size->pixmapRefSize = 0;
308
309    size->refCnt = 1;
310
311    if (window->backgroundState == BackgroundPixmap)
312    {
313        PixmapPtr pixmap = window->background.pixmap;
314        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
315        size->pixmapRefSize += pixmapSize.pixmapRefSize;
316    }
317    if (window->border.pixmap && !window->borderIsPixel)
318    {
319        PixmapPtr pixmap = window->border.pixmap;
320        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
321        size->pixmapRefSize += pixmapSize.pixmapRefSize;
322    }
323}
324
325/**
326 * Iterate through subresources of a window. The purpose of this
327 * function is to gather accurate information on what resources
328 * a resource uses.
329 *
330 * @note Currently only sub-pixmaps are iterated
331 *
332 * @param[in] value  Pointer to a window
333 *
334 * @param[in] func   Function to call with each subresource
335 *
336 * @param[out] cdata Pointer to opaque data
337 */
338static void
339FindWindowSubRes(void *value, FindAllRes func, void *cdata)
340{
341    WindowPtr window = value;
342
343    /* Currently only pixmap subresources are reported to clients. */
344
345    if (window->backgroundState == BackgroundPixmap)
346    {
347        PixmapPtr pixmap = window->background.pixmap;
348        func(window->background.pixmap, pixmap->drawable.id, RT_PIXMAP, cdata);
349    }
350    if (window->border.pixmap && !window->borderIsPixel)
351    {
352        PixmapPtr pixmap = window->border.pixmap;
353        func(window->background.pixmap, pixmap->drawable.id, RT_PIXMAP, cdata);
354    }
355}
356
357/**
358 * Calculate graphics context size in bytes. The purpose of this
359 * function is to estimate memory usage that can be attributed to all
360 * pixmap references of the graphics context.
361 *
362 * @param[in] value Pointer to a graphics context.
363 *
364 * @param[in] id    Resource ID of graphics context.
365 *
366 * @param[out] size Estimate of memory usage attributed to a all
367 *                  pixmap references of a graphics context.
368 */
369static void
370GetGcBytes(void *value, XID id, ResourceSizePtr size)
371{
372    SizeType pixmapSizeFunc = GetResourceTypeSizeFunc(RT_PIXMAP);
373    ResourceSizeRec pixmapSize = { 0, 0, 0 };
374    GCPtr gc = value;
375
376    /* Currently only pixmap bytes are reported to clients. */
377    size->resourceSize = 0;
378
379    /* Calculate pixmap reference sizes. */
380    size->pixmapRefSize = 0;
381
382    size->refCnt = 1;
383    if (gc->stipple)
384    {
385        PixmapPtr pixmap = gc->stipple;
386        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
387        size->pixmapRefSize += pixmapSize.pixmapRefSize;
388    }
389    if (gc->tile.pixmap && !gc->tileIsPixel)
390    {
391        PixmapPtr pixmap = gc->tile.pixmap;
392        pixmapSizeFunc(pixmap, pixmap->drawable.id, &pixmapSize);
393        size->pixmapRefSize += pixmapSize.pixmapRefSize;
394    }
395}
396
397/**
398 * Iterate through subresources of a graphics context. The purpose of
399 * this function is to gather accurate information on what resources a
400 * resource uses.
401 *
402 * @note Currently only sub-pixmaps are iterated
403 *
404 * @param[in] value  Pointer to a window
405 *
406 * @param[in] func   Function to call with each subresource
407 *
408 * @param[out] cdata Pointer to opaque data
409 */
410static void
411FindGCSubRes(void *value, FindAllRes func, void *cdata)
412{
413    GCPtr gc = value;
414
415    /* Currently only pixmap subresources are reported to clients. */
416
417    if (gc->stipple)
418    {
419        PixmapPtr pixmap = gc->stipple;
420        func(pixmap, pixmap->drawable.id, RT_PIXMAP, cdata);
421    }
422    if (gc->tile.pixmap && !gc->tileIsPixel)
423    {
424        PixmapPtr pixmap = gc->tile.pixmap;
425        func(pixmap, pixmap->drawable.id, RT_PIXMAP, cdata);
426    }
427}
428
429static struct ResourceType *resourceTypes;
430
431static const struct ResourceType predefTypes[] = {
432    [RT_NONE & (RC_LASTPREDEF - 1)] = {
433                                       .deleteFunc = (DeleteType) NoopDDA,
434                                       .sizeFunc = GetDefaultBytes,
435                                       .findSubResFunc = DefaultFindSubRes,
436                                       .errorValue = BadValue,
437                                       },
438    [RT_WINDOW & (RC_LASTPREDEF - 1)] = {
439                                         .deleteFunc = DeleteWindow,
440                                         .sizeFunc = GetWindowBytes,
441                                         .findSubResFunc = FindWindowSubRes,
442                                         .errorValue = BadWindow,
443                                         },
444    [RT_PIXMAP & (RC_LASTPREDEF - 1)] = {
445                                         .deleteFunc = dixDestroyPixmap,
446                                         .sizeFunc = GetPixmapBytes,
447                                         .findSubResFunc = DefaultFindSubRes,
448                                         .errorValue = BadPixmap,
449                                         },
450    [RT_GC & (RC_LASTPREDEF - 1)] = {
451                                     .deleteFunc = FreeGC,
452                                     .sizeFunc = GetGcBytes,
453                                     .findSubResFunc = FindGCSubRes,
454                                     .errorValue = BadGC,
455                                     },
456    [RT_FONT & (RC_LASTPREDEF - 1)] = {
457                                       .deleteFunc = CloseFont,
458                                       .sizeFunc = GetDefaultBytes,
459                                       .findSubResFunc = DefaultFindSubRes,
460                                       .errorValue = BadFont,
461                                       },
462    [RT_CURSOR & (RC_LASTPREDEF - 1)] = {
463                                         .deleteFunc = FreeCursor,
464                                         .sizeFunc = GetDefaultBytes,
465                                         .findSubResFunc = DefaultFindSubRes,
466                                         .errorValue = BadCursor,
467                                         },
468    [RT_COLORMAP & (RC_LASTPREDEF - 1)] = {
469                                           .deleteFunc = FreeColormap,
470                                           .sizeFunc = GetDefaultBytes,
471                                           .findSubResFunc = DefaultFindSubRes,
472                                           .errorValue = BadColor,
473                                           },
474    [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = {
475                                            .deleteFunc = FreeClientPixels,
476                                            .sizeFunc = GetDefaultBytes,
477                                            .findSubResFunc = DefaultFindSubRes,
478                                            .errorValue = BadColor,
479                                            },
480    [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = {
481                                              .deleteFunc = OtherClientGone,
482                                              .sizeFunc = GetDefaultBytes,
483                                              .findSubResFunc = DefaultFindSubRes,
484                                              .errorValue = BadValue,
485                                              },
486    [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = {
487                                              .deleteFunc = DeletePassiveGrab,
488                                              .sizeFunc = GetDefaultBytes,
489                                              .findSubResFunc = DefaultFindSubRes,
490                                              .errorValue = BadValue,
491                                              },
492};
493
494CallbackListPtr ResourceStateCallback;
495
496static _X_INLINE void
497CallResourceStateCallback(ResourceState state, ResourceRec * res)
498{
499    if (ResourceStateCallback) {
500        ResourceStateInfoRec rsi = { state, res->id, res->type, res->value };
501        CallCallbacks(&ResourceStateCallback, &rsi);
502    }
503}
504
505RESTYPE
506CreateNewResourceType(DeleteType deleteFunc, const char *name)
507{
508    RESTYPE next = lastResourceType + 1;
509    struct ResourceType *types;
510
511    if (next & lastResourceClass)
512        return 0;
513    types = reallocarray(resourceTypes, next + 1, sizeof(*resourceTypes));
514    if (!types)
515        return 0;
516
517    lastResourceType = next;
518    resourceTypes = types;
519    resourceTypes[next].deleteFunc = deleteFunc;
520    resourceTypes[next].sizeFunc = GetDefaultBytes;
521    resourceTypes[next].findSubResFunc = DefaultFindSubRes;
522    resourceTypes[next].errorValue = BadValue;
523
524#if X_REGISTRY_RESOURCE
525    /* Called even if name is NULL, to remove any previous entry */
526    RegisterResourceName(next, name);
527#endif
528
529    return next;
530}
531
532/**
533 * Get the function used to calculate resource size. Extensions and
534 * drivers need to be able to determine the current size calculation
535 * function if they want to wrap or override it.
536 *
537 * @param[in] type     Resource type used in size calculations.
538 *
539 * @return Function to calculate the size of a single
540 *                     resource.
541 */
542SizeType
543GetResourceTypeSizeFunc(RESTYPE type)
544{
545    return resourceTypes[type & TypeMask].sizeFunc;
546}
547
548/**
549 * Override the default function that calculates resource size. For
550 * example, video driver knows better how to calculate pixmap memory
551 * usage and can therefore wrap or override size calculation for
552 * RT_PIXMAP.
553 *
554 * @param[in] type     Resource type used in size calculations.
555 *
556 * @param[in] sizeFunc Function to calculate the size of a single
557 *                     resource.
558 */
559void
560SetResourceTypeSizeFunc(RESTYPE type, SizeType sizeFunc)
561{
562    resourceTypes[type & TypeMask].sizeFunc = sizeFunc;
563}
564
565/**
566 * Provide a function for iterating the subresources of a resource.
567 * This allows for example more accurate accounting of the (memory)
568 * resources consumed by a resource.
569 *
570 * @see FindSubResources
571 *
572 * @param[in] type     Resource type used in size calculations.
573 *
574 * @param[in] sizeFunc Function to calculate the size of a single
575 *                     resource.
576 */
577void
578SetResourceTypeFindSubResFunc(RESTYPE type, FindTypeSubResources findFunc)
579{
580    resourceTypes[type & TypeMask].findSubResFunc = findFunc;
581}
582
583void
584SetResourceTypeErrorValue(RESTYPE type, int errorValue)
585{
586    resourceTypes[type & TypeMask].errorValue = errorValue;
587}
588
589RESTYPE
590CreateNewResourceClass(void)
591{
592    RESTYPE next = lastResourceClass >> 1;
593
594    if (next & lastResourceType)
595        return 0;
596    lastResourceClass = next;
597    TypeMask = next - 1;
598    return next;
599}
600
601static ClientResourceRec clientTable[MAXCLIENTS];
602
603static unsigned int
604ilog2(int val)
605{
606    int bits;
607
608    if (val <= 0)
609	return 0;
610    for (bits = 0; val != 0; bits++)
611	val >>= 1;
612    return bits - 1;
613}
614
615/*****************
616 * ResourceClientBits
617 *    Returns the client bit offset in the client + resources ID field
618 *****************/
619
620unsigned int
621ResourceClientBits(void)
622{
623    static unsigned int cache_ilog2 = 0;
624    static unsigned int cache_limit = 0;
625
626    if (LimitClients != cache_limit) {
627        cache_limit = LimitClients;
628        cache_ilog2 = ilog2(LimitClients);
629    }
630
631    return cache_ilog2;
632}
633
634/*****************
635 * InitClientResources
636 *    When a new client is created, call this to allocate space
637 *    in resource table
638 *****************/
639
640Bool
641InitClientResources(ClientPtr client)
642{
643    int i, j;
644
645    if (client == serverClient) {
646        lastResourceType = RT_LASTPREDEF;
647        lastResourceClass = RC_LASTPREDEF;
648        TypeMask = RC_LASTPREDEF - 1;
649        free(resourceTypes);
650        resourceTypes = malloc(sizeof(predefTypes));
651        if (!resourceTypes)
652            return FALSE;
653        memcpy(resourceTypes, predefTypes, sizeof(predefTypes));
654    }
655    clientTable[i = client->index].resources =
656        malloc(INITBUCKETS * sizeof(ResourcePtr));
657    if (!clientTable[i].resources)
658        return FALSE;
659    clientTable[i].buckets = INITBUCKETS;
660    clientTable[i].elements = 0;
661    clientTable[i].hashsize = INITHASHSIZE;
662    /* Many IDs allocated from the server client are visible to clients,
663     * so we don't use the SERVER_BIT for them, but we have to start
664     * past the magic value constants used in the protocol.  For normal
665     * clients, we can start from zero, with SERVER_BIT set.
666     */
667    clientTable[i].fakeID = client->clientAsMask |
668        (client->index ? SERVER_BIT : SERVER_MINID);
669    clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1;
670    for (j = 0; j < INITBUCKETS; j++) {
671        clientTable[i].resources[j] = NULL;
672    }
673    return TRUE;
674}
675
676int
677HashResourceID(XID id, unsigned int numBits)
678{
679    static XID mask;
680
681    if (!mask)
682        mask = RESOURCE_ID_MASK;
683    id &= mask;
684    if (numBits < 9)
685        return (id ^ (id >> numBits) ^ (id >> (numBits<<1))) & ~((~0U) << numBits);
686    return (id ^ (id >> numBits)) & ~((~0) << numBits);
687}
688
689static XID
690AvailableID(int client, XID id, XID maxid, XID goodid)
691{
692    ResourcePtr res;
693
694    if ((goodid >= id) && (goodid <= maxid))
695        return goodid;
696    for (; id <= maxid; id++) {
697        res = clientTable[client].resources[HashResourceID(id, clientTable[client].hashsize)];
698        while (res && (res->id != id))
699            res = res->next;
700        if (!res)
701            return id;
702    }
703    return 0;
704}
705
706void
707GetXIDRange(int client, Bool server, XID *minp, XID *maxp)
708{
709    XID id, maxid;
710    ResourcePtr *resp;
711    ResourcePtr res;
712    int i;
713    XID goodid;
714
715    id = (Mask) client << CLIENTOFFSET;
716    if (server)
717        id |= client ? SERVER_BIT : SERVER_MINID;
718    maxid = id | RESOURCE_ID_MASK;
719    goodid = 0;
720    for (resp = clientTable[client].resources, i = clientTable[client].buckets;
721         --i >= 0;) {
722        for (res = *resp++; res; res = res->next) {
723            if ((res->id < id) || (res->id > maxid))
724                continue;
725            if (((res->id - id) >= (maxid - res->id)) ?
726                (goodid = AvailableID(client, id, res->id - 1, goodid)) :
727                !(goodid = AvailableID(client, res->id + 1, maxid, goodid)))
728                maxid = res->id - 1;
729            else
730                id = res->id + 1;
731        }
732    }
733    if (id > maxid)
734        id = maxid = 0;
735    *minp = id;
736    *maxp = maxid;
737}
738
739/**
740 *  GetXIDList is called by the XC-MISC extension's MiscGetXIDList function.
741 *  This function tries to find count unused XIDs for the given client.  It
742 *  puts the IDs in the array pids and returns the number found, which should
743 *  almost always be the number requested.
744 *
745 *  The circumstances that lead to a call to this function are very rare.
746 *  Xlib must run out of IDs while trying to generate a request that wants
747 *  multiple ID's, like the Multi-buffering CreateImageBuffers request.
748 *
749 *  No rocket science in the implementation; just iterate over all
750 *  possible IDs for the given client and pick the first count IDs
751 *  that aren't in use.  A more efficient algorithm could probably be
752 *  invented, but this will be used so rarely that this should suffice.
753 */
754
755unsigned int
756GetXIDList(ClientPtr pClient, unsigned count, XID *pids)
757{
758    unsigned int found = 0;
759    XID rc, id = pClient->clientAsMask;
760    XID maxid;
761    void *val;
762
763    maxid = id | RESOURCE_ID_MASK;
764    while ((found < count) && (id <= maxid)) {
765        rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
766                                      DixGetAttrAccess);
767        if (rc == BadValue) {
768            pids[found++] = id;
769        }
770        id++;
771    }
772    return found;
773}
774
775/*
776 * Return the next usable fake client ID.
777 *
778 * Normally this is just the next one in line, but if we've used the last
779 * in the range, we need to find a new range of safe IDs to avoid
780 * over-running another client.
781 */
782
783XID
784FakeClientID(int client)
785{
786    XID id, maxid;
787
788    id = clientTable[client].fakeID++;
789    if (id != clientTable[client].endFakeID)
790        return id;
791    GetXIDRange(client, TRUE, &id, &maxid);
792    if (!id) {
793        if (!client)
794            FatalError("FakeClientID: server internal ids exhausted\n");
795        MarkClientException(clients[client]);
796        id = ((Mask) client << CLIENTOFFSET) | (SERVER_BIT * 3);
797        maxid = id | RESOURCE_ID_MASK;
798    }
799    clientTable[client].fakeID = id + 1;
800    clientTable[client].endFakeID = maxid + 1;
801    return id;
802}
803
804Bool
805AddResource(XID id, RESTYPE type, void *value)
806{
807    int client;
808    ClientResourceRec *rrec;
809    ResourcePtr res, *head;
810
811#ifdef XSERVER_DTRACE
812    XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type));
813#endif
814    client = CLIENT_ID(id);
815    rrec = &clientTable[client];
816    if (!rrec->buckets) {
817        ErrorF("[dix] AddResource(%lx, %x, %lx), client=%d \n",
818               (unsigned long) id, type, (unsigned long) value, client);
819        FatalError("client not in use\n");
820    }
821    if ((rrec->elements >= 4 * rrec->buckets) && (rrec->hashsize < MAXHASHSIZE))
822        RebuildTable(client);
823    head = &rrec->resources[HashResourceID(id, clientTable[client].hashsize)];
824    res = malloc(sizeof(ResourceRec));
825    if (!res) {
826        (*resourceTypes[type & TypeMask].deleteFunc) (value, id);
827        return FALSE;
828    }
829    res->next = *head;
830    res->id = id;
831    res->type = type;
832    res->value = value;
833    *head = res;
834    rrec->elements++;
835    CallResourceStateCallback(ResourceStateAdding, res);
836    return TRUE;
837}
838
839static void
840RebuildTable(int client)
841{
842    int j;
843    ResourcePtr res, next;
844    ResourcePtr **tails, *resources;
845    ResourcePtr **tptr, *rptr;
846
847    /*
848     * For now, preserve insertion order, since some ddx layers depend
849     * on resources being free in the opposite order they are added.
850     */
851
852    j = 2 * clientTable[client].buckets;
853    tails =  xallocarray(j, sizeof(ResourcePtr *));
854    if (!tails)
855        return;
856    resources =  xallocarray(j, sizeof(ResourcePtr));
857    if (!resources) {
858        free(tails);
859        return;
860    }
861    for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) {
862        *rptr = NULL;
863        *tptr = rptr;
864    }
865    clientTable[client].hashsize++;
866    for (j = clientTable[client].buckets,
867         rptr = clientTable[client].resources; --j >= 0; rptr++) {
868        for (res = *rptr; res; res = next) {
869            next = res->next;
870            res->next = NULL;
871            tptr = &tails[HashResourceID(res->id, clientTable[client].hashsize)];
872            **tptr = res;
873            *tptr = &res->next;
874        }
875    }
876    free(tails);
877    clientTable[client].buckets *= 2;
878    free(clientTable[client].resources);
879    clientTable[client].resources = resources;
880}
881
882static void
883doFreeResource(ResourcePtr res, Bool skip)
884{
885    CallResourceStateCallback(ResourceStateFreeing, res);
886
887    if (!skip)
888        resourceTypes[res->type & TypeMask].deleteFunc(res->value, res->id);
889
890    free(res);
891}
892
893void
894FreeResource(XID id, RESTYPE skipDeleteFuncType)
895{
896    int cid;
897    ResourcePtr res;
898    ResourcePtr *prev, *head;
899    int *eltptr;
900    int elements;
901
902    if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
903        head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
904        eltptr = &clientTable[cid].elements;
905
906        prev = head;
907        while ((res = *prev)) {
908            if (res->id == id) {
909                RESTYPE rtype = res->type;
910
911#ifdef XSERVER_DTRACE
912                XSERVER_RESOURCE_FREE(res->id, res->type,
913                                      res->value, TypeNameString(res->type));
914#endif
915                *prev = res->next;
916                elements = --*eltptr;
917
918                doFreeResource(res, rtype == skipDeleteFuncType);
919
920                if (*eltptr != elements)
921                    prev = head;        /* prev may no longer be valid */
922            }
923            else
924                prev = &res->next;
925        }
926    }
927}
928
929void
930FreeResourceByType(XID id, RESTYPE type, Bool skipFree)
931{
932    int cid;
933    ResourcePtr res;
934    ResourcePtr *prev, *head;
935
936    if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
937        head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
938
939        prev = head;
940        while ((res = *prev)) {
941            if (res->id == id && res->type == type) {
942#ifdef XSERVER_DTRACE
943                XSERVER_RESOURCE_FREE(res->id, res->type,
944                                      res->value, TypeNameString(res->type));
945#endif
946                *prev = res->next;
947                clientTable[cid].elements--;
948
949                doFreeResource(res, skipFree);
950
951                break;
952            }
953            else
954                prev = &res->next;
955        }
956    }
957}
958
959/*
960 * Change the value associated with a resource id.  Caller
961 * is responsible for "doing the right thing" with the old
962 * data
963 */
964
965Bool
966ChangeResourceValue(XID id, RESTYPE rtype, void *value)
967{
968    int cid;
969    ResourcePtr res;
970
971    if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
972        res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
973
974        for (; res; res = res->next)
975            if ((res->id == id) && (res->type == rtype)) {
976                res->value = value;
977                return TRUE;
978            }
979    }
980    return FALSE;
981}
982
983/* Note: if func adds or deletes resources, then func can get called
984 * more than once for some resources.  If func adds new resources,
985 * func might or might not get called for them.  func cannot both
986 * add and delete an equal number of resources!
987 */
988
989void
990FindClientResourcesByType(ClientPtr client,
991                          RESTYPE type, FindResType func, void *cdata)
992{
993    ResourcePtr *resources;
994    ResourcePtr this, next;
995    int i, elements;
996    int *eltptr;
997
998    if (!client)
999        client = serverClient;
1000
1001    resources = clientTable[client->index].resources;
1002    eltptr = &clientTable[client->index].elements;
1003    for (i = 0; i < clientTable[client->index].buckets; i++) {
1004        for (this = resources[i]; this; this = next) {
1005            next = this->next;
1006            if (!type || this->type == type) {
1007                elements = *eltptr;
1008                (*func) (this->value, this->id, cdata);
1009                if (*eltptr != elements)
1010                    next = resources[i];        /* start over */
1011            }
1012        }
1013    }
1014}
1015
1016void FindSubResources(void *resource,
1017                      RESTYPE    type,
1018                      FindAllRes func,
1019                      void *cdata)
1020{
1021    struct ResourceType rtype = resourceTypes[type & TypeMask];
1022    rtype.findSubResFunc(resource, func, cdata);
1023}
1024
1025void
1026FindAllClientResources(ClientPtr client, FindAllRes func, void *cdata)
1027{
1028    ResourcePtr *resources;
1029    ResourcePtr this, next;
1030    int i, elements;
1031    int *eltptr;
1032
1033    if (!client)
1034        client = serverClient;
1035
1036    resources = clientTable[client->index].resources;
1037    eltptr = &clientTable[client->index].elements;
1038    for (i = 0; i < clientTable[client->index].buckets; i++) {
1039        for (this = resources[i]; this; this = next) {
1040            next = this->next;
1041            elements = *eltptr;
1042            (*func) (this->value, this->id, this->type, cdata);
1043            if (*eltptr != elements)
1044                next = resources[i];    /* start over */
1045        }
1046    }
1047}
1048
1049void *
1050LookupClientResourceComplex(ClientPtr client,
1051                            RESTYPE type,
1052                            FindComplexResType func, void *cdata)
1053{
1054    ResourcePtr *resources;
1055    ResourcePtr this, next;
1056    void *value;
1057    int i;
1058
1059    if (!client)
1060        client = serverClient;
1061
1062    resources = clientTable[client->index].resources;
1063    for (i = 0; i < clientTable[client->index].buckets; i++) {
1064        for (this = resources[i]; this; this = next) {
1065            next = this->next;
1066            if (!type || this->type == type) {
1067                /* workaround func freeing the type as DRI1 does */
1068                value = this->value;
1069                if ((*func) (value, this->id, cdata))
1070                    return value;
1071            }
1072        }
1073    }
1074    return NULL;
1075}
1076
1077void
1078FreeClientNeverRetainResources(ClientPtr client)
1079{
1080    ResourcePtr *resources;
1081    ResourcePtr this;
1082    ResourcePtr *prev;
1083    int j, elements;
1084    int *eltptr;
1085
1086    if (!client)
1087        return;
1088
1089    resources = clientTable[client->index].resources;
1090    eltptr = &clientTable[client->index].elements;
1091    for (j = 0; j < clientTable[client->index].buckets; j++) {
1092        prev = &resources[j];
1093        while ((this = *prev)) {
1094            RESTYPE rtype = this->type;
1095
1096            if (rtype & RC_NEVERRETAIN) {
1097#ifdef XSERVER_DTRACE
1098                XSERVER_RESOURCE_FREE(this->id, this->type,
1099                                      this->value, TypeNameString(this->type));
1100#endif
1101                *prev = this->next;
1102                clientTable[client->index].elements--;
1103                elements = *eltptr;
1104
1105                doFreeResource(this, FALSE);
1106
1107                if (*eltptr != elements)
1108                    prev = &resources[j];       /* prev may no longer be valid */
1109            }
1110            else
1111                prev = &this->next;
1112        }
1113    }
1114}
1115
1116void
1117FreeClientResources(ClientPtr client)
1118{
1119    ResourcePtr *resources;
1120    ResourcePtr this;
1121    int j;
1122
1123    /* This routine shouldn't be called with a null client, but just in
1124       case ... */
1125
1126    if (!client)
1127        return;
1128
1129    HandleSaveSet(client);
1130
1131    resources = clientTable[client->index].resources;
1132    for (j = 0; j < clientTable[client->index].buckets; j++) {
1133        /* It may seem silly to update the head of this resource list as
1134           we delete the members, since the entire list will be deleted any way,
1135           but there are some resource deletion functions "FreeClientPixels" for
1136           one which do a LookupID on another resource id (a Colormap id in this
1137           case), so the resource list must be kept valid up to the point that
1138           it is deleted, so every time we delete a resource, we must update the
1139           head, just like in FreeResource. I hope that this doesn't slow down
1140           mass deletion appreciably. PRH */
1141
1142        ResourcePtr *head;
1143
1144        head = &resources[j];
1145
1146        for (this = *head; this; this = *head) {
1147#ifdef XSERVER_DTRACE
1148            XSERVER_RESOURCE_FREE(this->id, this->type,
1149                                  this->value, TypeNameString(this->type));
1150#endif
1151            *head = this->next;
1152            clientTable[client->index].elements--;
1153
1154            doFreeResource(this, FALSE);
1155        }
1156    }
1157    free(clientTable[client->index].resources);
1158    clientTable[client->index].resources = NULL;
1159    clientTable[client->index].buckets = 0;
1160}
1161
1162void
1163FreeAllResources(void)
1164{
1165    int i;
1166
1167    for (i = currentMaxClients; --i >= 0;) {
1168        if (clientTable[i].buckets)
1169            FreeClientResources(clients[i]);
1170    }
1171}
1172
1173Bool
1174LegalNewID(XID id, ClientPtr client)
1175{
1176    void *val;
1177    int rc;
1178
1179#ifdef PANORAMIX
1180    XID minid, maxid;
1181
1182    if (!noPanoramiXExtension) {
1183        minid = client->clientAsMask | (client->index ?
1184                                        SERVER_BIT : SERVER_MINID);
1185        maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1;
1186        if ((id >= minid) && (id <= maxid))
1187            return TRUE;
1188    }
1189#endif                          /* PANORAMIX */
1190    if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) {
1191        rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
1192                                      DixGetAttrAccess);
1193        return rc == BadValue;
1194    }
1195    return FALSE;
1196}
1197
1198int
1199dixLookupResourceByType(void **result, XID id, RESTYPE rtype,
1200                        ClientPtr client, Mask mode)
1201{
1202    int cid = CLIENT_ID(id);
1203    ResourcePtr res = NULL;
1204
1205    *result = NULL;
1206    if ((rtype & TypeMask) > lastResourceType)
1207        return BadImplementation;
1208
1209    if ((cid < LimitClients) && clientTable[cid].buckets) {
1210        res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
1211
1212        for (; res; res = res->next)
1213            if (res->id == id && res->type == rtype)
1214                break;
1215    }
1216    if (client) {
1217        client->errorValue = id;
1218    }
1219    if (!res)
1220        return resourceTypes[rtype & TypeMask].errorValue;
1221
1222    if (client) {
1223        cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
1224                       res->value, RT_NONE, NULL, mode);
1225        if (cid == BadValue)
1226            return resourceTypes[rtype & TypeMask].errorValue;
1227        if (cid != Success)
1228            return cid;
1229    }
1230
1231    *result = res->value;
1232    return Success;
1233}
1234
1235int
1236dixLookupResourceByClass(void **result, XID id, RESTYPE rclass,
1237                         ClientPtr client, Mask mode)
1238{
1239    int cid = CLIENT_ID(id);
1240    ResourcePtr res = NULL;
1241
1242    *result = NULL;
1243
1244    if ((cid < LimitClients) && clientTable[cid].buckets) {
1245        res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
1246
1247        for (; res; res = res->next)
1248            if (res->id == id && (res->type & rclass))
1249                break;
1250    }
1251    if (client) {
1252        client->errorValue = id;
1253    }
1254    if (!res)
1255        return BadValue;
1256
1257    if (client) {
1258        cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
1259                       res->value, RT_NONE, NULL, mode);
1260        if (cid != Success)
1261            return cid;
1262    }
1263
1264    *result = res->value;
1265    return Success;
1266}
1267