resource.c revision 706f2543
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 25 26Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 27 28 All Rights Reserved 29 30Permission to use, copy, modify, and distribute this software and its 31documentation for any purpose and without fee is hereby granted, 32provided that the above copyright notice appear in all copies and that 33both that copyright notice and this permission notice appear in 34supporting documentation, and that the name of Digital not be 35used in advertising or publicity pertaining to distribution of the 36software without specific, written prior permission. 37 38DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 39ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 40DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 41ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 42WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 43ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 44SOFTWARE. 45 46********************************************************/ 47/* The panoramix components contained the following notice */ 48/***************************************************************** 49 50Copyright (c) 1991, 1997 Digital Equipment Corporation, Maynard, Massachusetts. 51 52Permission is hereby granted, free of charge, to any person obtaining a copy 53of this software and associated documentation files (the "Software"), to deal 54in the Software without restriction, including without limitation the rights 55to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 56copies of the Software. 57 58The above copyright notice and this permission notice shall be included in 59all copies or substantial portions of the Software. 60 61THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 62IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 63FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 64DIGITAL EQUIPMENT CORPORATION BE LIABLE FOR ANY CLAIM, DAMAGES, INCLUDING, 65BUT NOT LIMITED TO CONSEQUENTIAL OR INCIDENTAL DAMAGES, OR OTHER LIABILITY, 66WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 67IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 68 69Except as contained in this notice, the name of Digital Equipment Corporation 70shall not be used in advertising or otherwise to promote the sale, use or other 71dealings in this Software without prior written authorization from Digital 72Equipment Corporation. 73 74******************************************************************/ 75/* XSERVER_DTRACE additions: 76 * Copyright (c) 2005-2006, Oracle and/or its affiliates. All rights reserved. 77 * 78 * Permission is hereby granted, free of charge, to any person obtaining a 79 * copy of this software and associated documentation files (the "Software"), 80 * to deal in the Software without restriction, including without limitation 81 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 82 * and/or sell copies of the Software, and to permit persons to whom the 83 * Software is furnished to do so, subject to the following conditions: 84 * 85 * The above copyright notice and this permission notice (including the next 86 * paragraph) shall be included in all copies or substantial portions of the 87 * Software. 88 * 89 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 90 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 91 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 92 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 93 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 94 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 95 * DEALINGS IN THE SOFTWARE. 96 */ 97 98/* Routines to manage various kinds of resources: 99 * 100 * CreateNewResourceType, CreateNewResourceClass, InitClientResources, 101 * FakeClientID, AddResource, FreeResource, FreeClientResources, 102 * FreeAllResources, LookupIDByType, LookupIDByClass, GetXIDRange 103 */ 104 105/* 106 * A resource ID is a 32 bit quantity, the upper 2 bits of which are 107 * off-limits for client-visible resources. The next 8 bits are 108 * used as client ID, and the low 22 bits come from the client. 109 * A resource ID is "hashed" by extracting and xoring subfields 110 * (varying with the size of the hash table). 111 * 112 * It is sometimes necessary for the server to create an ID that looks 113 * like it belongs to a client. This ID, however, must not be one 114 * the client actually can create, or we have the potential for conflict. 115 * The 31st bit of the ID is reserved for the server's use for this 116 * purpose. By setting CLIENT_ID(id) to the client, the SERVER_BIT to 117 * 1, and an otherwise arbitrary ID in the low 22 bits, we can create a 118 * resource "owned" by the client. 119 */ 120 121#ifdef HAVE_DIX_CONFIG_H 122#include <dix-config.h> 123#endif 124 125#include <X11/X.h> 126#include "misc.h" 127#include "os.h" 128#include "resource.h" 129#include "dixstruct.h" 130#include "opaque.h" 131#include "windowstr.h" 132#include "dixfont.h" 133#include "colormap.h" 134#include "inputstr.h" 135#include "dixevents.h" 136#include "dixgrabs.h" 137#include "cursor.h" 138#ifdef PANORAMIX 139#include "panoramiX.h" 140#include "panoramiXsrv.h" 141#endif 142#include "xace.h" 143#include <assert.h> 144#include "registry.h" 145 146#ifdef XSERVER_DTRACE 147#include <sys/types.h> 148typedef const char *string; 149#include "Xserver-dtrace.h" 150 151#define TypeNameString(t) LookupResourceName(t) 152#endif 153 154static void RebuildTable( 155 int /*client*/ 156); 157 158#define SERVER_MINID 32 159 160#define INITBUCKETS 64 161#define INITHASHSIZE 6 162#define MAXHASHSIZE 11 163 164typedef struct _Resource { 165 struct _Resource *next; 166 XID id; 167 RESTYPE type; 168 pointer value; 169} ResourceRec, *ResourcePtr; 170 171typedef struct _ClientResource { 172 ResourcePtr *resources; 173 int elements; 174 int buckets; 175 int hashsize; /* log(2)(buckets) */ 176 XID fakeID; 177 XID endFakeID; 178} ClientResourceRec; 179 180RESTYPE lastResourceType; 181static RESTYPE lastResourceClass; 182RESTYPE TypeMask; 183 184struct ResourceType { 185 DeleteType deleteFunc; 186 int errorValue; 187}; 188 189static struct ResourceType *resourceTypes; 190static const struct ResourceType predefTypes[] = { 191 [RT_NONE & (RC_LASTPREDEF - 1)] = { 192 .deleteFunc = (DeleteType)NoopDDA, 193 .errorValue = BadValue, 194 }, 195 [RT_WINDOW & (RC_LASTPREDEF - 1)] = { 196 .deleteFunc = DeleteWindow, 197 .errorValue = BadWindow, 198 }, 199 [RT_PIXMAP & (RC_LASTPREDEF - 1)] = { 200 .deleteFunc = dixDestroyPixmap, 201 .errorValue = BadPixmap, 202 }, 203 [RT_GC & (RC_LASTPREDEF - 1)] = { 204 .deleteFunc = FreeGC, 205 .errorValue = BadGC, 206 }, 207 [RT_FONT & (RC_LASTPREDEF - 1)] = { 208 .deleteFunc = CloseFont, 209 .errorValue = BadFont, 210 }, 211 [RT_CURSOR & (RC_LASTPREDEF - 1)] = { 212 .deleteFunc = FreeCursor, 213 .errorValue = BadCursor, 214 }, 215 [RT_COLORMAP & (RC_LASTPREDEF - 1)] = { 216 .deleteFunc = FreeColormap, 217 .errorValue = BadColor, 218 }, 219 [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = { 220 .deleteFunc = FreeClientPixels, 221 .errorValue = BadColor, 222 }, 223 [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = { 224 .deleteFunc = OtherClientGone, 225 .errorValue = BadValue, 226 }, 227 [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = { 228 .deleteFunc = DeletePassiveGrab, 229 .errorValue = BadValue, 230 }, 231}; 232 233CallbackListPtr ResourceStateCallback; 234 235static _X_INLINE void 236CallResourceStateCallback(ResourceState state, ResourceRec *res) 237{ 238 if (ResourceStateCallback) { 239 ResourceStateInfoRec rsi = { state, res->id, res->type, res->value }; 240 CallCallbacks(&ResourceStateCallback, &rsi); 241 } 242} 243 244RESTYPE 245CreateNewResourceType(DeleteType deleteFunc, char *name) 246{ 247 RESTYPE next = lastResourceType + 1; 248 struct ResourceType *types; 249 250 if (next & lastResourceClass) 251 return 0; 252 types = realloc(resourceTypes, (next + 1) * sizeof(*resourceTypes)); 253 if (!types) 254 return 0; 255 256 lastResourceType = next; 257 resourceTypes = types; 258 resourceTypes[next].deleteFunc = deleteFunc; 259 resourceTypes[next].errorValue = BadValue; 260 261 /* Called even if name is NULL, to remove any previous entry */ 262 RegisterResourceName(next, name); 263 264 return next; 265} 266 267void 268SetResourceTypeErrorValue(RESTYPE type, int errorValue) 269{ 270 resourceTypes[type & TypeMask].errorValue = errorValue; 271} 272 273RESTYPE 274CreateNewResourceClass(void) 275{ 276 RESTYPE next = lastResourceClass >> 1; 277 278 if (next & lastResourceType) 279 return 0; 280 lastResourceClass = next; 281 TypeMask = next - 1; 282 return next; 283} 284 285static ClientResourceRec clientTable[MAXCLIENTS]; 286 287/***************** 288 * InitClientResources 289 * When a new client is created, call this to allocate space 290 * in resource table 291 *****************/ 292 293Bool 294InitClientResources(ClientPtr client) 295{ 296 int i, j; 297 298 if (client == serverClient) 299 { 300 lastResourceType = RT_LASTPREDEF; 301 lastResourceClass = RC_LASTPREDEF; 302 TypeMask = RC_LASTPREDEF - 1; 303 free(resourceTypes); 304 resourceTypes = malloc(sizeof(predefTypes)); 305 if (!resourceTypes) 306 return FALSE; 307 memcpy(resourceTypes, predefTypes, sizeof(predefTypes)); 308 } 309 clientTable[i = client->index].resources = 310 malloc(INITBUCKETS*sizeof(ResourcePtr)); 311 if (!clientTable[i].resources) 312 return FALSE; 313 clientTable[i].buckets = INITBUCKETS; 314 clientTable[i].elements = 0; 315 clientTable[i].hashsize = INITHASHSIZE; 316 /* Many IDs allocated from the server client are visible to clients, 317 * so we don't use the SERVER_BIT for them, but we have to start 318 * past the magic value constants used in the protocol. For normal 319 * clients, we can start from zero, with SERVER_BIT set. 320 */ 321 clientTable[i].fakeID = client->clientAsMask | 322 (client->index ? SERVER_BIT : SERVER_MINID); 323 clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1; 324 for (j=0; j<INITBUCKETS; j++) 325 { 326 clientTable[i].resources[j] = NULL; 327 } 328 return TRUE; 329} 330 331 332static int 333Hash(int client, XID id) 334{ 335 id &= RESOURCE_ID_MASK; 336 switch (clientTable[client].hashsize) 337 { 338 case 6: 339 return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12)))); 340 case 7: 341 return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13)))); 342 case 8: 343 return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16)))); 344 case 9: 345 return ((int)(0x1FF & (id ^ (id>>9)))); 346 case 10: 347 return ((int)(0x3FF & (id ^ (id>>10)))); 348 case 11: 349 return ((int)(0x7FF & (id ^ (id>>11)))); 350 } 351 return -1; 352} 353 354static XID 355AvailableID( 356 int client, 357 XID id, 358 XID maxid, 359 XID goodid) 360{ 361 ResourcePtr res; 362 363 if ((goodid >= id) && (goodid <= maxid)) 364 return goodid; 365 for (; id <= maxid; id++) 366 { 367 res = clientTable[client].resources[Hash(client, id)]; 368 while (res && (res->id != id)) 369 res = res->next; 370 if (!res) 371 return id; 372 } 373 return 0; 374} 375 376void 377GetXIDRange(int client, Bool server, XID *minp, XID *maxp) 378{ 379 XID id, maxid; 380 ResourcePtr *resp; 381 ResourcePtr res; 382 int i; 383 XID goodid; 384 385 id = (Mask)client << CLIENTOFFSET; 386 if (server) 387 id |= client ? SERVER_BIT : SERVER_MINID; 388 maxid = id | RESOURCE_ID_MASK; 389 goodid = 0; 390 for (resp = clientTable[client].resources, i = clientTable[client].buckets; 391 --i >= 0;) 392 { 393 for (res = *resp++; res; res = res->next) 394 { 395 if ((res->id < id) || (res->id > maxid)) 396 continue; 397 if (((res->id - id) >= (maxid - res->id)) ? 398 (goodid = AvailableID(client, id, res->id - 1, goodid)) : 399 !(goodid = AvailableID(client, res->id + 1, maxid, goodid))) 400 maxid = res->id - 1; 401 else 402 id = res->id + 1; 403 } 404 } 405 if (id > maxid) 406 id = maxid = 0; 407 *minp = id; 408 *maxp = maxid; 409} 410 411/** 412 * GetXIDList is called by the XC-MISC extension's MiscGetXIDList function. 413 * This function tries to find count unused XIDs for the given client. It 414 * puts the IDs in the array pids and returns the number found, which should 415 * almost always be the number requested. 416 * 417 * The circumstances that lead to a call to this function are very rare. 418 * Xlib must run out of IDs while trying to generate a request that wants 419 * multiple ID's, like the Multi-buffering CreateImageBuffers request. 420 * 421 * No rocket science in the implementation; just iterate over all 422 * possible IDs for the given client and pick the first count IDs 423 * that aren't in use. A more efficient algorithm could probably be 424 * invented, but this will be used so rarely that this should suffice. 425 */ 426 427unsigned int 428GetXIDList(ClientPtr pClient, unsigned count, XID *pids) 429{ 430 unsigned int found = 0; 431 XID rc, id = pClient->clientAsMask; 432 XID maxid; 433 pointer val; 434 435 maxid = id | RESOURCE_ID_MASK; 436 while ( (found < count) && (id <= maxid) ) 437 { 438 rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, 439 DixGetAttrAccess); 440 if (rc == BadValue) 441 { 442 pids[found++] = id; 443 } 444 id++; 445 } 446 return found; 447} 448 449/* 450 * Return the next usable fake client ID. 451 * 452 * Normally this is just the next one in line, but if we've used the last 453 * in the range, we need to find a new range of safe IDs to avoid 454 * over-running another client. 455 */ 456 457XID 458FakeClientID(int client) 459{ 460 XID id, maxid; 461 462 id = clientTable[client].fakeID++; 463 if (id != clientTable[client].endFakeID) 464 return id; 465 GetXIDRange(client, TRUE, &id, &maxid); 466 if (!id) { 467 if (!client) 468 FatalError("FakeClientID: server internal ids exhausted\n"); 469 MarkClientException(clients[client]); 470 id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3); 471 maxid = id | RESOURCE_ID_MASK; 472 } 473 clientTable[client].fakeID = id + 1; 474 clientTable[client].endFakeID = maxid + 1; 475 return id; 476} 477 478Bool 479AddResource(XID id, RESTYPE type, pointer value) 480{ 481 int client; 482 ClientResourceRec *rrec; 483 ResourcePtr res, *head; 484 485#ifdef XSERVER_DTRACE 486 XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type)); 487#endif 488 client = CLIENT_ID(id); 489 rrec = &clientTable[client]; 490 if (!rrec->buckets) 491 { 492 ErrorF("[dix] AddResource(%lx, %lx, %lx), client=%d \n", 493 (unsigned long)id, type, (unsigned long)value, client); 494 FatalError("client not in use\n"); 495 } 496 if ((rrec->elements >= 4*rrec->buckets) && 497 (rrec->hashsize < MAXHASHSIZE)) 498 RebuildTable(client); 499 head = &rrec->resources[Hash(client, id)]; 500 res = malloc(sizeof(ResourceRec)); 501 if (!res) 502 { 503 (*resourceTypes[type & TypeMask].deleteFunc)(value, id); 504 return FALSE; 505 } 506 res->next = *head; 507 res->id = id; 508 res->type = type; 509 res->value = value; 510 *head = res; 511 rrec->elements++; 512 CallResourceStateCallback(ResourceStateAdding, res); 513 return TRUE; 514} 515 516static void 517RebuildTable(int client) 518{ 519 int j; 520 ResourcePtr res, next; 521 ResourcePtr **tails, *resources; 522 ResourcePtr **tptr, *rptr; 523 524 /* 525 * For now, preserve insertion order, since some ddx layers depend 526 * on resources being free in the opposite order they are added. 527 */ 528 529 j = 2 * clientTable[client].buckets; 530 tails = malloc(j * sizeof(ResourcePtr *)); 531 if (!tails) 532 return; 533 resources = malloc(j * sizeof(ResourcePtr)); 534 if (!resources) 535 { 536 free(tails); 537 return; 538 } 539 for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) 540 { 541 *rptr = NULL; 542 *tptr = rptr; 543 } 544 clientTable[client].hashsize++; 545 for (j = clientTable[client].buckets, 546 rptr = clientTable[client].resources; 547 --j >= 0; 548 rptr++) 549 { 550 for (res = *rptr; res; res = next) 551 { 552 next = res->next; 553 res->next = NULL; 554 tptr = &tails[Hash(client, res->id)]; 555 **tptr = res; 556 *tptr = &res->next; 557 } 558 } 559 free(tails); 560 clientTable[client].buckets *= 2; 561 free(clientTable[client].resources); 562 clientTable[client].resources = resources; 563} 564 565void 566FreeResource(XID id, RESTYPE skipDeleteFuncType) 567{ 568 int cid; 569 ResourcePtr res; 570 ResourcePtr *prev, *head; 571 int *eltptr; 572 int elements; 573 574 if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) 575 { 576 head = &clientTable[cid].resources[Hash(cid, id)]; 577 eltptr = &clientTable[cid].elements; 578 579 prev = head; 580 while ( (res = *prev) ) 581 { 582 if (res->id == id) 583 { 584 RESTYPE rtype = res->type; 585 586#ifdef XSERVER_DTRACE 587 XSERVER_RESOURCE_FREE(res->id, res->type, 588 res->value, TypeNameString(res->type)); 589#endif 590 *prev = res->next; 591 elements = --*eltptr; 592 593 CallResourceStateCallback(ResourceStateFreeing, res); 594 595 if (rtype != skipDeleteFuncType) 596 (*resourceTypes[rtype & TypeMask].deleteFunc)(res->value, res->id); 597 free(res); 598 if (*eltptr != elements) 599 prev = head; /* prev may no longer be valid */ 600 } 601 else 602 prev = &res->next; 603 } 604 } 605} 606 607 608void 609FreeResourceByType(XID id, RESTYPE type, Bool skipFree) 610{ 611 int cid; 612 ResourcePtr res; 613 ResourcePtr *prev, *head; 614 if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) 615 { 616 head = &clientTable[cid].resources[Hash(cid, id)]; 617 618 prev = head; 619 while ( (res = *prev) ) 620 { 621 if (res->id == id && res->type == type) 622 { 623#ifdef XSERVER_DTRACE 624 XSERVER_RESOURCE_FREE(res->id, res->type, 625 res->value, TypeNameString(res->type)); 626#endif 627 *prev = res->next; 628 clientTable[cid].elements--; 629 630 CallResourceStateCallback(ResourceStateFreeing, res); 631 632 if (!skipFree) 633 (*resourceTypes[type & TypeMask].deleteFunc)(res->value, res->id); 634 free(res); 635 break; 636 } 637 else 638 prev = &res->next; 639 } 640 } 641} 642 643/* 644 * Change the value associated with a resource id. Caller 645 * is responsible for "doing the right thing" with the old 646 * data 647 */ 648 649Bool 650ChangeResourceValue (XID id, RESTYPE rtype, pointer value) 651{ 652 int cid; 653 ResourcePtr res; 654 655 if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) 656 { 657 res = clientTable[cid].resources[Hash(cid, id)]; 658 659 for (; res; res = res->next) 660 if ((res->id == id) && (res->type == rtype)) 661 { 662 res->value = value; 663 return TRUE; 664 } 665 } 666 return FALSE; 667} 668 669/* Note: if func adds or deletes resources, then func can get called 670 * more than once for some resources. If func adds new resources, 671 * func might or might not get called for them. func cannot both 672 * add and delete an equal number of resources! 673 */ 674 675void 676FindClientResourcesByType( 677 ClientPtr client, 678 RESTYPE type, 679 FindResType func, 680 pointer cdata 681){ 682 ResourcePtr *resources; 683 ResourcePtr this, next; 684 int i, elements; 685 int *eltptr; 686 687 if (!client) 688 client = serverClient; 689 690 resources = clientTable[client->index].resources; 691 eltptr = &clientTable[client->index].elements; 692 for (i = 0; i < clientTable[client->index].buckets; i++) 693 { 694 for (this = resources[i]; this; this = next) 695 { 696 next = this->next; 697 if (!type || this->type == type) { 698 elements = *eltptr; 699 (*func)(this->value, this->id, cdata); 700 if (*eltptr != elements) 701 next = resources[i]; /* start over */ 702 } 703 } 704 } 705} 706 707void 708FindAllClientResources( 709 ClientPtr client, 710 FindAllRes func, 711 pointer cdata 712){ 713 ResourcePtr *resources; 714 ResourcePtr this, next; 715 int i, elements; 716 int *eltptr; 717 718 if (!client) 719 client = serverClient; 720 721 resources = clientTable[client->index].resources; 722 eltptr = &clientTable[client->index].elements; 723 for (i = 0; i < clientTable[client->index].buckets; i++) 724 { 725 for (this = resources[i]; this; this = next) 726 { 727 next = this->next; 728 elements = *eltptr; 729 (*func)(this->value, this->id, this->type, cdata); 730 if (*eltptr != elements) 731 next = resources[i]; /* start over */ 732 } 733 } 734} 735 736 737pointer 738LookupClientResourceComplex( 739 ClientPtr client, 740 RESTYPE type, 741 FindComplexResType func, 742 pointer cdata 743){ 744 ResourcePtr *resources; 745 ResourcePtr this, next; 746 pointer value; 747 int i; 748 749 if (!client) 750 client = serverClient; 751 752 resources = clientTable[client->index].resources; 753 for (i = 0; i < clientTable[client->index].buckets; i++) { 754 for (this = resources[i]; this; this = next) { 755 next = this->next; 756 if (!type || this->type == type) { 757 /* workaround func freeing the type as DRI1 does */ 758 value = this->value; 759 if((*func)(value, this->id, cdata)) 760 return value; 761 } 762 } 763 } 764 return NULL; 765} 766 767 768void 769FreeClientNeverRetainResources(ClientPtr client) 770{ 771 ResourcePtr *resources; 772 ResourcePtr this; 773 ResourcePtr *prev; 774 int j, elements; 775 int *eltptr; 776 777 if (!client) 778 return; 779 780 resources = clientTable[client->index].resources; 781 eltptr = &clientTable[client->index].elements; 782 for (j=0; j < clientTable[client->index].buckets; j++) 783 { 784 prev = &resources[j]; 785 while ( (this = *prev) ) 786 { 787 RESTYPE rtype = this->type; 788 if (rtype & RC_NEVERRETAIN) 789 { 790#ifdef XSERVER_DTRACE 791 XSERVER_RESOURCE_FREE(this->id, this->type, 792 this->value, TypeNameString(this->type)); 793#endif 794 *prev = this->next; 795 clientTable[client->index].elements--; 796 797 CallResourceStateCallback(ResourceStateFreeing, this); 798 799 elements = *eltptr; 800 (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id); 801 free(this); 802 if (*eltptr != elements) 803 prev = &resources[j]; /* prev may no longer be valid */ 804 } 805 else 806 prev = &this->next; 807 } 808 } 809} 810 811void 812FreeClientResources(ClientPtr client) 813{ 814 ResourcePtr *resources; 815 ResourcePtr this; 816 int j; 817 818 /* This routine shouldn't be called with a null client, but just in 819 case ... */ 820 821 if (!client) 822 return; 823 824 HandleSaveSet(client); 825 826 resources = clientTable[client->index].resources; 827 for (j=0; j < clientTable[client->index].buckets; j++) 828 { 829 /* It may seem silly to update the head of this resource list as 830 we delete the members, since the entire list will be deleted any way, 831 but there are some resource deletion functions "FreeClientPixels" for 832 one which do a LookupID on another resource id (a Colormap id in this 833 case), so the resource list must be kept valid up to the point that 834 it is deleted, so every time we delete a resource, we must update the 835 head, just like in FreeResource. I hope that this doesn't slow down 836 mass deletion appreciably. PRH */ 837 838 ResourcePtr *head; 839 840 head = &resources[j]; 841 842 for (this = *head; this; this = *head) 843 { 844 RESTYPE rtype = this->type; 845#ifdef XSERVER_DTRACE 846 XSERVER_RESOURCE_FREE(this->id, this->type, 847 this->value, TypeNameString(this->type)); 848#endif 849 *head = this->next; 850 clientTable[client->index].elements--; 851 852 CallResourceStateCallback(ResourceStateFreeing, this); 853 854 (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id); 855 free(this); 856 } 857 } 858 free(clientTable[client->index].resources); 859 clientTable[client->index].resources = NULL; 860 clientTable[client->index].buckets = 0; 861} 862 863void 864FreeAllResources(void) 865{ 866 int i; 867 868 for (i = currentMaxClients; --i >= 0; ) 869 { 870 if (clientTable[i].buckets) 871 FreeClientResources(clients[i]); 872 } 873} 874 875Bool 876LegalNewID(XID id, ClientPtr client) 877{ 878 pointer val; 879 int rc; 880 881#ifdef PANORAMIX 882 XID minid, maxid; 883 884 if (!noPanoramiXExtension) { 885 minid = client->clientAsMask | (client->index ? 886 SERVER_BIT : SERVER_MINID); 887 maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1; 888 if ((id >= minid) && (id <= maxid)) 889 return TRUE; 890 } 891#endif /* PANORAMIX */ 892 if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) 893 { 894 rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, 895 DixGetAttrAccess); 896 return rc == BadValue; 897 } 898 return FALSE; 899} 900 901int 902dixLookupResourceByType(pointer *result, XID id, RESTYPE rtype, 903 ClientPtr client, Mask mode) 904{ 905 int cid = CLIENT_ID(id); 906 ResourcePtr res = NULL; 907 908 *result = NULL; 909 if ((rtype & TypeMask) > lastResourceType) 910 return BadImplementation; 911 912 if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { 913 res = clientTable[cid].resources[Hash(cid, id)]; 914 915 for (; res; res = res->next) 916 if (res->id == id && res->type == rtype) 917 break; 918 } 919 if (!res) 920 return resourceTypes[rtype & TypeMask].errorValue; 921 922 if (client) { 923 client->errorValue = id; 924 cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, 925 res->value, RT_NONE, NULL, mode); 926 if (cid == BadValue) 927 return resourceTypes[rtype & TypeMask].errorValue; 928 if (cid != Success) 929 return cid; 930 } 931 932 *result = res->value; 933 return Success; 934} 935 936int 937dixLookupResourceByClass(pointer *result, XID id, RESTYPE rclass, 938 ClientPtr client, Mask mode) 939{ 940 int cid = CLIENT_ID(id); 941 ResourcePtr res = NULL; 942 943 *result = NULL; 944 945 if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { 946 res = clientTable[cid].resources[Hash(cid, id)]; 947 948 for (; res; res = res->next) 949 if (res->id == id && (res->type & rclass)) 950 break; 951 } 952 if (!res) 953 return BadValue; 954 955 if (client) { 956 client->errorValue = id; 957 cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, 958 res->value, RT_NONE, NULL, mode); 959 if (cid != Success) 960 return cid; 961 } 962 963 *result = res->value; 964 return Success; 965} 966