xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

resource.c (39643B)


      1 /************************************************************
      2 
      3 Copyright 1987, 1998  The Open Group
      4 
      5 Permission to use, copy, modify, distribute, and sell this software and its
      6 documentation for any purpose is hereby granted without fee, provided that
      7 the above copyright notice appear in all copies and that both that
      8 copyright notice and this permission notice appear in supporting
      9 documentation.
     10 
     11 The above copyright notice and this permission notice shall be included in
     12 all copies or substantial portions of the Software.
     13 
     14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
     17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     20 
     21 Except as contained in this notice, the name of The Open Group shall not be
     22 used in advertising or otherwise to promote the sale, use or other dealings
     23 in this Software without prior written authorization from The Open Group.
     24 
     25 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
     26 
     27                         All Rights Reserved
     28 
     29 Permission to use, copy, modify, and distribute this software and its
     30 documentation for any purpose and without fee is hereby granted,
     31 provided that the above copyright notice appear in all copies and that
     32 both that copyright notice and this permission notice appear in
     33 supporting documentation, and that the name of Digital not be
     34 used in advertising or publicity pertaining to distribution of the
     35 software without specific, written prior permission.
     36 
     37 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
     38 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
     39 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
     40 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
     41 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
     42 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
     43 SOFTWARE.
     44 
     45 ********************************************************/
     46 /* The panoramix components contained the following notice */
     47 /*****************************************************************
     48 
     49 Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts.
     50 
     51 Permission is hereby granted, free of charge, to any person obtaining a copy
     52 of this software and associated documentation files (the "Software"), to deal
     53 in the Software without restriction, including without limitation the rights
     54 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     55 copies of the Software.
     56 
     57 The above copyright notice and this permission notice shall be included in
     58 all copies or substantial portions of the Software.
     59 
     60 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     61 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     62 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     63 DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING,
     64 BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY,
     65 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
     66 IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     67 
     68 Except as contained in this notice, the name of Digital Equipment Corporation
     69 shall not be used in advertising or otherwise to promote the sale, use or other
     70 dealings in this Software without prior written authorization from Digital
     71 Equipment 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 
    152 static 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 
    161 typedef struct _Resource {
    162     struct _Resource *next;
    163     XID id;
    164     RESTYPE type;
    165     void *value;
    166 } ResourceRec, *ResourcePtr;
    167 
    168 typedef 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 
    177 RESTYPE lastResourceType;
    178 static RESTYPE lastResourceClass;
    179 RESTYPE TypeMask;
    180 
    181 struct 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  */
    202 static void
    203 GetDefaultBytes(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  */
    223 static void
    224 DefaultFindSubRes(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  */
    237 static unsigned long
    238 GetDrawableBytes(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  */
    267 static void
    268 GetPixmapBytes(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  */
    296 static void
    297 GetWindowBytes(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  */
    338 static void
    339 FindWindowSubRes(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  */
    369 static void
    370 GetGcBytes(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  */
    410 static void
    411 FindGCSubRes(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 
    429 static struct ResourceType *resourceTypes;
    430 
    431 static 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 
    494 CallbackListPtr ResourceStateCallback;
    495 
    496 static _X_INLINE void
    497 CallResourceStateCallback(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 
    505 RESTYPE
    506 CreateNewResourceType(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  */
    542 SizeType
    543 GetResourceTypeSizeFunc(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  */
    559 void
    560 SetResourceTypeSizeFunc(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  */
    577 void
    578 SetResourceTypeFindSubResFunc(RESTYPE type, FindTypeSubResources findFunc)
    579 {
    580     resourceTypes[type & TypeMask].findSubResFunc = findFunc;
    581 }
    582 
    583 void
    584 SetResourceTypeErrorValue(RESTYPE type, int errorValue)
    585 {
    586     resourceTypes[type & TypeMask].errorValue = errorValue;
    587 }
    588 
    589 RESTYPE
    590 CreateNewResourceClass(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 
    601 static ClientResourceRec clientTable[MAXCLIENTS];
    602 
    603 static unsigned int
    604 ilog2(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 
    620 unsigned int
    621 ResourceClientBits(void)
    622 {
    623     static unsigned int cached = 0;
    624 
    625     if (cached == 0)
    626       cached = ilog2(LimitClients);
    627 
    628     return cached;
    629 }
    630 
    631 /*****************
    632  * InitClientResources
    633  *    When a new client is created, call this to allocate space
    634  *    in resource table
    635  *****************/
    636 
    637 Bool
    638 InitClientResources(ClientPtr client)
    639 {
    640     int i, j;
    641 
    642     if (client == serverClient) {
    643         lastResourceType = RT_LASTPREDEF;
    644         lastResourceClass = RC_LASTPREDEF;
    645         TypeMask = RC_LASTPREDEF - 1;
    646         free(resourceTypes);
    647         resourceTypes = malloc(sizeof(predefTypes));
    648         if (!resourceTypes)
    649             return FALSE;
    650         memcpy(resourceTypes, predefTypes, sizeof(predefTypes));
    651     }
    652     clientTable[i = client->index].resources =
    653         malloc(INITBUCKETS * sizeof(ResourcePtr));
    654     if (!clientTable[i].resources)
    655         return FALSE;
    656     clientTable[i].buckets = INITBUCKETS;
    657     clientTable[i].elements = 0;
    658     clientTable[i].hashsize = INITHASHSIZE;
    659     /* Many IDs allocated from the server client are visible to clients,
    660      * so we don't use the SERVER_BIT for them, but we have to start
    661      * past the magic value constants used in the protocol.  For normal
    662      * clients, we can start from zero, with SERVER_BIT set.
    663      */
    664     clientTable[i].fakeID = client->clientAsMask |
    665         (client->index ? SERVER_BIT : SERVER_MINID);
    666     clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1;
    667     for (j = 0; j < INITBUCKETS; j++) {
    668         clientTable[i].resources[j] = NULL;
    669     }
    670     return TRUE;
    671 }
    672 
    673 int
    674 HashResourceID(XID id, unsigned int numBits)
    675 {
    676     static XID mask;
    677 
    678     if (!mask)
    679         mask = RESOURCE_ID_MASK;
    680     id &= mask;
    681     if (numBits < 9)
    682         return (id ^ (id >> numBits) ^ (id >> (numBits<<1))) & ~((~0U) << numBits);
    683     return (id ^ (id >> numBits)) & ~((~0) << numBits);
    684 }
    685 
    686 static XID
    687 AvailableID(int client, XID id, XID maxid, XID goodid)
    688 {
    689     ResourcePtr res;
    690 
    691     if ((goodid >= id) && (goodid <= maxid))
    692         return goodid;
    693     for (; id <= maxid; id++) {
    694         res = clientTable[client].resources[HashResourceID(id, clientTable[client].hashsize)];
    695         while (res && (res->id != id))
    696             res = res->next;
    697         if (!res)
    698             return id;
    699     }
    700     return 0;
    701 }
    702 
    703 void
    704 GetXIDRange(int client, Bool server, XID *minp, XID *maxp)
    705 {
    706     XID id, maxid;
    707     ResourcePtr *resp;
    708     ResourcePtr res;
    709     int i;
    710     XID goodid;
    711 
    712     id = (Mask) client << CLIENTOFFSET;
    713     if (server)
    714         id |= client ? SERVER_BIT : SERVER_MINID;
    715     maxid = id | RESOURCE_ID_MASK;
    716     goodid = 0;
    717     for (resp = clientTable[client].resources, i = clientTable[client].buckets;
    718          --i >= 0;) {
    719         for (res = *resp++; res; res = res->next) {
    720             if ((res->id < id) || (res->id > maxid))
    721                 continue;
    722             if (((res->id - id) >= (maxid - res->id)) ?
    723                 (goodid = AvailableID(client, id, res->id - 1, goodid)) :
    724                 !(goodid = AvailableID(client, res->id + 1, maxid, goodid)))
    725                 maxid = res->id - 1;
    726             else
    727                 id = res->id + 1;
    728         }
    729     }
    730     if (id > maxid)
    731         id = maxid = 0;
    732     *minp = id;
    733     *maxp = maxid;
    734 }
    735 
    736 /**
    737  *  GetXIDList is called by the XC-MISC extension's MiscGetXIDList function.
    738  *  This function tries to find count unused XIDs for the given client.  It
    739  *  puts the IDs in the array pids and returns the number found, which should
    740  *  almost always be the number requested.
    741  *
    742  *  The circumstances that lead to a call to this function are very rare.
    743  *  Xlib must run out of IDs while trying to generate a request that wants
    744  *  multiple ID's, like the Multi-buffering CreateImageBuffers request.
    745  *
    746  *  No rocket science in the implementation; just iterate over all
    747  *  possible IDs for the given client and pick the first count IDs
    748  *  that aren't in use.  A more efficient algorithm could probably be
    749  *  invented, but this will be used so rarely that this should suffice.
    750  */
    751 
    752 unsigned int
    753 GetXIDList(ClientPtr pClient, unsigned count, XID *pids)
    754 {
    755     unsigned int found = 0;
    756     XID rc, id = pClient->clientAsMask;
    757     XID maxid;
    758     void *val;
    759 
    760     maxid = id | RESOURCE_ID_MASK;
    761     while ((found < count) && (id <= maxid)) {
    762         rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
    763                                       DixGetAttrAccess);
    764         if (rc == BadValue) {
    765             pids[found++] = id;
    766         }
    767         id++;
    768     }
    769     return found;
    770 }
    771 
    772 /*
    773  * Return the next usable fake client ID.
    774  *
    775  * Normally this is just the next one in line, but if we've used the last
    776  * in the range, we need to find a new range of safe IDs to avoid
    777  * over-running another client.
    778  */
    779 
    780 XID
    781 FakeClientID(int client)
    782 {
    783     XID id, maxid;
    784 
    785     id = clientTable[client].fakeID++;
    786     if (id != clientTable[client].endFakeID)
    787         return id;
    788     GetXIDRange(client, TRUE, &id, &maxid);
    789     if (!id) {
    790         if (!client)
    791             FatalError("FakeClientID: server internal ids exhausted\n");
    792         MarkClientException(clients[client]);
    793         id = ((Mask) client << CLIENTOFFSET) | (SERVER_BIT * 3);
    794         maxid = id | RESOURCE_ID_MASK;
    795     }
    796     clientTable[client].fakeID = id + 1;
    797     clientTable[client].endFakeID = maxid + 1;
    798     return id;
    799 }
    800 
    801 Bool
    802 AddResource(XID id, RESTYPE type, void *value)
    803 {
    804     int client;
    805     ClientResourceRec *rrec;
    806     ResourcePtr res, *head;
    807 
    808 #ifdef XSERVER_DTRACE
    809     XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type));
    810 #endif
    811     client = CLIENT_ID(id);
    812     rrec = &clientTable[client];
    813     if (!rrec->buckets) {
    814         ErrorF("[dix] AddResource(%lx, %x, %lx), client=%d \n",
    815                (unsigned long) id, type, (unsigned long) value, client);
    816         FatalError("client not in use\n");
    817     }
    818     if ((rrec->elements >= 4 * rrec->buckets) && (rrec->hashsize < MAXHASHSIZE))
    819         RebuildTable(client);
    820     head = &rrec->resources[HashResourceID(id, clientTable[client].hashsize)];
    821     res = malloc(sizeof(ResourceRec));
    822     if (!res) {
    823         (*resourceTypes[type & TypeMask].deleteFunc) (value, id);
    824         return FALSE;
    825     }
    826     res->next = *head;
    827     res->id = id;
    828     res->type = type;
    829     res->value = value;
    830     *head = res;
    831     rrec->elements++;
    832     CallResourceStateCallback(ResourceStateAdding, res);
    833     return TRUE;
    834 }
    835 
    836 static void
    837 RebuildTable(int client)
    838 {
    839     int j;
    840     ResourcePtr res, next;
    841     ResourcePtr **tails, *resources;
    842     ResourcePtr **tptr, *rptr;
    843 
    844     /*
    845      * For now, preserve insertion order, since some ddx layers depend
    846      * on resources being free in the opposite order they are added.
    847      */
    848 
    849     j = 2 * clientTable[client].buckets;
    850     tails =  xallocarray(j, sizeof(ResourcePtr *));
    851     if (!tails)
    852         return;
    853     resources =  xallocarray(j, sizeof(ResourcePtr));
    854     if (!resources) {
    855         free(tails);
    856         return;
    857     }
    858     for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) {
    859         *rptr = NULL;
    860         *tptr = rptr;
    861     }
    862     clientTable[client].hashsize++;
    863     for (j = clientTable[client].buckets,
    864          rptr = clientTable[client].resources; --j >= 0; rptr++) {
    865         for (res = *rptr; res; res = next) {
    866             next = res->next;
    867             res->next = NULL;
    868             tptr = &tails[HashResourceID(res->id, clientTable[client].hashsize)];
    869             **tptr = res;
    870             *tptr = &res->next;
    871         }
    872     }
    873     free(tails);
    874     clientTable[client].buckets *= 2;
    875     free(clientTable[client].resources);
    876     clientTable[client].resources = resources;
    877 }
    878 
    879 static void
    880 doFreeResource(ResourcePtr res, Bool skip)
    881 {
    882     CallResourceStateCallback(ResourceStateFreeing, res);
    883 
    884     if (!skip)
    885         resourceTypes[res->type & TypeMask].deleteFunc(res->value, res->id);
    886 
    887     free(res);
    888 }
    889 
    890 void
    891 FreeResource(XID id, RESTYPE skipDeleteFuncType)
    892 {
    893     int cid;
    894     ResourcePtr res;
    895     ResourcePtr *prev, *head;
    896     int *eltptr;
    897     int elements;
    898 
    899     if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
    900         head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
    901         eltptr = &clientTable[cid].elements;
    902 
    903         prev = head;
    904         while ((res = *prev)) {
    905             if (res->id == id) {
    906                 RESTYPE rtype = res->type;
    907 
    908 #ifdef XSERVER_DTRACE
    909                 XSERVER_RESOURCE_FREE(res->id, res->type,
    910                                       res->value, TypeNameString(res->type));
    911 #endif
    912                 *prev = res->next;
    913                 elements = --*eltptr;
    914 
    915                 doFreeResource(res, rtype == skipDeleteFuncType);
    916 
    917                 if (*eltptr != elements)
    918                     prev = head;        /* prev may no longer be valid */
    919             }
    920             else
    921                 prev = &res->next;
    922         }
    923     }
    924 }
    925 
    926 void
    927 FreeResourceByType(XID id, RESTYPE type, Bool skipFree)
    928 {
    929     int cid;
    930     ResourcePtr res;
    931     ResourcePtr *prev, *head;
    932 
    933     if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
    934         head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
    935 
    936         prev = head;
    937         while ((res = *prev)) {
    938             if (res->id == id && res->type == type) {
    939 #ifdef XSERVER_DTRACE
    940                 XSERVER_RESOURCE_FREE(res->id, res->type,
    941                                       res->value, TypeNameString(res->type));
    942 #endif
    943                 *prev = res->next;
    944                 clientTable[cid].elements--;
    945 
    946                 doFreeResource(res, skipFree);
    947 
    948                 break;
    949             }
    950             else
    951                 prev = &res->next;
    952         }
    953     }
    954 }
    955 
    956 /*
    957  * Change the value associated with a resource id.  Caller
    958  * is responsible for "doing the right thing" with the old
    959  * data
    960  */
    961 
    962 Bool
    963 ChangeResourceValue(XID id, RESTYPE rtype, void *value)
    964 {
    965     int cid;
    966     ResourcePtr res;
    967 
    968     if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) {
    969         res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
    970 
    971         for (; res; res = res->next)
    972             if ((res->id == id) && (res->type == rtype)) {
    973                 res->value = value;
    974                 return TRUE;
    975             }
    976     }
    977     return FALSE;
    978 }
    979 
    980 /* Note: if func adds or deletes resources, then func can get called
    981  * more than once for some resources.  If func adds new resources,
    982  * func might or might not get called for them.  func cannot both
    983  * add and delete an equal number of resources!
    984  */
    985 
    986 void
    987 FindClientResourcesByType(ClientPtr client,
    988                           RESTYPE type, FindResType func, void *cdata)
    989 {
    990     ResourcePtr *resources;
    991     ResourcePtr this, next;
    992     int i, elements;
    993     int *eltptr;
    994 
    995     if (!client)
    996         client = serverClient;
    997 
    998     resources = clientTable[client->index].resources;
    999     eltptr = &clientTable[client->index].elements;
   1000     for (i = 0; i < clientTable[client->index].buckets; i++) {
   1001         for (this = resources[i]; this; this = next) {
   1002             next = this->next;
   1003             if (!type || this->type == type) {
   1004                 elements = *eltptr;
   1005                 (*func) (this->value, this->id, cdata);
   1006                 if (*eltptr != elements)
   1007                     next = resources[i];        /* start over */
   1008             }
   1009         }
   1010     }
   1011 }
   1012 
   1013 void FindSubResources(void *resource,
   1014                       RESTYPE    type,
   1015                       FindAllRes func,
   1016                       void *cdata)
   1017 {
   1018     struct ResourceType rtype = resourceTypes[type & TypeMask];
   1019     rtype.findSubResFunc(resource, func, cdata);
   1020 }
   1021 
   1022 void
   1023 FindAllClientResources(ClientPtr client, FindAllRes func, void *cdata)
   1024 {
   1025     ResourcePtr *resources;
   1026     ResourcePtr this, next;
   1027     int i, elements;
   1028     int *eltptr;
   1029 
   1030     if (!client)
   1031         client = serverClient;
   1032 
   1033     resources = clientTable[client->index].resources;
   1034     eltptr = &clientTable[client->index].elements;
   1035     for (i = 0; i < clientTable[client->index].buckets; i++) {
   1036         for (this = resources[i]; this; this = next) {
   1037             next = this->next;
   1038             elements = *eltptr;
   1039             (*func) (this->value, this->id, this->type, cdata);
   1040             if (*eltptr != elements)
   1041                 next = resources[i];    /* start over */
   1042         }
   1043     }
   1044 }
   1045 
   1046 void *
   1047 LookupClientResourceComplex(ClientPtr client,
   1048                             RESTYPE type,
   1049                             FindComplexResType func, void *cdata)
   1050 {
   1051     ResourcePtr *resources;
   1052     ResourcePtr this, next;
   1053     void *value;
   1054     int i;
   1055 
   1056     if (!client)
   1057         client = serverClient;
   1058 
   1059     resources = clientTable[client->index].resources;
   1060     for (i = 0; i < clientTable[client->index].buckets; i++) {
   1061         for (this = resources[i]; this; this = next) {
   1062             next = this->next;
   1063             if (!type || this->type == type) {
   1064                 /* workaround func freeing the type as DRI1 does */
   1065                 value = this->value;
   1066                 if ((*func) (value, this->id, cdata))
   1067                     return value;
   1068             }
   1069         }
   1070     }
   1071     return NULL;
   1072 }
   1073 
   1074 void
   1075 FreeClientNeverRetainResources(ClientPtr client)
   1076 {
   1077     ResourcePtr *resources;
   1078     ResourcePtr this;
   1079     ResourcePtr *prev;
   1080     int j, elements;
   1081     int *eltptr;
   1082 
   1083     if (!client)
   1084         return;
   1085 
   1086     resources = clientTable[client->index].resources;
   1087     eltptr = &clientTable[client->index].elements;
   1088     for (j = 0; j < clientTable[client->index].buckets; j++) {
   1089         prev = &resources[j];
   1090         while ((this = *prev)) {
   1091             RESTYPE rtype = this->type;
   1092 
   1093             if (rtype & RC_NEVERRETAIN) {
   1094 #ifdef XSERVER_DTRACE
   1095                 XSERVER_RESOURCE_FREE(this->id, this->type,
   1096                                       this->value, TypeNameString(this->type));
   1097 #endif
   1098                 *prev = this->next;
   1099                 clientTable[client->index].elements--;
   1100                 elements = *eltptr;
   1101 
   1102                 doFreeResource(this, FALSE);
   1103 
   1104                 if (*eltptr != elements)
   1105                     prev = &resources[j];       /* prev may no longer be valid */
   1106             }
   1107             else
   1108                 prev = &this->next;
   1109         }
   1110     }
   1111 }
   1112 
   1113 void
   1114 FreeClientResources(ClientPtr client)
   1115 {
   1116     ResourcePtr *resources;
   1117     ResourcePtr this;
   1118     int j;
   1119 
   1120     /* This routine shouldn't be called with a null client, but just in
   1121        case ... */
   1122 
   1123     if (!client)
   1124         return;
   1125 
   1126     HandleSaveSet(client);
   1127 
   1128     resources = clientTable[client->index].resources;
   1129     for (j = 0; j < clientTable[client->index].buckets; j++) {
   1130         /* It may seem silly to update the head of this resource list as
   1131            we delete the members, since the entire list will be deleted any way,
   1132            but there are some resource deletion functions "FreeClientPixels" for
   1133            one which do a LookupID on another resource id (a Colormap id in this
   1134            case), so the resource list must be kept valid up to the point that
   1135            it is deleted, so every time we delete a resource, we must update the
   1136            head, just like in FreeResource. I hope that this doesn't slow down
   1137            mass deletion appreciably. PRH */
   1138 
   1139         ResourcePtr *head;
   1140 
   1141         head = &resources[j];
   1142 
   1143         for (this = *head; this; this = *head) {
   1144 #ifdef XSERVER_DTRACE
   1145             XSERVER_RESOURCE_FREE(this->id, this->type,
   1146                                   this->value, TypeNameString(this->type));
   1147 #endif
   1148             *head = this->next;
   1149             clientTable[client->index].elements--;
   1150 
   1151             doFreeResource(this, FALSE);
   1152         }
   1153     }
   1154     free(clientTable[client->index].resources);
   1155     clientTable[client->index].resources = NULL;
   1156     clientTable[client->index].buckets = 0;
   1157 }
   1158 
   1159 void
   1160 FreeAllResources(void)
   1161 {
   1162     int i;
   1163 
   1164     for (i = currentMaxClients; --i >= 0;) {
   1165         if (clientTable[i].buckets)
   1166             FreeClientResources(clients[i]);
   1167     }
   1168 }
   1169 
   1170 Bool
   1171 LegalNewID(XID id, ClientPtr client)
   1172 {
   1173     void *val;
   1174     int rc;
   1175 
   1176 #ifdef PANORAMIX
   1177     XID minid, maxid;
   1178 
   1179     if (!noPanoramiXExtension) {
   1180         minid = client->clientAsMask | (client->index ?
   1181                                         SERVER_BIT : SERVER_MINID);
   1182         maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1;
   1183         if ((id >= minid) && (id <= maxid))
   1184             return TRUE;
   1185     }
   1186 #endif                          /* PANORAMIX */
   1187     if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) {
   1188         rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient,
   1189                                       DixGetAttrAccess);
   1190         return rc == BadValue;
   1191     }
   1192     return FALSE;
   1193 }
   1194 
   1195 int
   1196 dixLookupResourceByType(void **result, XID id, RESTYPE rtype,
   1197                         ClientPtr client, Mask mode)
   1198 {
   1199     int cid = CLIENT_ID(id);
   1200     ResourcePtr res = NULL;
   1201 
   1202     *result = NULL;
   1203     if ((rtype & TypeMask) > lastResourceType)
   1204         return BadImplementation;
   1205 
   1206     if ((cid < LimitClients) && clientTable[cid].buckets) {
   1207         res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
   1208 
   1209         for (; res; res = res->next)
   1210             if (res->id == id && res->type == rtype)
   1211                 break;
   1212     }
   1213     if (client) {
   1214         client->errorValue = id;
   1215     }
   1216     if (!res)
   1217         return resourceTypes[rtype & TypeMask].errorValue;
   1218 
   1219     if (client) {
   1220         cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
   1221                        res->value, RT_NONE, NULL, mode);
   1222         if (cid == BadValue)
   1223             return resourceTypes[rtype & TypeMask].errorValue;
   1224         if (cid != Success)
   1225             return cid;
   1226     }
   1227 
   1228     *result = res->value;
   1229     return Success;
   1230 }
   1231 
   1232 int
   1233 dixLookupResourceByClass(void **result, XID id, RESTYPE rclass,
   1234                          ClientPtr client, Mask mode)
   1235 {
   1236     int cid = CLIENT_ID(id);
   1237     ResourcePtr res = NULL;
   1238 
   1239     *result = NULL;
   1240 
   1241     if ((cid < LimitClients) && clientTable[cid].buckets) {
   1242         res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)];
   1243 
   1244         for (; res; res = res->next)
   1245             if (res->id == id && (res->type & rclass))
   1246                 break;
   1247     }
   1248     if (client) {
   1249         client->errorValue = id;
   1250     }
   1251     if (!res)
   1252         return BadValue;
   1253 
   1254     if (client) {
   1255         cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type,
   1256                        res->value, RT_NONE, NULL, mode);
   1257         if (cid != Success)
   1258             return cid;
   1259     }
   1260 
   1261     *result = res->value;
   1262     return Success;
   1263 }