#define XCACHE_C #include "xcache.h" #include "config.h" #include "lisp.h" /* General comments: * * - Each of the wrapper functions (xcache_[A-Z][A-z]*) goes through a similar * routine: allocate & build the key, search for the key in the cache, if * found, return that data, else execute the underlying X function and store * the result in the cache for future use. * * - The keys are basically a concatenation of the data type (XAC, XQC) with * the arguments to the wrapper function. */ /* The size of the largest key we bother to cache */ #define MAXKEYLENSIZE 2048 /* This gets prepended to the key to insure cached data doesn't * get confused between the different wrappers (necessary) */ static unsigned char XAC=1; static unsigned char XQC=2; /* For debugging purposes; should be 0 unless you want hit/miss info */ #define DEBUG_AC 0 #define DEBUG_QC 0 #define DEBUG_LF 0 #define DEBUG_LQF 0 /***************************************************************************** Definitions of main xcache structure & access functions The cache structure consists of a linked list of cache records. Each record consists of key and data pointers, and lengths for each of those. xcache_find(keylen, key) locates a cache record by its key and returns it, whereas xcache_store(keylen, key, datalen, data) creates and stores a new record in the cache list (at the head of the list). *****************************************************************************/ struct _xcache_record { unsigned int keylen, datalen; /* Lengths of the key and data binary strings */ char *key; char *data; unsigned int refcount; /* How many times is this data being used? */ struct _xcache_record *nextrec; /* next record in the list */ }; struct _xcache { unsigned int numrecs; /* Length of the list */ unsigned int cachesize; /* In bytes */ struct _xcache_record *first; /* Head of the list */ }; static struct _xcache xcache = {0, 0, NULL}; /* This is the actual _xcache object */ /* Store a new record into the cache */ struct _xcache_record * xcache_store(keylen, key, datalen, data) unsigned int keylen; char *key; unsigned int datalen; char *data; { struct _xcache_record *newrec= (struct _xcache_record*)xmalloc(sizeof(struct _xcache_record)); newrec->keylen=keylen; newrec->datalen=datalen; newrec->key=(char*)xmalloc(keylen); newrec->data=(char*)xmalloc(datalen); memcpy(newrec->key, key, keylen); memcpy(newrec->data, data, datalen); newrec->nextrec=xcache.first; xcache.first=newrec; xcache.numrecs++; newrec->refcount=1; xcache.cachesize+=keylen+datalen+(sizeof(unsigned int)*2); return newrec; } /* Find a cache record in the cache */ struct _xcache_record * xcache_find(keylen, key) unsigned int keylen; char *key; { struct _xcache_record *recptr = xcache.first; while (recptr) { if ((recptr->keylen==keylen) && !memcmp(key, recptr->key, keylen)) return recptr; recptr=recptr->nextrec; } return NULL; } /* Remove a cache record from the cache */ unsigned char xcache_remove(keylen, key) unsigned int keylen; char *key; { struct _xcache_record *recptr = xcache.first, *prevptr=NULL; while (recptr) { if ((recptr->keylen==keylen) && !memcmp(key, recptr->key, keylen)) { if (prevptr==NULL) xcache.first=xcache.first->nextrec; else prevptr->nextrec=recptr->nextrec; xcache.numrecs--; xcache.cachesize -= recptr->keylen + recptr->datalen + (sizeof(unsigned int)*2); xfree(recptr->key); xfree(recptr->data); xfree(recptr); return 1; } prevptr=recptr; recptr=recptr->nextrec; } return 0; } /***************************************************************************** XAllocColor *****************************************************************************/ /* Status is just an int, at least on XFree86 */ Status xcache_AllocColor(display, colormap, screen_in_out) Display *display; Colormap colormap; XColor *screen_in_out; { unsigned int keylen=sizeof(unsigned char) + strlen(DisplayString(display))+sizeof(Colormap)+sizeof(XColor); unsigned char *key=alloca(sizeof(char)*MAXKEYLENSIZE); struct _xcache_record *recptr=NULL; Status ret=1; if (keylen >= MAXKEYLENSIZE) return XAllocColor(display, colormap, screen_in_out); memset(key, 0, keylen); screen_in_out->pad=0; screen_in_out->flags=0; memcpy(key, &XAC, sizeof(unsigned char)); memcpy(key+sizeof(unsigned char), DisplayString(display), strlen(DisplayString(display))); memcpy(key+sizeof(unsigned char) +strlen(DisplayString(display)), &colormap, sizeof(Colormap)); memcpy(key+sizeof(unsigned char)+strlen(DisplayString(display)) +sizeof(Colormap), screen_in_out, sizeof(XColor)); if ((recptr=xcache_find(keylen, key))) { recptr->refcount++; memcpy(screen_in_out, recptr->data, recptr->datalen); #if DEBUG_AC TIMELOG("AllocColor hit!"); #endif } else { ret=XAllocColor(display, colormap, screen_in_out); if (ret) xcache_store(keylen, key, sizeof(XColor), (char*)screen_in_out); #if DEBUG_AC TIMELOG("AllocColor miss!"); { static char s[1024]; sprintf(s, " %lu %hu %hu %hu %hhd %hhd", screen_in_out->pixel, screen_in_out->red, screen_in_out->blue, screen_in_out->green, screen_in_out->pad, screen_in_out->flags); TIMELOG(s); } #endif } return ret; } /* A utility function that finds a cache record of type XAC * with a certain pixel value. Used for XFreeColors wrapping. */ struct _xcache_record * xcache_AC_findpixel(pixel) unsigned int pixel; { struct _xcache_record *recptr=xcache.first; XColor *xc=NULL; while (recptr) { if (memcmp(recptr->key, &XAC, sizeof(unsigned short))) recptr=recptr->nextrec; else { xc=(XColor*)recptr->key+recptr->keylen-sizeof(XColor); if (xc->pixel == pixel) return recptr; recptr=recptr->nextrec; } } return NULL; } /***************************************************************************** XQueryColor *****************************************************************************/ void xcache_QueryColor(display, colormap, xc) Display *display; Colormap colormap; XColor *xc; { unsigned int keylen=sizeof(unsigned char)+strlen(DisplayString(display))+ sizeof(Colormap)+sizeof(XColor); unsigned char *key=alloca(sizeof(char)*MAXKEYLENSIZE); struct _xcache_record *recptr=NULL; if (keylen >= MAXKEYLENSIZE) { XQueryColor(display, colormap, xc); return; } memset(key, 0, keylen); xc->pad=0; xc->flags=0; xc->red=xc->blue=xc->green=0; memcpy(key, &XQC, sizeof(unsigned char)); memcpy(key+sizeof(unsigned char), DisplayString(display), strlen(DisplayString(display))); memcpy(key+sizeof(unsigned char)+strlen(DisplayString(display)), &colormap, sizeof(Colormap)); memcpy(key+sizeof(unsigned char)+strlen(DisplayString(display)) +sizeof(Colormap), xc, sizeof(XColor)); if ((recptr=xcache_find(keylen, key))) { recptr->refcount++; memcpy(xc, recptr->data, recptr->datalen); #if DEBUG_QC TIMELOG("QueryColor hit!"); #endif } else { XQueryColor(display, colormap, xc); xcache_store(keylen, key, sizeof(XColor), (char*)xc); #if DEBUG_QC TIMELOG("QueryColor miss!"); { static char s[1024]; sprintf(s, " %lu %hu %hu %hu %hhd %hhd", xc->pixel, xc->red, xc->blue, xc->green, xc->pad, xc->flags); TIMELOG(s); } #endif } } /***************************************************************************** XQueryColors *****************************************************************************/ void xcache_QueryColors(display, colormap, xc, ncolors) Display *display; Colormap colormap; XColor xc[]; int ncolors; { int i=0; for(i=0; irefcount > 1) recptr->refcount--; else { XFreeColors(display, colormap, &pixels[i], 1, planes); xcache_remove(recptr->keylen, recptr->key); } } } /***************************************************************************** Generic logging mechanism -- this will simply log the file and source line where the TIMELOG(s) macro was called, noting the string s passed to the macro and timestamping the line in /tmp/timelog. Obviously this should never be enabled in a non-testing environment. *****************************************************************************/ #ifdef USE_XLOG void timerlog(char *s, unsigned int c, char *extra) { static FILE *logfile = NULL; static time_t now = 0; if (logfile==NULL) logfile=fopen("/tmp/timelog", "a"); now=time(NULL); fprintf(logfile, "%s:%u %s %s", s, c, extra, ctime(&now)); fflush(logfile); } #endif /* USE_XLOG */