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