home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / server / dix / resource.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-21  |  15.6 KB  |  600 lines

  1. /************************************************************
  2. Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
  3. and the Massachusetts Institute of Technology, Cambridge, Massachusetts.
  4.  
  5.                         All Rights Reserved
  6.  
  7. Permission to use, copy, modify, and distribute this software and its 
  8. documentation for any purpose and without fee is hereby granted, 
  9. provided that the above copyright notice appear in all copies and that
  10. both that copyright notice and this permission notice appear in 
  11. supporting documentation, and that the names of Digital or MIT not be
  12. used in advertising or publicity pertaining to distribution of the
  13. software without specific, written prior permission.  
  14.  
  15. DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  16. ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  17. DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  18. ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  19. WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  20. ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  21. SOFTWARE.
  22.  
  23. ********************************************************/
  24.  
  25. /* $XConsortium: resource.c,v 1.87 91/10/30 14:50:54 rws Exp $ */
  26.  
  27. /*    Routines to manage various kinds of resources:
  28.  *
  29.  *    CreateNewResourceType, CreateNewResourceClass, InitClientResources,
  30.  *    FakeClientID, AddResource, FreeResource, FreeClientResources,
  31.  *    FreeAllResources, LookupIDByType, LookupIDByClass
  32.  */
  33.  
  34. /* 
  35.  *      A resource ID is a 32 bit quantity, the upper 3 bits of which are
  36.  *    off-limits for client-visible resources.  The next 7 bits are
  37.  *      used as client ID, and the low 22 bits come from the client.
  38.  *    A resource ID is "hashed" by extracting and xoring subfields
  39.  *      (varying with the size of the hash table).
  40.  *
  41.  *      It is sometimes necessary for the server to create an ID that looks
  42.  *      like it belongs to a client.  This ID, however,  must not be one
  43.  *      the client actually can create, or we have the potential for conflict.
  44.  *      The 30th bit of the ID is reserved for the server's use for this
  45.  *      purpose.  By setting CLIENT_ID(id) to the client, the SERVER_BIT to
  46.  *      1, and an otherwise arbitrary ID in the low 22 bits, we can create a
  47.  *      resource "owned" by the client.
  48.  */
  49.  
  50. #include "X.h"
  51. #include "misc.h"
  52. #include "os.h"
  53. #include "resource.h"
  54. #include "dixstruct.h" 
  55. #include "opaque.h"
  56. #include "windowstr.h"
  57.  
  58. extern void HandleSaveSet();
  59. extern void FlushClientCaches();
  60. static void RebuildTable();
  61. extern WindowPtr *WindowTable;
  62.  
  63. #define SERVER_MINID 32
  64.  
  65. #define INITBUCKETS 64
  66. #define INITHASHSIZE 6
  67. #define MAXHASHSIZE 11
  68.  
  69. typedef struct _Resource {
  70.     struct _Resource    *next;
  71.     XID            id;
  72.     RESTYPE        type;
  73.     pointer        value;
  74. } ResourceRec, *ResourcePtr;
  75. #define NullResource ((ResourcePtr)NULL)
  76.  
  77. typedef struct _ClientResource {
  78.     ResourcePtr *resources;
  79.     int        elements;
  80.     int        buckets;
  81.     int        hashsize;    /* log(2)(buckets) */
  82.     XID        fakeID;
  83.     XID        endFakeID;
  84.     XID        expectID;
  85. } ClientResourceRec;
  86.  
  87. static RESTYPE lastResourceType;
  88. static RESTYPE lastResourceClass;
  89. static RESTYPE TypeMask;
  90.  
  91. typedef int (*DeleteType)();
  92.  
  93. static DeleteType *DeleteFuncs = (DeleteType *)NULL;
  94.  
  95. RESTYPE
  96. CreateNewResourceType(deleteFunc)
  97.     DeleteType deleteFunc;
  98. {
  99.     RESTYPE next = lastResourceType + 1;
  100.     DeleteType *funcs;
  101.  
  102.     if (next & lastResourceClass)
  103.     return 0;
  104.     funcs = (DeleteType *)xrealloc(DeleteFuncs,
  105.                    (next + 1) * sizeof(DeleteType));
  106.     if (!funcs)
  107.     return 0;
  108.     lastResourceType = next;
  109.     DeleteFuncs = funcs;
  110.     DeleteFuncs[next] = deleteFunc;
  111.     return next;
  112. }
  113.  
  114. RESTYPE
  115. CreateNewResourceClass()
  116. {
  117.     RESTYPE next = lastResourceClass >> 1;
  118.  
  119.     if (next & lastResourceType)
  120.     return 0;
  121.     lastResourceClass = next;
  122.     TypeMask = next - 1;
  123.     return next;
  124. }
  125.  
  126. ClientResourceRec clientTable[MAXCLIENTS];
  127.  
  128. /*****************
  129.  * InitClientResources
  130.  *    When a new client is created, call this to allocate space
  131.  *    in resource table
  132.  *****************/
  133.  
  134. Bool
  135. InitClientResources(client)
  136.     ClientPtr client;
  137. {
  138.     register int i, j;
  139.  
  140.     if (client == serverClient)
  141.     {
  142.     extern int DeleteWindow(), dixDestroyPixmap(), FreeGC();
  143.     extern int CloseFont(), FreeCursor();
  144.     extern int FreeColormap(), FreeClientPixels();
  145.     extern int OtherClientGone(), DeletePassiveGrab();
  146.  
  147.     lastResourceType = RT_LASTPREDEF;
  148.     lastResourceClass = RC_LASTPREDEF;
  149.     TypeMask = RC_LASTPREDEF - 1;
  150.     if (DeleteFuncs)
  151.         xfree(DeleteFuncs);
  152.     DeleteFuncs = (DeleteType *)xalloc((lastResourceType + 1) *
  153.                        sizeof(DeleteType));
  154.     if (!DeleteFuncs)
  155.         return FALSE;
  156.     DeleteFuncs[RT_NONE & TypeMask] = (int (*)()) NoopDDA;
  157.     DeleteFuncs[RT_WINDOW & TypeMask] = DeleteWindow;
  158.     DeleteFuncs[RT_PIXMAP & TypeMask] = dixDestroyPixmap;
  159.     DeleteFuncs[RT_GC & TypeMask] = FreeGC;
  160.     DeleteFuncs[RT_FONT & TypeMask] = CloseFont;
  161.     DeleteFuncs[RT_CURSOR & TypeMask] = FreeCursor;
  162.     DeleteFuncs[RT_COLORMAP & TypeMask] = FreeColormap;
  163.     DeleteFuncs[RT_CMAPENTRY & TypeMask] = FreeClientPixels;
  164.     DeleteFuncs[RT_OTHERCLIENT & TypeMask] = OtherClientGone;
  165.     DeleteFuncs[RT_PASSIVEGRAB & TypeMask] = DeletePassiveGrab;
  166.     }
  167.     clientTable[i = client->index].resources =
  168.     (ResourcePtr *)xalloc(INITBUCKETS*sizeof(ResourcePtr));
  169.     if (!clientTable[i].resources)
  170.     return FALSE;
  171.     clientTable[i].buckets = INITBUCKETS;
  172.     clientTable[i].elements = 0;
  173.     clientTable[i].hashsize = INITHASHSIZE;
  174.     /* Many IDs allocated from the server client are visible to clients,
  175.      * so we don't use the SERVER_BIT for them, but we have to start
  176.      * past the magic value constants used in the protocol.  For normal
  177.      * clients, we can start from zero, with SERVER_BIT set.
  178.      */
  179.     clientTable[i].fakeID = client->clientAsMask |
  180.                 (client->index ? SERVER_BIT : SERVER_MINID);
  181.     clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1;
  182.     clientTable[i].expectID = client->clientAsMask;
  183.     for (j=0; j<INITBUCKETS; j++) 
  184.     {
  185.         clientTable[i].resources[j] = NullResource;
  186.     }
  187.     return TRUE;
  188. }
  189.  
  190. static int
  191. Hash(client, id)
  192.     int client;
  193.     register XID id;
  194. {
  195.     id &= RESOURCE_ID_MASK;
  196.     switch (clientTable[client].hashsize)
  197.     {
  198.     case 6:
  199.         return ((int)(0x03F & (id ^ (id>>6) ^ (id>>12))));
  200.     case 7:
  201.         return ((int)(0x07F & (id ^ (id>>7) ^ (id>>13))));
  202.     case 8:
  203.         return ((int)(0x0FF & (id ^ (id>>8) ^ (id>>16))));
  204.     case 9:
  205.         return ((int)(0x1FF & (id ^ (id>>9))));
  206.     case 10:
  207.         return ((int)(0x3FF & (id ^ (id>>10))));
  208.     case 11:
  209.         return ((int)(0x7FF & (id ^ (id>>11))));
  210.     }
  211.     return -1;
  212. }
  213.  
  214. static XID
  215. AvailableID(client, id, maxid, goodid)
  216.     register int client;
  217.     register XID id, maxid, goodid;
  218. {
  219.     register ResourcePtr res;
  220.  
  221.     if ((goodid >= id) && (goodid <= maxid))
  222.     return goodid;
  223.     for (; id <= maxid; id++)
  224.     {
  225.     res = clientTable[client].resources[Hash(client, id)];
  226.     while (res && (res->id != id))
  227.         res = res->next;
  228.     if (!res)
  229.         return id;
  230.     }
  231.     return 0;
  232. }
  233.  
  234. /*
  235.  * Return the next usable fake client ID.
  236.  *
  237.  * Normally this is just the next one in line, but if we've used the last
  238.  * in the range, we need to find a new range of safe IDs to avoid
  239.  * over-running another client.
  240.  */
  241.  
  242. XID
  243. FakeClientID(client)
  244.     register int client;
  245. {
  246.     register XID id, maxid;
  247.     register ResourcePtr *resp;
  248.     register ResourcePtr res;
  249.     register int i;
  250.     XID goodid;
  251.  
  252.     id = clientTable[client].fakeID++;
  253.     if (id != clientTable[client].endFakeID)
  254.     return id;
  255.     id = ((Mask)client << CLIENTOFFSET) | (client ? SERVER_BIT : SERVER_MINID);
  256.     maxid = id | RESOURCE_ID_MASK;
  257.     goodid = 0;
  258.     for (resp = clientTable[client].resources, i = clientTable[client].buckets;
  259.      --i >= 0;)
  260.     {
  261.     for (res = *resp++; res; res = res->next)
  262.     {
  263.         if ((res->id < id) || (res->id > maxid))
  264.         continue;
  265.         if (((res->id - id) >= (maxid - res->id)) ?
  266.         (goodid = AvailableID(client, id, res->id - 1, goodid)) :
  267.         !(goodid = AvailableID(client, res->id + 1, maxid, goodid)))
  268.         maxid = res->id - 1;
  269.         else
  270.         id = res->id + 1;
  271.     }
  272.     }
  273.     if (id > maxid) {
  274.     if (!client)
  275.         FatalError("FakeClientID: server internal ids exhausted\n");
  276.     MarkClientException(clients[client]);
  277.     id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3);
  278.     maxid = id | RESOURCE_ID_MASK;
  279.     }
  280.     clientTable[client].fakeID = id + 1;
  281.     clientTable[client].endFakeID = maxid + 1;
  282.     return id;
  283. }
  284.  
  285. Bool
  286. AddResource(id, type, value)
  287.     XID id;
  288.     RESTYPE type;
  289.     pointer value;
  290. {
  291.     int client;
  292.     register ClientResourceRec *rrec;
  293.     register ResourcePtr res, *head;
  294.         
  295.     client = CLIENT_ID(id);
  296.     rrec = &clientTable[client];
  297.     if (!rrec->buckets)
  298.     {
  299.     ErrorF("AddResource(%x, %x, %x), client=%d \n",
  300.         id, type, (unsigned long)value, client);
  301.         FatalError("client not in use\n");
  302.     }
  303.     if ((rrec->elements >= 4*rrec->buckets) &&
  304.     (rrec->hashsize < MAXHASHSIZE))
  305.     RebuildTable(client);
  306.     head = &rrec->resources[Hash(client, id)];
  307.     res = (ResourcePtr)xalloc(sizeof(ResourceRec));
  308.     if (!res)
  309.     {
  310.     (*DeleteFuncs[type & TypeMask])(value, id);
  311.     return FALSE;
  312.     }
  313.     res->next = *head;
  314.     res->id = id;
  315.     res->type = type;
  316.     res->value = value;
  317.     *head = res;
  318.     rrec->elements++;
  319.     if (!(id & SERVER_BIT) && (id >= rrec->expectID))
  320.     rrec->expectID = id + 1;
  321.     return TRUE;
  322. }
  323.  
  324. static void
  325. RebuildTable(client)
  326.     int client;
  327. {
  328.     register int j;
  329.     register ResourcePtr res, next;
  330.     ResourcePtr **tails, *resources;
  331.     register ResourcePtr **tptr, *rptr;
  332.  
  333.     /*
  334.      * For now, preserve insertion order, since some ddx layers depend
  335.      * on resources being free in the opposite order they are added.
  336.      */
  337.  
  338.     j = 2 * clientTable[client].buckets;
  339.     tails = (ResourcePtr **)ALLOCATE_LOCAL(j * sizeof(ResourcePtr *));
  340.     if (!tails)
  341.     return;
  342.     resources = (ResourcePtr *)xalloc(j * sizeof(ResourcePtr));
  343.     if (!resources)
  344.     {
  345.     DEALLOCATE_LOCAL(tails);
  346.     return;
  347.     }
  348.     for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++)
  349.     {
  350.     *rptr = NullResource;
  351.     *tptr = rptr;
  352.     }
  353.     clientTable[client].hashsize++;
  354.     for (j = clientTable[client].buckets,
  355.      rptr = clientTable[client].resources;
  356.      --j >= 0;
  357.      rptr++)
  358.     {
  359.     for (res = *rptr; res; res = next)
  360.     {
  361.         next = res->next;
  362.         res->next = NullResource;
  363.         tptr = &tails[Hash(client, res->id)];
  364.         **tptr = res;
  365.         *tptr = &res->next;
  366.     }
  367.     }
  368.     DEALLOCATE_LOCAL(tails);
  369.     clientTable[client].buckets *= 2;
  370.     xfree(clientTable[client].resources);
  371.     clientTable[client].resources = resources;
  372. }
  373.  
  374. void
  375. FreeResource(id, skipDeleteFuncType)
  376.     XID id;
  377.     RESTYPE skipDeleteFuncType;
  378. {
  379.     int        cid;
  380.     register    ResourcePtr res;
  381.     register    ResourcePtr *prev, *head;
  382.     register    int *eltptr;
  383.     int        elements;
  384.     Bool    gotOne = FALSE;
  385.  
  386.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  387.     {
  388.     head = &clientTable[cid].resources[Hash(cid, id)];
  389.     eltptr = &clientTable[cid].elements;
  390.  
  391.     prev = head;
  392.     while (res = *prev)
  393.     {
  394.         if (res->id == id)
  395.         {
  396.         RESTYPE rtype = res->type;
  397.         *prev = res->next;
  398.         elements = --*eltptr;
  399.         if (rtype & RC_CACHED)
  400.             FlushClientCaches(res->id);
  401.         if (rtype != skipDeleteFuncType)
  402.             (*DeleteFuncs[rtype & TypeMask])(res->value, res->id);
  403.         xfree(res);
  404.         if (*eltptr != elements)
  405.             prev = head; /* prev may no longer be valid */
  406.         gotOne = TRUE;
  407.         }
  408.         else
  409.         prev = &res->next;
  410.         }
  411.     if(clients[cid] && (id == clients[cid]->lastDrawableID))
  412.     {
  413.         clients[cid]->lastDrawable = (DrawablePtr)WindowTable[0];
  414.         clients[cid]->lastDrawableID = WindowTable[0]->drawable.id;
  415.     }
  416.     }
  417.     if (!gotOne)
  418.     FatalError("Freeing resource id=%X which isn't there", id);
  419. }
  420. void
  421. FreeResourceByType(id, type, skipFree)
  422.     XID id;
  423.     RESTYPE type;
  424.     Bool    skipFree;
  425. {
  426.     int        cid;
  427.     register    ResourcePtr res;
  428.     register    ResourcePtr *prev, *head;
  429.  
  430.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  431.     {
  432.     head = &clientTable[cid].resources[Hash(cid, id)];
  433.  
  434.     prev = head;
  435.     while (res = *prev)
  436.     {
  437.         if (res->id == id && res->type == type)
  438.         {
  439.         *prev = res->next;
  440.         if (type & RC_CACHED)
  441.             FlushClientCaches(res->id);
  442.         if (!skipFree)
  443.             (*DeleteFuncs[type & TypeMask])(res->value, res->id);
  444.         xfree(res);
  445.         break;
  446.         }
  447.         else
  448.         prev = &res->next;
  449.         }
  450.     if(clients[cid] && (id == clients[cid]->lastDrawableID))
  451.     {
  452.         clients[cid]->lastDrawable = (DrawablePtr)WindowTable[0];
  453.         clients[cid]->lastDrawableID = WindowTable[0]->drawable.id;
  454.     }
  455.     }
  456. }
  457.  
  458. /*
  459.  * Change the value associated with a resource id.  Caller
  460.  * is responsible for "doing the right thing" with the old
  461.  * data
  462.  */
  463.  
  464. Bool
  465. ChangeResourceValue (id, rtype, value)
  466.     XID    id;
  467.     RESTYPE rtype;
  468.     pointer value;
  469. {
  470.     int    cid;
  471.     register    ResourcePtr res;
  472.  
  473.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  474.     {
  475.     res = clientTable[cid].resources[Hash(cid, id)];
  476.  
  477.     for (; res; res = res->next)
  478.         if ((res->id == id) && (res->type == rtype))
  479.         {
  480.         if (rtype & RC_CACHED)
  481.             FlushClientCaches(res->id);
  482.         res->value = value;
  483.         return TRUE;
  484.         }
  485.     }
  486.     return FALSE;
  487. }
  488.  
  489. void
  490. FreeClientResources(client)
  491.     ClientPtr client;
  492. {
  493.     register ResourcePtr *resources;
  494.     register ResourcePtr this;
  495.     int j;
  496.  
  497.     /* This routine shouldn't be called with a null client, but just in
  498.     case ... */
  499.  
  500.     if (!client)
  501.     return;
  502.  
  503.     HandleSaveSet(client);
  504.  
  505.     resources = clientTable[client->index].resources;
  506.     for (j=0; j < clientTable[client->index].buckets; j++) 
  507.     {
  508.         /* It may seem silly to update the head of this resource list as
  509.     we delete the members, since the entire list will be deleted any way, 
  510.     but there are some resource deletion functions "FreeClientPixels" for 
  511.     one which do a LookupID on another resource id (a Colormap id in this
  512.     case), so the resource list must be kept valid up to the point that
  513.     it is deleted, so every time we delete a resource, we must update the
  514.     head, just like in FreeResource. I hope that this doesn't slow down
  515.     mass deletion appreciably. PRH */
  516.  
  517.     ResourcePtr *head;
  518.  
  519.     head = &resources[j];
  520.  
  521.         for (this = *head; this; this = *head)
  522.     {
  523.         RESTYPE rtype = this->type;
  524.         *head = this->next;
  525.         if (rtype & RC_CACHED)
  526.         FlushClientCaches(this->id);
  527.         (*DeleteFuncs[rtype & TypeMask])(this->value, this->id);
  528.         xfree(this);        
  529.     }
  530.     }
  531.     xfree(clientTable[client->index].resources);
  532.     clientTable[client->index].buckets = 0;
  533. }
  534.  
  535. FreeAllResources()
  536. {
  537.     int    i;
  538.  
  539.     for (i=0; i<currentMaxClients; i++) 
  540.     {
  541.         if (clientTable[i].buckets) 
  542.         FreeClientResources(clients[i]);
  543.     }
  544. }
  545.  
  546. Bool
  547. LegalNewID(id, client)
  548.     XID id;
  549.     register ClientPtr client;
  550. {
  551.     return ((client->clientAsMask == (id & ~RESOURCE_ID_MASK)) &&
  552.         ((clientTable[client->index].expectID <= id) ||
  553.          !LookupIDByClass(id, RC_ANY)));
  554. }
  555.  
  556. /*
  557.  *  LookupIDByType returns the object with the given id and type, else NULL.
  558.  */ 
  559. pointer
  560. LookupIDByType(id, rtype)
  561.     XID id;
  562.     RESTYPE rtype;
  563. {
  564.     int    cid;
  565.     register    ResourcePtr res;
  566.  
  567.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  568.     {
  569.     res = clientTable[cid].resources[Hash(cid, id)];
  570.  
  571.     for (; res; res = res->next)
  572.         if ((res->id == id) && (res->type == rtype))
  573.         return res->value;
  574.     }
  575.     return (pointer)NULL;
  576. }
  577.  
  578. /*
  579.  *  LookupIDByClass returns the object with the given id and any one of the
  580.  *  given classes, else NULL.
  581.  */ 
  582. pointer
  583. LookupIDByClass(id, classes)
  584.     XID id;
  585.     RESTYPE classes;
  586. {
  587.     int    cid;
  588.     register    ResourcePtr res;
  589.  
  590.     if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets)
  591.     {
  592.     res = clientTable[cid].resources[Hash(cid, id)];
  593.  
  594.     for (; res; res = res->next)
  595.         if ((res->id == id) && (res->type & classes))
  596.         return res->value;
  597.     }
  598.     return (pointer)NULL;
  599. }
  600.