summaryrefslogtreecommitdiff
path: root/difs/resource.c
diff options
context:
space:
mode:
Diffstat (limited to 'difs/resource.c')
-rw-r--r--difs/resource.c569
1 files changed, 569 insertions, 0 deletions
diff --git a/difs/resource.c b/difs/resource.c
new file mode 100644
index 0000000..037b97f
--- /dev/null
+++ b/difs/resource.c
@@ -0,0 +1,569 @@
+/* $Xorg: resource.c,v 1.4 2001/02/09 02:05:42 xorgcvs Exp $ */
+/*
+Copyright 1987, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall not be
+used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization from The Open Group.
+ * Copyright 1990, 1991 Network Computing Devices;
+ * Portions Copyright 1987 by Digital Equipment Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the names of Network Computing Devices,
+ * or Digital not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. Network Computing Devices, or Digital
+ * make no representations about the
+ * suitability of this software for any purpose. It is provided "as is"
+ * without express or implied warranty.
+ *
+ * NETWORK COMPUTING DEVICES, AND DIGITAL DISCLAIM ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS, IN NO EVENT SHALL NETWORK COMPUTING DEVICES, OR DIGITAL BE
+ * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * %W% %G%
+ *
+ */
+/*
+ * a resource is a 32 bit quantity. the upper 12 bits are client id.
+ * client provides a 19 bit resource id. this is "hashed" by me by
+ * taking the 10 lower bits and xor'ing with the mid 10 bits.
+ *
+ * It is sometimes necessary for the server to create an ID that looks
+ * like it belongs to a client. This ID, however, must not be one
+ * the client actually can create, or we have the potential for conflict.
+ * The 20th bit of the ID is resevered for the server's use for this
+ * purpose. By setting CLIENT_ID(id) to the client, the SERVER_BIT to
+ * 1, and an otherwise unused ID in the low 19 bits, we can create a
+ * resource "owned" by the client.
+ *
+ * The following IDs are currently reserved for siccing on the client:
+ * 1 - allocated color to be freed when the client dies
+ */
+
+#include "FS.h"
+#include "misc.h"
+#include "os.h"
+#include "resource.h"
+#include "clientstr.h"
+#include "globals.h"
+
+static void rebuild_table();
+
+#define INITBUCKETS 64
+#define INITHASHSIZE 6
+#define MAXHASHSIZE 11
+
+typedef struct _Resource {
+ struct _Resource *next;
+ FSID id;
+ RESTYPE type;
+ pointer value;
+} ResourceRec, *ResourcePtr;
+
+#define NullResource ((ResourcePtr)NULL)
+
+typedef struct _ClientResource {
+ ResourcePtr *resources;
+ int elements;
+ int buckets;
+ int hashsize; /* log(2)(buckets) */
+ FSID fakeID;
+ FSID endFakeID;
+ FSID expectID;
+} ClientResourceRec;
+
+static RESTYPE lastResourceType;
+static RESTYPE lastResourceClass;
+static RESTYPE TypeMask;
+
+typedef int (*DeleteType) ();
+
+static DeleteType *DeleteFuncs = (DeleteType *) NULL;
+
+#ifdef NOTYET
+RESTYPE
+CreateNewResourceType(deleteFunc)
+ DeleteType deleteFunc;
+{
+ RESTYPE next = lastResourceType + 1;
+ DeleteType *funcs;
+
+ if (next & lastResourceClass)
+ return 0;
+ funcs = (DeleteType *) fsrealloc(DeleteFuncs,
+ (next + 1) * sizeof(DeleteType));
+ if (!funcs)
+ return 0;
+ lastResourceType = next;
+ DeleteFuncs = funcs;
+ DeleteFuncs[next] = deleteFunc;
+ return next;
+}
+
+RESTYPE
+CreateNewResourceClass()
+{
+ RESTYPE next = lastResourceClass >> 1;
+
+ if (next & lastResourceType)
+ return 0;
+ lastResourceClass = next;
+ TypeMask = next - 1;
+ return next;
+}
+
+#endif /* NOTYET */
+
+ClientResourceRec clientTable[MAXCLIENTS];
+
+/*****************
+ * InitClientResources
+ * When a new client is created, call this to allocate space
+ * in resource table
+ *****************/
+
+int
+NoneDeleteFunc ()
+{
+}
+
+Bool
+InitClientResources(client)
+ ClientPtr client;
+{
+ register int i,
+ j;
+
+ if (client == serverClient) {
+ extern int CloseClientFont();
+ extern int DeleteAuthCont ();
+
+ lastResourceType = RT_LASTPREDEF;
+ lastResourceClass = RC_LASTPREDEF;
+ TypeMask = RC_LASTPREDEF - 1;
+ if (DeleteFuncs)
+ fsfree(DeleteFuncs);
+ DeleteFuncs = (DeleteType *) fsalloc((lastResourceType + 1) *
+ sizeof(DeleteType));
+ if (!DeleteFuncs)
+ return FALSE;
+ DeleteFuncs[RT_NONE & TypeMask] = NoneDeleteFunc;
+ DeleteFuncs[RT_FONT & TypeMask] = CloseClientFont;
+ DeleteFuncs[RT_AUTHCONT & TypeMask] = DeleteAuthCont;
+ }
+ clientTable[i = client->index].resources =
+ (ResourcePtr *) fsalloc(INITBUCKETS * sizeof(ResourcePtr));
+ if (!clientTable[i].resources)
+ return FALSE;
+ clientTable[i].buckets = INITBUCKETS;
+ clientTable[i].elements = 0;
+ clientTable[i].hashsize = INITHASHSIZE;
+ clientTable[i].fakeID = SERVER_BIT;
+ clientTable[i].endFakeID = (clientTable[i].fakeID | RESOURCE_ID_MASK) + 1;
+ for (j = 0; j < INITBUCKETS; j++) {
+ clientTable[i].resources[j] = NullResource;
+ }
+ return TRUE;
+}
+
+static int
+hash(client, id)
+ int client;
+ register FSID id;
+{
+ id &= RESOURCE_ID_MASK;
+ switch (clientTable[client].hashsize) {
+ case 6:
+ return ((int) (0x03F & (id ^ (id >> 6) ^ (id >> 12))));
+ case 7:
+ return ((int) (0x07F & (id ^ (id >> 7) ^ (id >> 13))));
+ case 8:
+ return ((int) (0x0FF & (id ^ (id >> 8) ^ (id >> 16))));
+ case 9:
+ return ((int) (0x1FF & (id ^ (id >> 9))));
+ case 10:
+ return ((int) (0x3FF & (id ^ (id >> 10))));
+ case 11:
+ return ((int) (0x7FF & (id ^ (id >> 11))));
+ }
+ return -1;
+}
+
+
+static Font
+AvailableID(client, id, maxid, goodid)
+ register int client;
+ register FSID id, maxid, goodid;
+{
+ register ResourcePtr res;
+
+ if ((goodid >= id) && (goodid <= maxid))
+ return goodid;
+ for (; id <= maxid; id++)
+ {
+ res = clientTable[client].resources[hash(client, id)];
+ while (res && (res->id != id))
+ res = res->next;
+ if (!res)
+ return id;
+ }
+ return 0;
+}
+
+/*
+ * Return the next usable fake client ID.
+ *
+ * Normally this is just the next one in line, but if we've used the last
+ * in the range, we need to find a new range of safe IDs to avoid
+ * over-running another client.
+ */
+
+FSID
+FakeClientID(client)
+ int client;
+{
+ register FSID id, maxid;
+ register ResourcePtr *resp;
+ register ResourcePtr res;
+ register int i;
+ FSID goodid;
+
+ id = clientTable[client].fakeID++;
+ if (id != clientTable[client].endFakeID)
+ return id;
+ id = ((Mask)client << CLIENTOFFSET) | SERVER_BIT;
+ maxid = id | RESOURCE_ID_MASK;
+ goodid = 0;
+ for (resp = clientTable[client].resources, i = clientTable[client].buckets;
+ --i >= 0;)
+ {
+ for (res = *resp++; res; res = res->next)
+ {
+ if ((res->id < id) || (res->id > maxid))
+ continue;
+ if (((res->id - id) >= (maxid - res->id)) ?
+ (goodid = AvailableID(client, id, res->id - 1, goodid)) :
+ !(goodid = AvailableID(client, res->id + 1, maxid, goodid)))
+ maxid = res->id - 1;
+ else
+ id = res->id + 1;
+ }
+ }
+ if (id > maxid) {
+ if (!client)
+ FatalError("FakeClientID: server internal ids exhausted\n");
+ MarkClientException(clients[client]);
+ id = ((Mask)client << CLIENTOFFSET) | (SERVER_BIT * 3);
+ maxid = id | RESOURCE_ID_MASK;
+ }
+ clientTable[client].fakeID = id + 1;
+ clientTable[client].endFakeID = maxid + 1;
+ return id;
+}
+
+Bool
+AddResource(cid, id, type, value)
+ int cid;
+ FSID id;
+ RESTYPE type;
+ pointer value;
+{
+ register ClientResourceRec *rrec;
+ register ResourcePtr res,
+ *head;
+
+ rrec = &clientTable[cid];
+ if (!rrec->buckets) {
+ ErrorF("AddResource(%x, %x, %x), client=%d \n",
+ id, type, value, cid);
+ FatalError("client not in use\n");
+ }
+ if ((rrec->elements >= 4 * rrec->buckets) &&
+ (rrec->hashsize < MAXHASHSIZE))
+ rebuild_table(cid);
+ head = &rrec->resources[hash(cid, id)];
+ res = (ResourcePtr) fsalloc(sizeof(ResourceRec));
+ if (!res) {
+ (*DeleteFuncs[type & TypeMask]) (value, id);
+ return FALSE;
+ }
+ res->next = *head;
+ res->id = id;
+ res->type = type;
+ res->value = value;
+ *head = res;
+ rrec->elements++;
+ if (!(id & SERVER_BIT) && (id >= rrec->expectID))
+ rrec->expectID = id + 1;
+ return TRUE;
+}
+
+static void
+rebuild_table(client)
+ int client;
+{
+ register int j;
+ register ResourcePtr res,
+ next;
+ ResourcePtr **tails,
+ *resources;
+ register ResourcePtr **tptr,
+ *rptr;
+
+ /*
+ * For now, preserve insertion order, since some ddx layers depend on
+ * resources being free in the opposite order they are added.
+ */
+
+ j = 2 * clientTable[client].buckets;
+ tails = (ResourcePtr **) ALLOCATE_LOCAL(j * sizeof(ResourcePtr *));
+ if (!tails)
+ return;
+ resources = (ResourcePtr *) fsalloc(j * sizeof(ResourcePtr));
+ if (!resources) {
+ DEALLOCATE_LOCAL(tails);
+ return;
+ }
+ for (rptr = resources, tptr = tails; --j >= 0; rptr++, tptr++) {
+ *rptr = NullResource;
+ *tptr = rptr;
+ }
+ clientTable[client].hashsize++;
+ for (j = clientTable[client].buckets,
+ rptr = clientTable[client].resources;
+ --j >= 0;
+ rptr++) {
+ for (res = *rptr; res; res = next) {
+ next = res->next;
+ res->next = NullResource;
+ tptr = &tails[hash(client, res->id)];
+ **tptr = res;
+ *tptr = &res->next;
+ }
+ }
+ DEALLOCATE_LOCAL(tails);
+ clientTable[client].buckets *= 2;
+ fsfree(clientTable[client].resources);
+ clientTable[client].resources = resources;
+}
+
+void
+FreeResource(cid, id, skipDeleteFuncType)
+ int cid;
+ FSID id;
+ RESTYPE skipDeleteFuncType;
+{
+ register ResourcePtr res;
+ register ResourcePtr *prev,
+ *head;
+ register int *eltptr;
+ int elements;
+ Bool gotOne = FALSE;
+
+ if (clientTable[cid].buckets) {
+ head = &clientTable[cid].resources[hash(cid, id)];
+ eltptr = &clientTable[cid].elements;
+
+ prev = head;
+ while ((res = *prev) != (ResourcePtr) 0) {
+ if (res->id == id) {
+ RESTYPE rtype = res->type;
+
+ *prev = res->next;
+ elements = --*eltptr;
+ if (rtype != skipDeleteFuncType)
+ (*DeleteFuncs[rtype & TypeMask]) (res->value, res->id);
+ fsfree(res);
+ if (*eltptr != elements)
+ prev = head;/* prev may no longer be valid */
+ gotOne = TRUE;
+ } else
+ prev = &res->next;
+ }
+ }
+ if (!gotOne)
+ FatalError("Freeing resource id=%X which isn't there\n", id);
+}
+
+#ifdef NOTYET
+void
+FreeResourceByType(cid, id, type, skipFree)
+ int cid;
+ FSID id;
+ RESTYPE type;
+ Bool skipFree;
+{
+ register ResourcePtr res;
+ register ResourcePtr *prev,
+ *head;
+
+ if (clientTable[cid].buckets) {
+ head = &clientTable[cid].resources[hash(cid, id)];
+
+ prev = head;
+ while (res = *prev) {
+ if (res->id == id && res->type == type) {
+ *prev = res->next;
+ if (!skipFree)
+ (*DeleteFuncs[type & TypeMask]) (res->value, res->id);
+ fsfree(res);
+ break;
+ } else
+ prev = &res->next;
+ }
+ }
+}
+
+/*
+ * Change the value associated with a resource id. Caller
+ * is responsible for "doing the right thing" with the old
+ * data
+ */
+
+Bool
+ChangeResourceValue(cid, id, rtype, value)
+ int cid;
+ FSID id;
+ RESTYPE rtype;
+ pointer value;
+{
+ register ResourcePtr res;
+
+ if (clientTable[cid].buckets) {
+ res = clientTable[cid].resources[hash(cid, id)];
+
+ for (; res; res = res->next)
+ if ((res->id == id) && (res->type == rtype)) {
+ res->value = value;
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+#endif /* NOTYET */
+
+void
+FreeClientResources(client)
+ ClientPtr client;
+{
+ register ResourcePtr *resources;
+ register ResourcePtr this;
+ int j;
+
+ /*
+ * This routine shouldn't be called with a null client, but just in case
+ * ...
+ */
+
+ if (!client)
+ return;
+
+ resources = clientTable[client->index].resources;
+ for (j = 0; j < clientTable[client->index].buckets; j++) {
+ /*
+ * It may seem silly to update the head of this resource list as we
+ * delete the members, since the entire list will be deleted any way,
+ * but there are some resource deletion functions "FreeClientPixels"
+ * for one which do a LookupID on another resource id (a Colormap id
+ * in this case), so the resource list must be kept valid up to the
+ * point that it is deleted, so every time we delete a resource, we
+ * must update the head, just like in free_resource. I hope that this
+ * doesn't slow down mass deletion appreciably. PRH
+ */
+
+ ResourcePtr *head;
+
+ head = &resources[j];
+
+ for (this = *head; this; this = *head) {
+ RESTYPE rtype = this->type;
+
+ *head = this->next;
+ (*DeleteFuncs[rtype & TypeMask]) (this->value, this->id);
+ fsfree(this);
+ }
+ }
+ fsfree(clientTable[client->index].resources);
+ clientTable[client->index].buckets = 0;
+}
+
+FreeAllResources()
+{
+ int i;
+
+ for (i = 0; i < currentMaxClients; i++) {
+ if (clientTable[i].buckets)
+ FreeClientResources(clients[i]);
+ }
+}
+
+/*
+ * lookup_id_by_type returns the object with the given id and type, else NULL.
+ */
+pointer
+LookupIDByType(cid, id, rtype)
+ int cid;
+ FSID id;
+ RESTYPE rtype;
+{
+ register ResourcePtr res;
+
+ if (clientTable[cid].buckets) {
+ res = clientTable[cid].resources[hash(cid, id)];
+
+ for (; res; res = res->next)
+ if ((res->id == id) && (res->type == rtype))
+ return res->value;
+ }
+ return (pointer) NULL;
+}
+
+#ifdef NOTYET
+/*
+ * lookup_ID_by_class returns the object with the given id and any one of the
+ * given classes, else NULL.
+ */
+pointer
+LookupIDByClass(id, classes)
+ FSID id;
+ RESTYPE classes;
+{
+ int cid;
+ register ResourcePtr res;
+
+ if (((cid = CLIENT_ID(id)) < MAXCLIENTS) && clientTable[cid].buckets) {
+ res = clientTable[cid].resources[hash(cid, id)];
+
+ for (; res; res = res->next)
+ if ((res->id == id) && (res->type & classes))
+ return res->value;
+ }
+ return (pointer) NULL;
+}
+
+#endif /* NOTYET */