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