|
|
1.1 root 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: /* $Header: resource.c,v 1.62 87/09/04 11:45:57 toddb Exp $ */
26:
27: /* Routines to manage various kinds of resources:
28: *
29: * CreateNewResourceType, CreateNewResourceClass, InitClientResources,
30: * FakeClientID, AddResource, FreeResource, FreeClientResources,
31: * FreeAllResources, LookupID
32: */
33:
34: /*
35: * a resource is a 32 bit quantity. the upper 12 bits are client id.
36: * client provides a 19 bit resource id. this is "hashed" by me by
37: * taking the 10 lower bits and xor'ing with the mid 10 bits.
38: *
39: * It is sometimes necessary for the server to create an ID that looks
40: * like it belongs to a client. This ID, however, must not be one
41: * the client actually can create, or we have the potential for conflict.
42: * The 20th bit of the ID is resevered for the server's use for this
43: * purpose. By setting CLIENT_ID(id) to the client, the SERVER_BIT to
44: * 1, and an otherwise unused ID in the low 19 bits, we can create a
45: * resource "owned" by the client.
46: *
47: * The following IDs are currently reserved for siccing on the client:
48: * 1 - allocated color to be freed when the client dies
49: */
50:
51: #include "X.h"
52: #include "misc.h"
53: #include "os.h"
54: #include "resource.h"
55: #include "dixstruct.h"
56: #include "opaque.h"
57:
58: #define CACHEDTYPES (RT_WINDOW | RT_PIXMAP | RT_GC)
59: #define INITBUCKETS 64
60: #define INITHASHSIZE 6
61: #define MAXHASHSIZE 11
62:
63: typedef struct _Resource {
64: struct _Resource *next;
65: XID id;
66: int (*DeleteFunc)();
67: unsigned short type;
68: unsigned short class;
69: pointer value;
70: } ResourceRec, *ResourcePtr;
71: #define NullResource ((ResourcePtr)NULL)
72:
73: typedef struct _ClientResource {
74: ResourcePtr *resources;
75: int elements;
76: int buckets;
77: int hashsize; /* log(2)(buckets) */
78: int fakeID;
79: } ClientResourceRec;
80:
81: static unsigned short lastResourceType;
82: static unsigned short lastResourceClass;
83:
84: unsigned short
85: CreateNewResourceType()
86: {
87: if (lastResourceType == 0x8000) /* this is compiler dependent XXX */
88: lastResourceType = 0;
89: lastResourceType <<= 1;
90: return lastResourceType;
91: }
92:
93: short
94: CreateNewResourceClass()
95: {
96: return ++lastResourceClass;
97: }
98:
99: ClientResourceRec clientTable[MAXCLIENTS];
100:
101: /*****************
102: * InitClientResources
103: * When a new client is created, call this to allocate space
104: * in resource table
105: *****************/
106:
107: InitClientResources(client)
108: ClientPtr client;
109: {
110: register int i, j;
111:
112: if (client == serverClient)
113: {
114: lastResourceType = RT_LASTPREDEF;
115: lastResourceClass = RC_LASTPREDEF;
116: }
117: clientTable[i = client->index].resources =
118: (ResourcePtr *)Xalloc(INITBUCKETS*sizeof(ResourcePtr));
119: clientTable[i].buckets = INITBUCKETS;
120: clientTable[i].elements = 0;
121: clientTable[i].hashsize = INITHASHSIZE;
122: clientTable[i].fakeID = 100;
123: for (j=0; j<INITBUCKETS; j++)
124: {
125: clientTable[i].resources[j] = NullResource;
126: }
127: }
128:
129: static int
130: Hash(client, id)
131: int client;
132: register int id;
133: {
134: id &= RESOURCE_ID_MASK;
135: switch (clientTable[client].hashsize)
136: {
137: case 6:
138: return 0x03F & (id ^ (id>>6) ^ (id>>12));
139: case 7:
140: return 0x07F & (id ^ (id>>7) ^ (id>>13));
141: case 8:
142: return 0x0FF & (id ^ (id>>8) ^ (id>>16));
143: case 9:
144: return 0x1FF & (id ^ (id>>9));
145: case 10:
146: return 0x3FF & (id ^ (id>>10));
147: case 11:
148: return 0x7FF & (id ^ (id>>11));
149: }
150: return -1;
151: }
152:
153: int
154: FakeClientID(client)
155: int client;
156: {
157: return (
158: (client<<CLIENTOFFSET) + (SERVER_BIT) +
159: ((clientTable[client].fakeID++) & RESOURCE_ID_MASK));
160: }
161:
162: void
163: AddResource(id, type, value, func, class)
164: int id;
165: unsigned short type, class;
166: pointer value;
167: int (* func)();
168: {
169: int client, j;
170: ResourcePtr res, next, *head;
171:
172: client = CLIENT_ID(id);
173: if (!clientTable[client].buckets)
174: {
175: ErrorF("AddResource(%x, %d, %x, %d), client=%d \n",
176: id, type, value, class, client);
177: FatalError("client not in use\n");
178: }
179: if (!func)
180: {
181: ErrorF("AddResource(%x, %d, %x, %d), client=%d \n",
182: id, type, value, class, client);
183: FatalError("No delete function given to AddResource \n");
184: }
185: if ((clientTable[client].elements >= 4*clientTable[client].buckets) &&
186: (clientTable[client].hashsize <= MAXHASHSIZE))
187: {
188: register ResourcePtr *resources = (ResourcePtr *)
189: Xalloc(2*clientTable[client].buckets*sizeof(ResourcePtr));
190: for (j = 0; j < clientTable[client].buckets*2; j++)
191: resources[j] = NullResource;
192: clientTable[client].hashsize++;
193: for (j = 0; j < clientTable[client].buckets; j++)
194: {
195: for (res = clientTable[client].resources[j]; res; res = next)
196: {
197: next = res->next;
198: head = &resources[Hash(client, res->id)];
199: res->next = *head;
200: *head = res;
201: }
202: }
203: clientTable[client].buckets *= 2;
204: Xfree(clientTable[client].resources);
205: clientTable[client].resources = resources;
206: }
207: head = &clientTable[client].resources[Hash(client, id)];
208: res = (ResourcePtr)Xalloc(sizeof(ResourceRec));
209: res->next = *head;
210: res->id = id;
211: res->DeleteFunc = func;
212: res->type = type;
213: res->class = class;
214: res->value = value;
215: *head = res;
216: clientTable[client].elements++;
217: }
218:
219: void
220: FreeResource(id, skipDeleteFuncClass)
221: int id, skipDeleteFuncClass;
222:
223: {
224: unsigned cid;
225: register ResourcePtr res;
226: ResourcePtr * head;
227: Bool gotOne = FALSE;
228:
229: if (((cid = CLIENT_ID(id)) < MaxClients) && clientTable[cid].buckets)
230: {
231: head = &clientTable[cid].resources[Hash(cid, id)];
232:
233: for (res = *head; res; res = *head)
234: {
235: if (res->id == id)
236: {
237: *head = res->next;
238: clientTable[cid].elements--;
239: if (res->type & CACHEDTYPES)
240: FlushClientCaches(res->id);
241: if (skipDeleteFuncClass != res->class)
242: (*res->DeleteFunc) (res->value, res->id);
243: Xfree(res);
244: gotOne = TRUE;
245: break;
246: }
247: else
248: head = &res->next;
249: }
250: if(clients[cid] && (id == clients[cid]->lastDrawableID))
251: clients[cid]->lastDrawableID = INVALID;
252: }
253: if (!gotOne)
254: FatalError("Freeing resource id=%X which isn't there", id);
255: }
256:
257: void
258: FreeClientResources(client)
259: ClientPtr client;
260: {
261: register ResourcePtr *resources;
262: register ResourcePtr this;
263: int j;
264:
265: /* This routine shouldn't be called with a null client, but just in
266: case ... */
267:
268: if (!client)
269: return;
270:
271: HandleSaveSet(client);
272:
273: resources = clientTable[client->index].resources;
274: for (j=0; j < clientTable[client->index].buckets; j++)
275: {
276: /* It may seem silly to update the head of this resource list as
277: we delete the members, since the entire list will be deleted any way,
278: but there are some resource deletion functions "FreeClientPixels" for
279: one which do a LookupID on another resource id (a Colormap id in this
280: case), so the resource list must be kept valid up to the point that
281: it is deleted, so every time we delete a resource, we must update the
282: head, just like in FreeResource. I hope that this doesn't slow down
283: mass deletion appreciably. PRH */
284:
285: ResourcePtr *head;
286:
287: head = &resources[j];
288:
289: for (this = *head; this; this = *head)
290: {
291: *head = this->next;
292: if (this->type & CACHEDTYPES)
293: FlushClientCaches(this->id);
294: (*this->DeleteFunc)(this->value, this->id);
295: Xfree(this);
296: }
297: }
298: Xfree(clientTable[client->index].resources);
299: clientTable[client->index].buckets = 0;
300: }
301:
302: FreeAllResources()
303: {
304: int i;
305:
306: for (i=0; i<currentMaxClients; i++)
307: {
308: if (clientTable[i].buckets)
309: FreeClientResources(clients[i]);
310: }
311: }
312:
313: /*
314: * LookupID returns the value field in the resource or NULL
315: * if an illegal id was handed to it or given type doesn't match the
316: * type for this id and class.
317: */
318: pointer
319: LookupID(id, rType, class)
320: unsigned int id;
321: unsigned short rType, class;
322: {
323: unsigned cid;
324: register ResourcePtr res;
325:
326: if (((cid = CLIENT_ID(id)) < MaxClients) && clientTable[cid].buckets)
327: {
328: res = clientTable[cid].resources[Hash(cid, id)];
329:
330: for (; res; res = res->next)
331: if ((res->id == id) && (res->class == class))
332: if (res->type & rType)
333: return res->value;
334: else
335: return(pointer) NULL;
336: }
337: return(pointer) NULL;
338: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.