[comp.windows.x] V11 fix #28, server/dix/resource.c, FreeResource won't free all classes of a resource

RWS@ZERMATT.LCS.MIT.EDU (Robert Scheifler) (10/22/87)

    Date: Thu, 15 Oct 87 11:26:04 PDT
    From: deboor%sloth.Berkeley.EDU@berkeley.edu (Adam de Boor)

    SYNOPSIS:
	    If there is more than one class of resource under a given resource
	    ID, FreeResource() will only free the first resource it encounters.
    DESCRIPTION:
	    Because FreeResource() breaks out of the loop once it has freed a single
	    resource, rather than proceeding to the end of the chain, if there
	    is more than one class for a single resource id (as is done for
	    windows in the sun server), the previous resource will remain.
    FIX:
	It should be noted as a caveat that the DeleteFunc for a resource is not
	allowed to call AddResource (although it is permitted to recall FreeResource).

	in server/dix/resource.c:

*** /tmp/,RCSt1003320	Thu Oct 22 08:14:34 1987
--- resource.c	Wed Oct 21 09:26:27 1987
***************
*** 22,28 ****
  
  ********************************************************/
  
! /* $Header: resource.c,v 1.62 87/09/04 11:45:57 toddb Exp $ */
  
  /*	Routines to manage various kinds of resources:
   *
--- 22,28 ----
  
  ********************************************************/
  
! /* $Header: resource.c,v 1.63 87/10/21 09:25:11 rws Exp $ */
  
  /*	Routines to manage various kinds of resources:
   *
***************
*** 223,251 ****
  {
      unsigned    cid;
      register    ResourcePtr res;
!     ResourcePtr * head;
!     Bool gotOne = FALSE;
  
      if (((cid = CLIENT_ID(id)) < MaxClients) && clientTable[cid].buckets)
      {
  	head = &clientTable[cid].resources[Hash(cid, id)];
  
! 	for (res = *head; res; res = *head)
  	{
  	    if (res->id == id)
  	    {
! 		*head = res->next;
! 		clientTable[cid].elements--;
  		if (res->type & CACHEDTYPES)
  		    FlushClientCaches(res->id);
  		if (skipDeleteFuncClass != res->class)
  		    (*res->DeleteFunc) (res->value, res->id);
  		Xfree(res);
  		gotOne = TRUE;
- 		break;
  	    }
  	    else
! 		head = &res->next;
          }
  	if(clients[cid] && (id == clients[cid]->lastDrawableID))
  	    clients[cid]->lastDrawableID = INVALID;
--- 223,256 ----
  {
      unsigned    cid;
      register    ResourcePtr res;
!     register	ResourcePtr *prev, *head;
!     register	int *eltptr;
!     int		elements;
!     Bool	gotOne = FALSE;
  
      if (((cid = CLIENT_ID(id)) < MaxClients) && clientTable[cid].buckets)
      {
  	head = &clientTable[cid].resources[Hash(cid, id)];
+ 	eltptr = &clientTable[cid].elements;
  
! 	prev = head;
! 	while (res = *prev)
  	{
  	    if (res->id == id)
  	    {
! 		*prev = res->next;
! 		elements = --*eltptr;
  		if (res->type & CACHEDTYPES)
  		    FlushClientCaches(res->id);
  		if (skipDeleteFuncClass != res->class)
  		    (*res->DeleteFunc) (res->value, res->id);
  		Xfree(res);
+ 		if (*eltptr != elements)
+ 		    prev = head; /* prev may no longer be valid */
  		gotOne = TRUE;
  	    }
  	    else
! 		prev = &res->next;
          }
  	if(clients[cid] && (id == clients[cid]->lastDrawableID))
  	    clients[cid]->lastDrawableID = INVALID;