resource.c revision 35c4bbdf
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 11 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 return (ilog2(LimitClients)); 624} 625 626/***************** 627 * InitClientResources 628 * When a new client is created, call this to allocate space 629 * in resource table 630 *****************/ 631 632Bool 633InitClientResources(ClientPtr client) 634{ 635 int i, j; 636 637 if (client == serverClient) { 638 lastResourceType = RT_LASTPREDEF; 639 lastResourceClass = RC_LASTPREDEF; 640 TypeMask = RC_LASTPREDEF - 1; 641 free(resourceTypes); 642 resourceTypes = malloc(sizeof(predefTypes)); 643 if (!resourceTypes) 644 return FALSE; 645 memcpy(resourceTypes, predefTypes, sizeof(predefTypes)); 646 } 647 clientTable[i = client->index].resources = 648 malloc(INITBUCKETS * sizeof(ResourcePtr)); 649 if (!clientTable[i].resources) 650 return FALSE; 651 clientTable[i].buckets = INITBUCKETS; 652 clientTable[i].elements = 0; 653 clientTable[i].hashsize = INITHASHSIZE; 654 /* Many IDs allocated from the server client are visible to clients, 655 * so we don't use the SERVER_BIT for them, but we have to start 656 * past the magic value constants used in the protocol. For normal 657 * clients, we can start from zero, with SERVER_BIT set. 658 */ 659 clientTable[i].fakeID = client->clientAsMask | 660 (client->index ? SERVER_BIT : SERVER_MINID); 661 clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1; 662 for (j = 0; j < INITBUCKETS; j++) { 663 clientTable[i].resources[j] = NULL; 664 } 665 return TRUE; 666} 667 668int 669HashResourceID(XID id, int numBits) 670{ 671 id &= RESOURCE_ID_MASK; 672 switch (numBits) 673 { 674 case 6: 675 return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12)))); 676 case 7: 677 return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13)))); 678 case 8: 679 return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16)))); 680 case 9: 681 return ((int)(0x1FF & (id ^ (id>>9)))); 682 case 10: 683 return ((int)(0x3FF & (id ^ (id>>10)))); 684 case 11: 685 return ((int)(0x7FF & (id ^ (id>>11)))); 686 } 687 if (numBits >= 11) 688 return ((int)(0x7FF & (id ^ (id>>11)))); 689 else 690 { 691 assert(numBits >= 0); 692 return id & ~((~0) << numBits); 693 } 694} 695 696static XID 697AvailableID(int client, XID id, XID maxid, XID goodid) 698{ 699 ResourcePtr res; 700 701 if ((goodid >= id) && (goodid <= maxid)) 702 return goodid; 703 for (; id <= maxid; id++) { 704 res = clientTable[client].resources[HashResourceID(id, clientTable[client].hashsize)]; 705 while (res && (res->id != id)) 706 res = res->next; 707 if (!res) 708 return id; 709 } 710 return 0; 711} 712 713void 714GetXIDRange(int client, Bool server, XID *minp, XID *maxp) 715{ 716 XID id, maxid; 717 ResourcePtr *resp; 718 ResourcePtr res; 719 int i; 720 XID goodid; 721 722 id = (Mask) client << CLIENTOFFSET; 723 if (server) 724 id |= client ? SERVER_BIT : SERVER_MINID; 725 maxid = id | RESOURCE_ID_MASK; 726 goodid = 0; 727 for (resp = clientTable[client].resources, i = clientTable[client].buckets; 728 --i >= 0;) { 729 for (res = *resp++; res; res = res->next) { 730 if ((res->id < id) || (res->id > maxid)) 731 continue; 732 if (((res->id - id) >= (maxid - res->id)) ? 733 (goodid = AvailableID(client, id, res->id - 1, goodid)) : 734 !(goodid = AvailableID(client, res->id + 1, maxid, goodid))) 735 maxid = res->id - 1; 736 else 737 id = res->id + 1; 738 } 739 } 740 if (id > maxid) 741 id = maxid = 0; 742 *minp = id; 743 *maxp = maxid; 744} 745 746/** 747 * GetXIDList is called by the XC-MISC extension's MiscGetXIDList function. 748 * This function tries to find count unused XIDs for the given client. It 749 * puts the IDs in the array pids and returns the number found, which should 750 * almost always be the number requested. 751 * 752 * The circumstances that lead to a call to this function are very rare. 753 * Xlib must run out of IDs while trying to generate a request that wants 754 * multiple ID's, like the Multi-buffering CreateImageBuffers request. 755 * 756 * No rocket science in the implementation; just iterate over all 757 * possible IDs for the given client and pick the first count IDs 758 * that aren't in use. A more efficient algorithm could probably be 759 * invented, but this will be used so rarely that this should suffice. 760 */ 761 762unsigned int 763GetXIDList(ClientPtr pClient, unsigned count, XID *pids) 764{ 765 unsigned int found = 0; 766 XID rc, id = pClient->clientAsMask; 767 XID maxid; 768 void *val; 769 770 maxid = id | RESOURCE_ID_MASK; 771 while ((found < count) && (id <= maxid)) { 772 rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, 773 DixGetAttrAccess); 774 if (rc == BadValue) { 775 pids[found++] = id; 776 } 777 id++; 778 } 779 return found; 780} 781 782/* 783 * Return the next usable fake client ID. 784 * 785 * Normally this is just the next one in line, but if we've used the last 786 * in the range, we need to find a new range of safe IDs to avoid 787 * over-running another client. 788 */ 789 790XID 791FakeClientID(int client) 792{ 793 XID id, maxid; 794 795 id = clientTable[client].fakeID++; 796 if (id != clientTable[client].endFakeID) 797 return id; 798 GetXIDRange(client, TRUE, &id, &maxid); 799 if (!id) { 800 if (!client) 801 FatalError("FakeClientID: server internal ids exhausted\n"); 802 MarkClientException(clients[client]); 803 id = ((Mask) client << CLIENTOFFSET) | (SERVER_BIT * 3); 804 maxid = id | RESOURCE_ID_MASK; 805 } 806 clientTable[client].fakeID = id + 1; 807 clientTable[client].endFakeID = maxid + 1; 808 return id; 809} 810 811Bool 812AddResource(XID id, RESTYPE type, void *value) 813{ 814 int client; 815 ClientResourceRec *rrec; 816 ResourcePtr res, *head; 817 818#ifdef XSERVER_DTRACE 819 XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type)); 820#endif 821 client = CLIENT_ID(id); 822 rrec = &clientTable[client]; 823 if (!rrec->buckets) { 824 ErrorF("[dix] AddResource(%lx, %x, %lx), client=%d \n", 825 (unsigned long) id, type, (unsigned long) value, client); 826 FatalError("client not in use\n"); 827 } 828 if ((rrec->elements >= 4 * rrec->buckets) && (rrec->hashsize < MAXHASHSIZE)) 829 RebuildTable(client); 830 head = &rrec->resources[HashResourceID(id, clientTable[client].hashsize)]; 831 res = malloc(sizeof(ResourceRec)); 832 if (!res) { 833 (*resourceTypes[type & TypeMask].deleteFunc) (value, id); 834 return FALSE; 835 } 836 res->next = *head; 837 res->id = id; 838 res->type = type; 839 res->value = value; 840 *head = res; 841 rrec->elements++; 842 CallResourceStateCallback(ResourceStateAdding, res); 843 return TRUE; 844} 845 846static void 847RebuildTable(int client) 848{ 849 int j; 850 ResourcePtr res, next; 851 ResourcePtr **tails, *resources; 852 ResourcePtr **tptr, *rptr; 853 854 /* 855 * For now, preserve insertion order, since some ddx layers depend 856 * on resources being free in the opposite order they are added. 857 */ 858 859 j = 2 * clientTable[client].buckets; 860 tails = xallocarray(j, sizeof(ResourcePtr *)); 861 if (!tails) 862 return; 863 resources = xallocarray(j, sizeof(ResourcePtr)); 864 if (!resources) { 865 free(tails); 866 return; 867 } 868 for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) { 869 *rptr = NULL; 870 *tptr = rptr; 871 } 872 clientTable[client].hashsize++; 873 for (j = clientTable[client].buckets, 874 rptr = clientTable[client].resources; --j >= 0; rptr++) { 875 for (res = *rptr; res; res = next) { 876 next = res->next; 877 res->next = NULL; 878 tptr = &tails[HashResourceID(res->id, clientTable[client].hashsize)]; 879 **tptr = res; 880 *tptr = &res->next; 881 } 882 } 883 free(tails); 884 clientTable[client].buckets *= 2; 885 free(clientTable[client].resources); 886 clientTable[client].resources = resources; 887} 888 889static void 890doFreeResource(ResourcePtr res, Bool skip) 891{ 892 CallResourceStateCallback(ResourceStateFreeing, res); 893 894 if (!skip) 895 resourceTypes[res->type & TypeMask].deleteFunc(res->value, res->id); 896 897 free(res); 898} 899 900void 901FreeResource(XID id, RESTYPE skipDeleteFuncType) 902{ 903 int cid; 904 ResourcePtr res; 905 ResourcePtr *prev, *head; 906 int *eltptr; 907 int elements; 908 909 if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) { 910 head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; 911 eltptr = &clientTable[cid].elements; 912 913 prev = head; 914 while ((res = *prev)) { 915 if (res->id == id) { 916 RESTYPE rtype = res->type; 917 918#ifdef XSERVER_DTRACE 919 XSERVER_RESOURCE_FREE(res->id, res->type, 920 res->value, TypeNameString(res->type)); 921#endif 922 *prev = res->next; 923 elements = --*eltptr; 924 925 doFreeResource(res, rtype == skipDeleteFuncType); 926 927 if (*eltptr != elements) 928 prev = head; /* prev may no longer be valid */ 929 } 930 else 931 prev = &res->next; 932 } 933 } 934} 935 936void 937FreeResourceByType(XID id, RESTYPE type, Bool skipFree) 938{ 939 int cid; 940 ResourcePtr res; 941 ResourcePtr *prev, *head; 942 943 if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) { 944 head = &clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; 945 946 prev = head; 947 while ((res = *prev)) { 948 if (res->id == id && res->type == type) { 949#ifdef XSERVER_DTRACE 950 XSERVER_RESOURCE_FREE(res->id, res->type, 951 res->value, TypeNameString(res->type)); 952#endif 953 *prev = res->next; 954 clientTable[cid].elements--; 955 956 doFreeResource(res, skipFree); 957 958 break; 959 } 960 else 961 prev = &res->next; 962 } 963 } 964} 965 966/* 967 * Change the value associated with a resource id. Caller 968 * is responsible for "doing the right thing" with the old 969 * data 970 */ 971 972Bool 973ChangeResourceValue(XID id, RESTYPE rtype, void *value) 974{ 975 int cid; 976 ResourcePtr res; 977 978 if (((cid = CLIENT_ID(id)) < LimitClients) && clientTable[cid].buckets) { 979 res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; 980 981 for (; res; res = res->next) 982 if ((res->id == id) && (res->type == rtype)) { 983 res->value = value; 984 return TRUE; 985 } 986 } 987 return FALSE; 988} 989 990/* Note: if func adds or deletes resources, then func can get called 991 * more than once for some resources. If func adds new resources, 992 * func might or might not get called for them. func cannot both 993 * add and delete an equal number of resources! 994 */ 995 996void 997FindClientResourcesByType(ClientPtr client, 998 RESTYPE type, FindResType func, void *cdata) 999{ 1000 ResourcePtr *resources; 1001 ResourcePtr this, next; 1002 int i, elements; 1003 int *eltptr; 1004 1005 if (!client) 1006 client = serverClient; 1007 1008 resources = clientTable[client->index].resources; 1009 eltptr = &clientTable[client->index].elements; 1010 for (i = 0; i < clientTable[client->index].buckets; i++) { 1011 for (this = resources[i]; this; this = next) { 1012 next = this->next; 1013 if (!type || this->type == type) { 1014 elements = *eltptr; 1015 (*func) (this->value, this->id, cdata); 1016 if (*eltptr != elements) 1017 next = resources[i]; /* start over */ 1018 } 1019 } 1020 } 1021} 1022 1023void FindSubResources(void *resource, 1024 RESTYPE type, 1025 FindAllRes func, 1026 void *cdata) 1027{ 1028 struct ResourceType rtype = resourceTypes[type & TypeMask]; 1029 rtype.findSubResFunc(resource, func, cdata); 1030} 1031 1032void 1033FindAllClientResources(ClientPtr client, FindAllRes func, void *cdata) 1034{ 1035 ResourcePtr *resources; 1036 ResourcePtr this, next; 1037 int i, elements; 1038 int *eltptr; 1039 1040 if (!client) 1041 client = serverClient; 1042 1043 resources = clientTable[client->index].resources; 1044 eltptr = &clientTable[client->index].elements; 1045 for (i = 0; i < clientTable[client->index].buckets; i++) { 1046 for (this = resources[i]; this; this = next) { 1047 next = this->next; 1048 elements = *eltptr; 1049 (*func) (this->value, this->id, this->type, cdata); 1050 if (*eltptr != elements) 1051 next = resources[i]; /* start over */ 1052 } 1053 } 1054} 1055 1056void * 1057LookupClientResourceComplex(ClientPtr client, 1058 RESTYPE type, 1059 FindComplexResType func, void *cdata) 1060{ 1061 ResourcePtr *resources; 1062 ResourcePtr this, next; 1063 void *value; 1064 int i; 1065 1066 if (!client) 1067 client = serverClient; 1068 1069 resources = clientTable[client->index].resources; 1070 for (i = 0; i < clientTable[client->index].buckets; i++) { 1071 for (this = resources[i]; this; this = next) { 1072 next = this->next; 1073 if (!type || this->type == type) { 1074 /* workaround func freeing the type as DRI1 does */ 1075 value = this->value; 1076 if ((*func) (value, this->id, cdata)) 1077 return value; 1078 } 1079 } 1080 } 1081 return NULL; 1082} 1083 1084void 1085FreeClientNeverRetainResources(ClientPtr client) 1086{ 1087 ResourcePtr *resources; 1088 ResourcePtr this; 1089 ResourcePtr *prev; 1090 int j, elements; 1091 int *eltptr; 1092 1093 if (!client) 1094 return; 1095 1096 resources = clientTable[client->index].resources; 1097 eltptr = &clientTable[client->index].elements; 1098 for (j = 0; j < clientTable[client->index].buckets; j++) { 1099 prev = &resources[j]; 1100 while ((this = *prev)) { 1101 RESTYPE rtype = this->type; 1102 1103 if (rtype & RC_NEVERRETAIN) { 1104#ifdef XSERVER_DTRACE 1105 XSERVER_RESOURCE_FREE(this->id, this->type, 1106 this->value, TypeNameString(this->type)); 1107#endif 1108 *prev = this->next; 1109 clientTable[client->index].elements--; 1110 elements = *eltptr; 1111 1112 doFreeResource(this, FALSE); 1113 1114 if (*eltptr != elements) 1115 prev = &resources[j]; /* prev may no longer be valid */ 1116 } 1117 else 1118 prev = &this->next; 1119 } 1120 } 1121} 1122 1123void 1124FreeClientResources(ClientPtr client) 1125{ 1126 ResourcePtr *resources; 1127 ResourcePtr this; 1128 int j; 1129 1130 /* This routine shouldn't be called with a null client, but just in 1131 case ... */ 1132 1133 if (!client) 1134 return; 1135 1136 HandleSaveSet(client); 1137 1138 resources = clientTable[client->index].resources; 1139 for (j = 0; j < clientTable[client->index].buckets; j++) { 1140 /* It may seem silly to update the head of this resource list as 1141 we delete the members, since the entire list will be deleted any way, 1142 but there are some resource deletion functions "FreeClientPixels" for 1143 one which do a LookupID on another resource id (a Colormap id in this 1144 case), so the resource list must be kept valid up to the point that 1145 it is deleted, so every time we delete a resource, we must update the 1146 head, just like in FreeResource. I hope that this doesn't slow down 1147 mass deletion appreciably. PRH */ 1148 1149 ResourcePtr *head; 1150 1151 head = &resources[j]; 1152 1153 for (this = *head; this; this = *head) { 1154#ifdef XSERVER_DTRACE 1155 XSERVER_RESOURCE_FREE(this->id, this->type, 1156 this->value, TypeNameString(this->type)); 1157#endif 1158 *head = this->next; 1159 clientTable[client->index].elements--; 1160 1161 doFreeResource(this, FALSE); 1162 } 1163 } 1164 free(clientTable[client->index].resources); 1165 clientTable[client->index].resources = NULL; 1166 clientTable[client->index].buckets = 0; 1167} 1168 1169void 1170FreeAllResources(void) 1171{ 1172 int i; 1173 1174 for (i = currentMaxClients; --i >= 0;) { 1175 if (clientTable[i].buckets) 1176 FreeClientResources(clients[i]); 1177 } 1178} 1179 1180Bool 1181LegalNewID(XID id, ClientPtr client) 1182{ 1183 void *val; 1184 int rc; 1185 1186#ifdef PANORAMIX 1187 XID minid, maxid; 1188 1189 if (!noPanoramiXExtension) { 1190 minid = client->clientAsMask | (client->index ? 1191 SERVER_BIT : SERVER_MINID); 1192 maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1; 1193 if ((id >= minid) && (id <= maxid)) 1194 return TRUE; 1195 } 1196#endif /* PANORAMIX */ 1197 if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) { 1198 rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, 1199 DixGetAttrAccess); 1200 return rc == BadValue; 1201 } 1202 return FALSE; 1203} 1204 1205int 1206dixLookupResourceByType(void **result, XID id, RESTYPE rtype, 1207 ClientPtr client, Mask mode) 1208{ 1209 int cid = CLIENT_ID(id); 1210 ResourcePtr res = NULL; 1211 1212 *result = NULL; 1213 if ((rtype & TypeMask) > lastResourceType) 1214 return BadImplementation; 1215 1216 if ((cid < LimitClients) && clientTable[cid].buckets) { 1217 res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; 1218 1219 for (; res; res = res->next) 1220 if (res->id == id && res->type == rtype) 1221 break; 1222 } 1223 if (!res) 1224 return resourceTypes[rtype & TypeMask].errorValue; 1225 1226 if (client) { 1227 client->errorValue = id; 1228 cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, 1229 res->value, RT_NONE, NULL, mode); 1230 if (cid == BadValue) 1231 return resourceTypes[rtype & TypeMask].errorValue; 1232 if (cid != Success) 1233 return cid; 1234 } 1235 1236 *result = res->value; 1237 return Success; 1238} 1239 1240int 1241dixLookupResourceByClass(void **result, XID id, RESTYPE rclass, 1242 ClientPtr client, Mask mode) 1243{ 1244 int cid = CLIENT_ID(id); 1245 ResourcePtr res = NULL; 1246 1247 *result = NULL; 1248 1249 if ((cid < LimitClients) && clientTable[cid].buckets) { 1250 res = clientTable[cid].resources[HashResourceID(id, clientTable[cid].hashsize)]; 1251 1252 for (; res; res = res->next) 1253 if (res->id == id && (res->type & rclass)) 1254 break; 1255 } 1256 if (!res) 1257 return BadValue; 1258 1259 if (client) { 1260 client->errorValue = id; 1261 cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, 1262 res->value, RT_NONE, NULL, mode); 1263 if (cid != Success) 1264 return cid; 1265 } 1266 1267 *result = res->value; 1268 return Success; 1269} 1270