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 }