resource.c revision 6747b715
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 2005-2006 Sun Microsystems, Inc. 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#define NullResource ((ResourcePtr)NULL) 171 172typedef struct _ClientResource { 173 ResourcePtr *resources; 174 int elements; 175 int buckets; 176 int hashsize; /* log(2)(buckets) */ 177 XID fakeID; 178 XID endFakeID; 179 XID expectID; 180} ClientResourceRec; 181 182RESTYPE lastResourceType; 183static RESTYPE lastResourceClass; 184RESTYPE TypeMask; 185 186struct ResourceType { 187 DeleteType deleteFunc; 188 int errorValue; 189}; 190 191static struct ResourceType *resourceTypes; 192static const struct ResourceType predefTypes[] = { 193 [RT_NONE & (RC_LASTPREDEF - 1)] = { 194 .deleteFunc = (DeleteType)NoopDDA, 195 .errorValue = BadValue, 196 }, 197 [RT_WINDOW & (RC_LASTPREDEF - 1)] = { 198 .deleteFunc = DeleteWindow, 199 .errorValue = BadWindow, 200 }, 201 [RT_PIXMAP & (RC_LASTPREDEF - 1)] = { 202 .deleteFunc = dixDestroyPixmap, 203 .errorValue = BadPixmap, 204 }, 205 [RT_GC & (RC_LASTPREDEF - 1)] = { 206 .deleteFunc = FreeGC, 207 .errorValue = BadGC, 208 }, 209 [RT_FONT & (RC_LASTPREDEF - 1)] = { 210 .deleteFunc = CloseFont, 211 .errorValue = BadFont, 212 }, 213 [RT_CURSOR & (RC_LASTPREDEF - 1)] = { 214 .deleteFunc = FreeCursor, 215 .errorValue = BadCursor, 216 }, 217 [RT_COLORMAP & (RC_LASTPREDEF - 1)] = { 218 .deleteFunc = FreeColormap, 219 .errorValue = BadColor, 220 }, 221 [RT_CMAPENTRY & (RC_LASTPREDEF - 1)] = { 222 .deleteFunc = FreeClientPixels, 223 .errorValue = BadColor, 224 }, 225 [RT_OTHERCLIENT & (RC_LASTPREDEF - 1)] = { 226 .deleteFunc = OtherClientGone, 227 .errorValue = BadValue, 228 }, 229 [RT_PASSIVEGRAB & (RC_LASTPREDEF - 1)] = { 230 .deleteFunc = DeletePassiveGrab, 231 .errorValue = BadValue, 232 }, 233}; 234 235CallbackListPtr ResourceStateCallback; 236 237static _X_INLINE void 238CallResourceStateCallback(ResourceState state, ResourceRec *res) 239{ 240 if (ResourceStateCallback) { 241 ResourceStateInfoRec rsi = { state, res->id, res->type, res->value }; 242 CallCallbacks(&ResourceStateCallback, &rsi); 243 } 244} 245 246RESTYPE 247CreateNewResourceType(DeleteType deleteFunc, char *name) 248{ 249 RESTYPE next = lastResourceType + 1; 250 struct ResourceType *types; 251 252 if (next & lastResourceClass) 253 return 0; 254 types = realloc(resourceTypes, (next + 1) * sizeof(*resourceTypes)); 255 if (!types) 256 return 0; 257 258 lastResourceType = next; 259 resourceTypes = types; 260 resourceTypes[next].deleteFunc = deleteFunc; 261 resourceTypes[next].errorValue = BadValue; 262 263 /* Called even if name is NULL, to remove any previous entry */ 264 RegisterResourceName(next, name); 265 266 return next; 267} 268 269void 270SetResourceTypeErrorValue(RESTYPE type, int errorValue) 271{ 272 resourceTypes[type & TypeMask].errorValue = errorValue; 273} 274 275RESTYPE 276CreateNewResourceClass(void) 277{ 278 RESTYPE next = lastResourceClass >> 1; 279 280 if (next & lastResourceType) 281 return 0; 282 lastResourceClass = next; 283 TypeMask = next - 1; 284 return next; 285} 286 287static ClientResourceRec clientTable[MAXCLIENTS]; 288 289/***************** 290 * InitClientResources 291 * When a new client is created, call this to allocate space 292 * in resource table 293 *****************/ 294 295Bool 296InitClientResources(ClientPtr client) 297{ 298 int i, j; 299 300 if (client == serverClient) 301 { 302 lastResourceType = RT_LASTPREDEF; 303 lastResourceClass = RC_LASTPREDEF; 304 TypeMask = RC_LASTPREDEF - 1; 305 free(resourceTypes); 306 resourceTypes = malloc(sizeof(predefTypes)); 307 if (!resourceTypes) 308 return FALSE; 309 memcpy(resourceTypes, predefTypes, sizeof(predefTypes)); 310 } 311 clientTable[i = client->index].resources = 312 malloc(INITBUCKETS*sizeof(ResourcePtr)); 313 if (!clientTable[i].resources) 314 return FALSE; 315 clientTable[i].buckets = INITBUCKETS; 316 clientTable[i].elements = 0; 317 clientTable[i].hashsize = INITHASHSIZE; 318 /* Many IDs allocated from the server client are visible to clients, 319 * so we don't use the SERVER_BIT for them, but we have to start 320 * past the magic value constants used in the protocol. For normal 321 * clients, we can start from zero, with SERVER_BIT set. 322 */ 323 clientTable[i].fakeID = client->clientAsMask | 324 (client->index ? SERVER_BIT : SERVER_MINID); 325 clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1; 326 clientTable[i].expectID = client->clientAsMask; 327 for (j=0; j<INITBUCKETS; j++) 328 { 329 clientTable[i].resources[j] = NullResource; 330 } 331 return TRUE; 332} 333 334 335static int 336Hash(int client, XID id) 337{ 338 id &= RESOURCE_ID_MASK; 339 switch (clientTable[client].hashsize) 340 { 341 case 6: 342 return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12)))); 343 case 7: 344 return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13)))); 345 case 8: 346 return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16)))); 347 case 9: 348 return ((int)(0x1FF & (id ^ (id>>9)))); 349 case 10: 350 return ((int)(0x3FF & (id ^ (id>>10)))); 351 case 11: 352 return ((int)(0x7FF & (id ^ (id>>11)))); 353 } 354 return -1; 355} 356 357static XID 358AvailableID( 359 int client, 360 XID id, 361 XID maxid, 362 XID goodid) 363{ 364 ResourcePtr res; 365 366 if ((goodid >= id) && (goodid <= maxid)) 367 return goodid; 368 for (; id <= maxid; id++) 369 { 370 res = clientTable[client].resources[Hash(client, id)]; 371 while (res && (res->id != id)) 372 res = res->next; 373 if (!res) 374 return id; 375 } 376 return 0; 377} 378 379void 380GetXIDRange(int client, Bool server, XID *minp, XID *maxp) 381{ 382 XID id, maxid; 383 ResourcePtr *resp; 384 ResourcePtr res; 385 int i; 386 XID goodid; 387 388 id = (Mask)client << CLIENTOFFSET; 389 if (server) 390 id |= client ? SERVER_BIT : SERVER_MINID; 391 maxid = id | RESOURCE_ID_MASK; 392 goodid = 0; 393 for (resp = clientTable[client].resources, i = clientTable[client].buckets; 394 --i >= 0;) 395 { 396 for (res = *resp++; res; res = res->next) 397 { 398 if ((res->id < id) || (res->id > maxid)) 399 continue; 400 if (((res->id - id) >= (maxid - res->id)) ? 401 (goodid = AvailableID(client, id, res->id - 1, goodid)) : 402 !(goodid = AvailableID(client, res->id + 1, maxid, goodid))) 403 maxid = res->id - 1; 404 else 405 id = res->id + 1; 406 } 407 } 408 if (id > maxid) 409 id = maxid = 0; 410 *minp = id; 411 *maxp = maxid; 412} 413 414/** 415 * GetXIDList is called by the XC-MISC extension's MiscGetXIDList function. 416 * This function tries to find count unused XIDs for the given client. It 417 * puts the IDs in the array pids and returns the number found, which should 418 * almost always be the number requested. 419 * 420 * The circumstances that lead to a call to this function are very rare. 421 * Xlib must run out of IDs while trying to generate a request that wants 422 * multiple ID's, like the Multi-buffering CreateImageBuffers request. 423 * 424 * No rocket science in the implementation; just iterate over all 425 * possible IDs for the given client and pick the first count IDs 426 * that aren't in use. A more efficient algorithm could probably be 427 * invented, but this will be used so rarely that this should suffice. 428 */ 429 430unsigned int 431GetXIDList(ClientPtr pClient, unsigned count, XID *pids) 432{ 433 unsigned int found = 0; 434 XID rc, id = pClient->clientAsMask; 435 XID maxid; 436 pointer val; 437 438 maxid = id | RESOURCE_ID_MASK; 439 while ( (found < count) && (id <= maxid) ) 440 { 441 rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, 442 DixGetAttrAccess); 443 if (rc == BadValue) 444 { 445 pids[found++] = id; 446 } 447 id++; 448 } 449 return found; 450} 451 452/* 453 * Return the next usable fake client ID. 454 * 455 * Normally this is just the next one in line, but if we've used the last 456 * in the range, we need to find a new range of safe IDs to avoid 457 * over-running another client. 458 */ 459 460XID 461FakeClientID(int client) 462{ 463 XID id, maxid; 464 465 id = clientTable[client].fakeID++; 466 if (id != clientTable[client].endFakeID) 467 return id; 468 GetXIDRange(client, TRUE, &id, &maxid); 469 if (!id) { 470 if (!client) 471 FatalError("FakeClientID: server internal ids exhausted\n"); 472 MarkClientException(clients[client]); 473 id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3); 474 maxid = id | RESOURCE_ID_MASK; 475 } 476 clientTable[client].fakeID = id + 1; 477 clientTable[client].endFakeID = maxid + 1; 478 return id; 479} 480 481Bool 482AddResource(XID id, RESTYPE type, pointer value) 483{ 484 int client; 485 ClientResourceRec *rrec; 486 ResourcePtr res, *head; 487 488#ifdef XSERVER_DTRACE 489 XSERVER_RESOURCE_ALLOC(id, type, value, TypeNameString(type)); 490#endif 491 client = CLIENT_ID(id); 492 rrec = &clientTable[client]; 493 if (!rrec->buckets) 494 { 495 ErrorF("[dix] AddResource(%lx, %lx, %lx), client=%d \n", 496 (unsigned long)id, type, (unsigned long)value, client); 497 FatalError("client not in use\n"); 498 } 499 if ((rrec->elements >= 4*rrec->buckets) && 500 (rrec->hashsize < MAXHASHSIZE)) 501 RebuildTable(client); 502 head = &rrec->resources[Hash(client, id)]; 503 res = malloc(sizeof(ResourceRec)); 504 if (!res) 505 { 506 (*resourceTypes[type & TypeMask].deleteFunc)(value, id); 507 return FALSE; 508 } 509 res->next = *head; 510 res->id = id; 511 res->type = type; 512 res->value = value; 513 *head = res; 514 rrec->elements++; 515 if (!(id & SERVER_BIT) && (id >= rrec->expectID)) 516 rrec->expectID = id + 1; 517 CallResourceStateCallback(ResourceStateAdding, res); 518 return TRUE; 519} 520 521static void 522RebuildTable(int client) 523{ 524 int j; 525 ResourcePtr res, next; 526 ResourcePtr **tails, *resources; 527 ResourcePtr **tptr, *rptr; 528 529 /* 530 * For now, preserve insertion order, since some ddx layers depend 531 * on resources being free in the opposite order they are added. 532 */ 533 534 j = 2 * clientTable[client].buckets; 535 tails = malloc(j * sizeof(ResourcePtr *)); 536 if (!tails) 537 return; 538 resources = malloc(j * sizeof(ResourcePtr)); 539 if (!resources) 540 { 541 free(tails); 542 return; 543 } 544 for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) 545 { 546 *rptr = NullResource; 547 *tptr = rptr; 548 } 549 clientTable[client].hashsize++; 550 for (j = clientTable[client].buckets, 551 rptr = clientTable[client].resources; 552 --j >= 0; 553 rptr++) 554 { 555 for (res = *rptr; res; res = next) 556 { 557 next = res->next; 558 res->next = NullResource; 559 tptr = &tails[Hash(client, res->id)]; 560 **tptr = res; 561 *tptr = &res->next; 562 } 563 } 564 free(tails); 565 clientTable[client].buckets *= 2; 566 free(clientTable[client].resources); 567 clientTable[client].resources = resources; 568} 569 570void 571FreeResource(XID id, RESTYPE skipDeleteFuncType) 572{ 573 int cid; 574 ResourcePtr res; 575 ResourcePtr *prev, *head; 576 int *eltptr; 577 int elements; 578 579 if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) 580 { 581 head = &clientTable[cid].resources[Hash(cid, id)]; 582 eltptr = &clientTable[cid].elements; 583 584 prev = head; 585 while ( (res = *prev) ) 586 { 587 if (res->id == id) 588 { 589 RESTYPE rtype = res->type; 590 591#ifdef XSERVER_DTRACE 592 XSERVER_RESOURCE_FREE(res->id, res->type, 593 res->value, TypeNameString(res->type)); 594#endif 595 *prev = res->next; 596 elements = --*eltptr; 597 598 CallResourceStateCallback(ResourceStateFreeing, res); 599 600 if (rtype != skipDeleteFuncType) 601 (*resourceTypes[rtype & TypeMask].deleteFunc)(res->value, res->id); 602 free(res); 603 if (*eltptr != elements) 604 prev = head; /* prev may no longer be valid */ 605 } 606 else 607 prev = &res->next; 608 } 609 } 610} 611 612 613void 614FreeResourceByType(XID id, RESTYPE type, Bool skipFree) 615{ 616 int cid; 617 ResourcePtr res; 618 ResourcePtr *prev, *head; 619 if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) 620 { 621 head = &clientTable[cid].resources[Hash(cid, id)]; 622 623 prev = head; 624 while ( (res = *prev) ) 625 { 626 if (res->id == id && res->type == type) 627 { 628#ifdef XSERVER_DTRACE 629 XSERVER_RESOURCE_FREE(res->id, res->type, 630 res->value, TypeNameString(res->type)); 631#endif 632 *prev = res->next; 633 clientTable[cid].elements--; 634 635 CallResourceStateCallback(ResourceStateFreeing, res); 636 637 if (!skipFree) 638 (*resourceTypes[type & TypeMask].deleteFunc)(res->value, res->id); 639 free(res); 640 break; 641 } 642 else 643 prev = &res->next; 644 } 645 } 646} 647 648/* 649 * Change the value associated with a resource id. Caller 650 * is responsible for "doing the right thing" with the old 651 * data 652 */ 653 654Bool 655ChangeResourceValue (XID id, RESTYPE rtype, pointer value) 656{ 657 int cid; 658 ResourcePtr res; 659 660 if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) 661 { 662 res = clientTable[cid].resources[Hash(cid, id)]; 663 664 for (; res; res = res->next) 665 if ((res->id == id) && (res->type == rtype)) 666 { 667 res->value = value; 668 return TRUE; 669 } 670 } 671 return FALSE; 672} 673 674/* Note: if func adds or deletes resources, then func can get called 675 * more than once for some resources. If func adds new resources, 676 * func might or might not get called for them. func cannot both 677 * add and delete an equal number of resources! 678 */ 679 680void 681FindClientResourcesByType( 682 ClientPtr client, 683 RESTYPE type, 684 FindResType func, 685 pointer cdata 686){ 687 ResourcePtr *resources; 688 ResourcePtr this, next; 689 int i, elements; 690 int *eltptr; 691 692 if (!client) 693 client = serverClient; 694 695 resources = clientTable[client->index].resources; 696 eltptr = &clientTable[client->index].elements; 697 for (i = 0; i < clientTable[client->index].buckets; i++) 698 { 699 for (this = resources[i]; this; this = next) 700 { 701 next = this->next; 702 if (!type || this->type == type) { 703 elements = *eltptr; 704 (*func)(this->value, this->id, cdata); 705 if (*eltptr != elements) 706 next = resources[i]; /* start over */ 707 } 708 } 709 } 710} 711 712void 713FindAllClientResources( 714 ClientPtr client, 715 FindAllRes func, 716 pointer cdata 717){ 718 ResourcePtr *resources; 719 ResourcePtr this, next; 720 int i, elements; 721 int *eltptr; 722 723 if (!client) 724 client = serverClient; 725 726 resources = clientTable[client->index].resources; 727 eltptr = &clientTable[client->index].elements; 728 for (i = 0; i < clientTable[client->index].buckets; i++) 729 { 730 for (this = resources[i]; this; this = next) 731 { 732 next = this->next; 733 elements = *eltptr; 734 (*func)(this->value, this->id, this->type, cdata); 735 if (*eltptr != elements) 736 next = resources[i]; /* start over */ 737 } 738 } 739} 740 741 742pointer 743LookupClientResourceComplex( 744 ClientPtr client, 745 RESTYPE type, 746 FindComplexResType func, 747 pointer cdata 748){ 749 ResourcePtr *resources; 750 ResourcePtr this, next; 751 pointer value; 752 int i; 753 754 if (!client) 755 client = serverClient; 756 757 resources = clientTable[client->index].resources; 758 for (i = 0; i < clientTable[client->index].buckets; i++) { 759 for (this = resources[i]; this; this = next) { 760 next = this->next; 761 if (!type || this->type == type) { 762 /* workaround func freeing the type as DRI1 does */ 763 value = this->value; 764 if((*func)(value, this->id, cdata)) 765 return value; 766 } 767 } 768 } 769 return NULL; 770} 771 772 773void 774FreeClientNeverRetainResources(ClientPtr client) 775{ 776 ResourcePtr *resources; 777 ResourcePtr this; 778 ResourcePtr *prev; 779 int j, elements; 780 int *eltptr; 781 782 if (!client) 783 return; 784 785 resources = clientTable[client->index].resources; 786 eltptr = &clientTable[client->index].elements; 787 for (j=0; j < clientTable[client->index].buckets; j++) 788 { 789 prev = &resources[j]; 790 while ( (this = *prev) ) 791 { 792 RESTYPE rtype = this->type; 793 if (rtype & RC_NEVERRETAIN) 794 { 795#ifdef XSERVER_DTRACE 796 XSERVER_RESOURCE_FREE(this->id, this->type, 797 this->value, TypeNameString(this->type)); 798#endif 799 *prev = this->next; 800 clientTable[client->index].elements--; 801 802 CallResourceStateCallback(ResourceStateFreeing, this); 803 804 elements = *eltptr; 805 (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id); 806 free(this); 807 if (*eltptr != elements) 808 prev = &resources[j]; /* prev may no longer be valid */ 809 } 810 else 811 prev = &this->next; 812 } 813 } 814} 815 816void 817FreeClientResources(ClientPtr client) 818{ 819 ResourcePtr *resources; 820 ResourcePtr this; 821 int j; 822 823 /* This routine shouldn't be called with a null client, but just in 824 case ... */ 825 826 if (!client) 827 return; 828 829 HandleSaveSet(client); 830 831 resources = clientTable[client->index].resources; 832 for (j=0; j < clientTable[client->index].buckets; j++) 833 { 834 /* It may seem silly to update the head of this resource list as 835 we delete the members, since the entire list will be deleted any way, 836 but there are some resource deletion functions "FreeClientPixels" for 837 one which do a LookupID on another resource id (a Colormap id in this 838 case), so the resource list must be kept valid up to the point that 839 it is deleted, so every time we delete a resource, we must update the 840 head, just like in FreeResource. I hope that this doesn't slow down 841 mass deletion appreciably. PRH */ 842 843 ResourcePtr *head; 844 845 head = &resources[j]; 846 847 for (this = *head; this; this = *head) 848 { 849 RESTYPE rtype = this->type; 850#ifdef XSERVER_DTRACE 851 XSERVER_RESOURCE_FREE(this->id, this->type, 852 this->value, TypeNameString(this->type)); 853#endif 854 *head = this->next; 855 clientTable[client->index].elements--; 856 857 CallResourceStateCallback(ResourceStateFreeing, this); 858 859 (*resourceTypes[rtype & TypeMask].deleteFunc)(this->value, this->id); 860 free(this); 861 } 862 } 863 free(clientTable[client->index].resources); 864 clientTable[client->index].resources = NULL; 865 clientTable[client->index].buckets = 0; 866} 867 868void 869FreeAllResources(void) 870{ 871 int i; 872 873 for (i = currentMaxClients; --i >= 0; ) 874 { 875 if (clientTable[i].buckets) 876 FreeClientResources(clients[i]); 877 } 878} 879 880Bool 881LegalNewID(XID id, ClientPtr client) 882{ 883 pointer val; 884 int rc; 885 886#ifdef PANORAMIX 887 XID minid, maxid; 888 889 if (!noPanoramiXExtension) { 890 minid = client->clientAsMask | (client->index ? 891 SERVER_BIT : SERVER_MINID); 892 maxid = (clientTable[client->index].fakeID | RESOURCE_ID_MASK) + 1; 893 if ((id >= minid) && (id <= maxid)) 894 return TRUE; 895 } 896#endif /* PANORAMIX */ 897 if (client->clientAsMask == (id & ~RESOURCE_ID_MASK)) 898 { 899 if (clientTable[client->index].expectID <= id) 900 return TRUE; 901 902 rc = dixLookupResourceByClass(&val, id, RC_ANY, serverClient, 903 DixGetAttrAccess); 904 return rc == BadValue; 905 } 906 return FALSE; 907} 908 909int 910dixLookupResourceByType(pointer *result, XID id, RESTYPE rtype, 911 ClientPtr client, Mask mode) 912{ 913 int cid = CLIENT_ID(id); 914 ResourcePtr res = NULL; 915 916 *result = NULL; 917 if ((rtype & TypeMask) > lastResourceType) 918 return BadImplementation; 919 920 if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { 921 res = clientTable[cid].resources[Hash(cid, id)]; 922 923 for (; res; res = res->next) 924 if (res->id == id && res->type == rtype) 925 break; 926 } 927 if (!res) 928 return resourceTypes[rtype & TypeMask].errorValue; 929 930 if (client) { 931 client->errorValue = id; 932 cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, 933 res->value, RT_NONE, NULL, mode); 934 if (cid == BadValue) 935 return resourceTypes[rtype & TypeMask].errorValue; 936 if (cid != Success) 937 return cid; 938 } 939 940 *result = res->value; 941 return Success; 942} 943 944int 945dixLookupResourceByClass(pointer *result, XID id, RESTYPE rclass, 946 ClientPtr client, Mask mode) 947{ 948 int cid = CLIENT_ID(id); 949 ResourcePtr res = NULL; 950 951 *result = NULL; 952 953 if ((cid < MAXCLIENTS) && clientTable[cid].buckets) { 954 res = clientTable[cid].resources[Hash(cid, id)]; 955 956 for (; res; res = res->next) 957 if (res->id == id && (res->type & rclass)) 958 break; 959 } 960 if (!res) 961 return BadValue; 962 963 if (client) { 964 client->errorValue = id; 965 cid = XaceHook(XACE_RESOURCE_ACCESS, client, id, res->type, 966 res->value, RT_NONE, NULL, mode); 967 if (cid != Success) 968 return cid; 969 } 970 971 *result = res->value; 972 return Success; 973} 974