#include "FS.h"
#include "misc.h"
#include "os.h"
#include "fsresource.h"
#include "clientstr.h"
#include "dispatch.h"
#include "globals.h"
static void rebuild_table(int client);
#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;
FSID fakeID;
FSID endFakeID;
FSID expectID;
} ClientResourceRec;
static RESTYPE lastResourceType;
#ifdef NOTYET
static RESTYPE lastResourceClass;
#endif
static RESTYPE TypeMask;
typedef int (*DeleteType) (void *, FSID);
extern int CloseClientFont(ClientPtr, FSID);
static DeleteType *DeleteFuncs = (DeleteType *) NULL;
#ifdef NOTYET
RESTYPE
CreateNewResourceType(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(void)
{
RESTYPE next = lastResourceClass >> 1;
if (next & lastResourceType)
return 0;
lastResourceClass = next;
TypeMask = next - 1;
return next;
}
#endif
ClientResourceRec clientTable[MAXCLIENTS];
int
NoneDeleteFunc (void *ptr, FSID id)
{
return FSSuccess;
}
Bool
InitClientResources(ClientPtr client)
{
register int i,
j;
if (client == serverClient) {
lastResourceType = RT_LASTPREDEF;
#ifdef NOTYET
lastResourceClass = RC_LASTPREDEF;
#endif
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] = (DeleteType)CloseClientFont;
DeleteFuncs[RT_AUTHCONT & TypeMask] = (DeleteType)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(int client, 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(
register int client,
register FSID id,
register FSID maxid,
register FSID 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;
}
FSID
FakeClientID(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(
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(int client)
{
register int j;
register ResourcePtr res,
next;
ResourcePtr **tails,
*resources;
register ResourcePtr **tptr,
*rptr;
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(
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;
gotOne = TRUE;
} else
prev = &res->next;
}
}
if (!gotOne)
FatalError("freeing resource id=%X which isn't there\n", id);
}
#ifdef NOTYET
void
FreeResourceByType(
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;
}
}
}
Bool
ChangeResourceValue(
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
void
FreeClientResources(ClientPtr client)
{
register ResourcePtr *resources;
register ResourcePtr this;
int j;
if (!client)
return;
resources = clientTable[client->index].resources;
for (j = 0; j < clientTable[client->index].buckets; j++) {
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;
}
void
FreeAllResources(void)
{
int i;
for (i = 0; i < currentMaxClients; i++) {
if (clientTable[i].buckets)
FreeClientResources(clients[i]);
}
}
pointer
LookupIDByType(
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
pointer
LookupIDByClass(
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