diff options
author | Eamon Walsh <ewalsh@tycho.nsa.gov> | 2007-03-01 15:00:02 -0500 |
---|---|---|
committer | Eamon Walsh <ewalsh@moss-uranus.epoch.ncsc.mil> | 2007-03-05 11:50:45 -0500 |
commit | e684824709fa8ffe03dde3c8dfbc58c267515a4f (patch) | |
tree | dd9172343b3dea7cd2ab0ae365724c62cff81673 | |
parent | 74f1de1de9633119c2cf26086875717181c8a6f7 (diff) |
devPrivates rework: redo interface and implementation.
-rw-r--r-- | dix/main.c | 3 | ||||
-rw-r--r-- | dix/privates.c | 433 | ||||
-rw-r--r-- | dix/resource.c | 6 | ||||
-rw-r--r-- | hw/xfree86/loader/dixsym.c | 7 | ||||
-rw-r--r-- | include/privates.h | 126 | ||||
-rw-r--r-- | include/resource.h | 23 |
6 files changed, 312 insertions, 286 deletions
diff --git a/dix/main.c b/dix/main.c index b5954af2b..ed5e358c4 100644 --- a/dix/main.c +++ b/dix/main.c @@ -357,7 +357,8 @@ main(int argc, char *argv[], char *envp[]) InitAtoms(); InitEvents(); InitGlyphCaching(); - dixResetPrivates(); + if (!dixResetPrivates()) + FatalError("couldn't init private data storage"); ResetExtensionPrivates(); ResetClientPrivates(); ResetScreenPrivates(); diff --git a/dix/privates.c b/dix/privates.c index feab86714..c4ecf6ada 100644 --- a/dix/privates.c +++ b/dix/privates.c @@ -31,6 +31,7 @@ from The Open Group. #endif #include <X11/X.h> +#include <stddef.h> #include "scrnintstr.h" #include "misc.h" #include "os.h" @@ -45,315 +46,265 @@ from The Open Group. #include "inputstr.h" #include "extnsionst.h" -typedef struct _PrivateDescItem { - int index; +typedef struct _PrivateDesc { + devprivate_key_t *key; RESTYPE type; pointer parent; unsigned size; CallbackListPtr initfuncs; CallbackListPtr deletefuncs; -} PrivateDescItemRec, *PrivateDescItemPtr; - -/* keeps track of whether resource objects have been created */ -static char *instances = NULL; -static RESTYPE instancesSize = 0; -static char anyInstances = 0; + struct _PrivateDesc *next; +} PrivateDescRec; /* list of all allocated privates */ -static PrivateDescItemPtr items = NULL; -static unsigned itemsSize = 0; -static unsigned nextPrivateIndex = 0; - -/* number of extra slots to add when resizing the tables */ -#define PRIV_TAB_INCREMENT 48 -/* set in index value for privates registered after resources were created */ -#define PRIV_DYN_MASK (1<<30) -/* descriptor item lookup convenience macro */ -#define GET_DESCRIPTOR(index) (items + ((index) & (PRIV_DYN_MASK - 1))) -/* type mask convenience macro */ -#define TYPE_BITS(type) ((type) & TypeMask) +static PrivateDescRec *items = NULL; -static _X_INLINE ResourcePtr -findResourceBucket(RESTYPE type, pointer instance) { - ResourcePtr res = *((ResourcePtr *)instance); - - while (res->type != type) - res = res->nexttype; - return res; +static _X_INLINE PrivateDescRec * +findItem(devprivate_key_t *const key) +{ + PrivateDescRec *item = items; + while (item) { + if (item->key == key) + return item; + item = item->next; + } + return NULL; } /* - * Request functions; the latter calls the former internally. + * Request pre-allocated space in resources of a given type. */ _X_EXPORT int -dixRequestPrivate(RESTYPE type, unsigned size, pointer parent) -{ - int index = nextPrivateIndex; +dixRequestPrivate(RESTYPE type, devprivate_key_t *const key, + unsigned size, pointer parent) +{ + PrivateDescRec *item = findItem(key); + if (item) { + assert(item->type == type); + if (size > item->size) + item->size = size; + } else { + item = (PrivateDescRec *)xalloc(sizeof(PrivateDescRec)); + if (!item) + return FALSE; + memset(item, 0, sizeof(PrivateDescRec)); + + /* add privates descriptor */ + item->key = key; + item->type = type; + item->parent = parent; + item->size = size; + item->next = items; + items = item; + } + return TRUE; +} - /* check if privates descriptor table needs to be resized */ - if (nextPrivateIndex >= itemsSize) { - unsigned bytes; - unsigned size = itemsSize; +/* + * Allocate a private and attach it to an existing object. + */ +_X_EXPORT pointer * +dixAllocatePrivate(PrivateRec **privates, devprivate_key_t *const key) +{ + PrivateDescRec *item = findItem(key); + PrivateRec *ptr; + unsigned size = sizeof(PrivateRec); + + if (item) + size += item->size; - while (nextPrivateIndex >= size) - size += PRIV_TAB_INCREMENT; + ptr = (PrivateRec *)xalloc(size); + if (!ptr) + return NULL; + memset(ptr, 0, size); + ptr->key = key; + ptr->value = (size > sizeof(PrivateRec)) ? (ptr + 1) : NULL; + ptr->next = *privates; + *privates = ptr; - bytes = size * sizeof(PrivateDescItemRec); - items = (PrivateDescItemPtr)xrealloc(items, bytes); - if (!items) { - itemsSize = nextPrivateIndex = 0; - return -1; - } - memset(items + itemsSize, 0, - (size - itemsSize) * sizeof(PrivateDescItemRec)); + /* call any init funcs and return */ + if (item) { + PrivateCallbackRec calldata = { key, ptr->value }; + CallCallbacks(&item->initfuncs, &calldata); } - - /* figure out if resource instances already exist */ - if ((type != RC_ANY && instances[TYPE_BITS(type)]) || - (type == RC_ANY && anyInstances)) - index |= PRIV_DYN_MASK; - - /* add privates descriptor */ - items[nextPrivateIndex].index = index; - items[nextPrivateIndex].type = type; - items[nextPrivateIndex].parent = parent; - items[nextPrivateIndex].size = size; - nextPrivateIndex++; - return index; + return &ptr->value; } -_X_EXPORT int -dixRequestSinglePrivate(RESTYPE type, unsigned size, pointer instance) +/* + * Allocates pre-requested privates in a single chunk. + */ +_X_EXPORT PrivateRec * +dixAllocatePrivates(RESTYPE type, pointer parent) { - PrivatePtr ptr; - ResourcePtr res = findResourceBucket(type, instance); - int index = dixRequestPrivate(type, size, instance); - if (index < 0) - return index; + unsigned count = 0, size = 0; + PrivateCallbackRec calldata; + PrivateDescRec *item; + PrivateRec *ptr; + char *value; + + /* first pass figures out total size */ + for (item = items; item; item = item->next) + if ((item->type == type || item->type == RC_ANY) && + (item->parent == NULL || item->parent == parent)) { + + size += sizeof(PrivateRec) + item->size; + count++; + } - ptr = (PrivatePtr)xalloc(sizeof(PrivateRec) + size); + /* allocate one chunk of memory for everything */ + ptr = (PrivateRec *)xalloc(size); if (!ptr) - return -1; - ptr->index = index; - ptr->value = ptr + 1; - ptr->next = res->privates; - res->privates = ptr; - return index; + return NULL; + memset(ptr, 0, size); + value = (char *)(ptr + count); + + /* second pass sets up records and calls init funcs */ + count = 0; + for (item = items; item; item = item->next) + if ((item->type == type || item->type == RC_ANY) && + (item->parent == NULL || item->parent == parent)) { + + ptr[count].key = calldata.key = item->key; + ptr[count].dontfree = (count > 0); + ptr[count].value = calldata.value = (items->size ? value : NULL); + ptr[count].next = ptr + (count + 1); + + CallCallbacks(&item->initfuncs, &calldata); + + count++; + value += item->size; + } + + if (count > 0) + ptr[count-1].next = NULL; + + return ptr; } /* - * Lookup function (some of this could be static inlined) + * Called to free privates at object deletion time. */ -_X_EXPORT pointer -dixLookupPrivate(RESTYPE type, int index, pointer instance) +_X_EXPORT void +dixFreePrivates(PrivateRec *privates) { - ResourcePtr res = findResourceBucket(type, instance); - PrivatePtr ptr = res->privates; - PrivateDescItemPtr item; + PrivateRec *ptr, *next; + PrivateDescRec *item; PrivateCallbackRec calldata; - /* see if private has already been allocated (likely) */ + /* first pass calls the delete callbacks */ + for (ptr = privates; ptr; ptr = ptr->next) { + item = findItem(ptr->key); + if (item) { + calldata.key = ptr->key; + calldata.value = ptr->value; + CallCallbacks(&item->deletefuncs, &calldata); + } + } + + /* second pass frees the memory */ + ptr = privates; while (ptr) { - if (ptr->index == index) - return ptr->value; - ptr = ptr->next; + if (ptr->dontfree) + ptr = ptr->next; + else { + next = ptr->next; + while (next && next->dontfree) + next = next->next; + + xfree(ptr); + ptr = next; + } } - /* past this point, need to create private on the fly */ - /* create the new private */ - item = GET_DESCRIPTOR(index); - ptr = (PrivatePtr)xalloc(sizeof(PrivateRec) + item->size); - if (!ptr) - return NULL; - memset(ptr, 0, sizeof(PrivateRec) + item->size); - ptr->index = index; - ptr->value = ptr + 1; - ptr->next = res->privates; - res->privates = ptr; - - /* call any init funcs and return */ - calldata.value = ptr->value; - calldata.index = index; - calldata.resource = res; - CallCallbacks(&item->initfuncs, &calldata); - return ptr->value; + /* no more use of privates permitted */ + *privates = NULL; } /* * Callback registration */ _X_EXPORT int -dixRegisterPrivateInitFunc(RESTYPE type, int index, +dixRegisterPrivateInitFunc(devprivate_key_t *const key, CallbackProcPtr callback, pointer data) { - return AddCallback(&GET_DESCRIPTOR(index)->initfuncs, callback, data); + PrivateDescRec *item = findItem(key); + if (!item) + return FALSE; + return AddCallback(&item->initfuncs, callback, data); } _X_EXPORT int -dixRegisterPrivateDeleteFunc(RESTYPE type, int index, +dixRegisterPrivateDeleteFunc(devprivate_key_t *const key, CallbackProcPtr callback, pointer data) { - return AddCallback(&GET_DESCRIPTOR(index)->deletefuncs, callback, data); + PrivateDescRec *item = findItem(key); + if (!item) + return FALSE; + return AddCallback(&item->deletefuncs, callback, data); } -/* - * Internal function called from the main loop to reset the subsystem. - */ -void -dixResetPrivates(void) -{ - if (items) - xfree(items); - items = NULL; - itemsSize = 0; - nextPrivateIndex = 0; - - if (instances) - xfree(instances); - instances = NULL; - instancesSize = 0; - anyInstances = 0; -} +/* Table of devPrivates offsets */ +static unsigned *offsets = NULL; +static unsigned offsetsSize = 0; /* - * Internal function called from CreateNewResourceType. + * Specify where the devPrivates field is located in a structure type */ -int -dixUpdatePrivates(void) +_X_EXPORT int +dixRegisterPrivateOffset(RESTYPE type, unsigned offset) { - RESTYPE next = lastResourceType + 1; - - /* check if instances table needs to be resized */ - if (next >= instancesSize) { - RESTYPE size = instancesSize; - - while (next >= size) - size += PRIV_TAB_INCREMENT; + type = type & TypeMask; - instances = (char *)xrealloc(instances, size); - if (!instances) { - instancesSize = 0; + /* resize offsets table if necessary */ + while (type >= offsetsSize) { + offsets = (unsigned *)xrealloc(offsets, + offsetsSize * 2 * sizeof(unsigned)); + if (!offsets) { + offsetsSize = 0; return FALSE; } - memset(instances + instancesSize, 0, size - instancesSize); - instancesSize = size; + offsetsSize *= 2; } + + offsets[type] = offset; return TRUE; } -/* - * Internal function called from dixAddResource. - * Allocates a ResourceRec along with any private space all in one chunk. - */ -ResourcePtr -dixAllocateResourceRec(RESTYPE type, pointer instance, pointer parent) +_X_EXPORT unsigned +dixLookupPrivateOffset(RESTYPE type) { - unsigned i, count = 0, size = sizeof(ResourceRec); - ResourcePtr res; - PrivatePtr ptr; - char *value; - - /* first pass figures out total size */ - for (i=0; i<nextPrivateIndex; i++) - if (items[i].type == type && - (items[i].parent == NULL || items[i].parent == parent)) { - - size += sizeof(PrivateRec) + items[i].size; - count++; - } - - /* allocate resource bucket */ - res = (ResourcePtr)xalloc(size); - if (!res) - return res; - memset(res, 0, size); - ptr = (PrivatePtr)(res + 1); - value = (char *)(ptr + count); - res->privates = (count > 0) ? ptr : NULL; - - /* second pass sets up privates records */ - count = 0; - for (i=0; i<nextPrivateIndex; i++) - if (items[i].type == type && - (items[i].parent == NULL || items[i].parent == parent)) { - - ptr[count].index = items[i].index; - ptr[count].value = value; - ptr[count].next = ptr + (count + 1); - count++; - value += items[i].size; - } - - if (count > 0) - ptr[count-1].next = NULL; - - /* hook up back-pointer to resource record(s) */ - if (type & RC_PRIVATES) { - res->nexttype = *((ResourcePtr *)instance); - *((ResourcePtr *)instance) = res; - } - - instances[TYPE_BITS(type)] = anyInstances = 1; - return res; + assert(type & RC_PRIVATES); + type = type & TypeMask; + assert(type < offsetsSize); + return offsets[type]; } - + /* - * Internal function called from dixAddResource. - * Calls the init functions on a newly allocated resource. + * Called from the main loop to reset the subsystem. */ -void -dixCallPrivateInitFuncs(ResourcePtr res) +int +dixResetPrivates(void) { - PrivatePtr ptr = res->privates; - PrivateCallbackRec calldata; - - calldata.resource = res; - while (ptr) { - calldata.value = ptr->value; - calldata.index = ptr->index; - CallCallbacks(&GET_DESCRIPTOR(ptr->index)->initfuncs, &calldata); - ptr = ptr->next; + PrivateDescRec *next; + while (items) { + next = items->next; + xfree(items); + items = next; } -} -/* - * Internal function called from the various delete resource functions. - * Calls delete callbacks before freeing the ResourceRec and other bits. - */ -void -dixFreeResourceRec(ResourcePtr res) -{ - ResourcePtr *tmp; - PrivatePtr ptr, next, base; - PrivateCallbackRec calldata; + if (offsets) + xfree(offsets); - /* first pass calls the delete callbacks */ - ptr = res->privates; - calldata.resource = res; - while (ptr) { - calldata.value = ptr->value; - calldata.index = ptr->index; - CallCallbacks(&GET_DESCRIPTOR(ptr->index)->deletefuncs, &calldata); - ptr = ptr->next; - } + offsetsSize = 16; + offsets = (unsigned *)xalloc(offsetsSize * sizeof(unsigned)); + if (!offsets) + return FALSE; - /* second pass frees any off-struct private records */ - ptr = res->privates; - base = (PrivatePtr)(res + 1); - while (ptr && ptr != base) { - next = ptr->next; - xfree(ptr); - ptr = next; - } + /* register basic resource offsets */ + if (!dixRegisterPrivateOffset(RT_WINDOW, offsetof(WindowRec,devPrivates))) + return FALSE; - /* remove the record from the nexttype linked list and free it*/ - if (res->type & RC_PRIVATES) { - tmp = (ResourcePtr *)res->value; - while (*tmp != res) - tmp = &(*tmp)->nexttype; - *tmp = (*tmp)->nexttype; - } - xfree(res); + return TRUE; } /* diff --git a/dix/resource.c b/dix/resource.c index c568ed0b0..2cad7c01b 100644 --- a/dix/resource.c +++ b/dix/resource.c @@ -169,6 +169,12 @@ static void RebuildTable( #define INITHASHSIZE 6 #define MAXHASHSIZE 11 +typedef struct _Resource { + struct _Resource *next; + XID id; + RESTYPE type; + pointer value; +} ResourceRec, *ResourcePtr; #define NullResource ((ResourcePtr)NULL) typedef struct _ClientResource { diff --git a/hw/xfree86/loader/dixsym.c b/hw/xfree86/loader/dixsym.c index 9136351a2..5479ed0df 100644 --- a/hw/xfree86/loader/dixsym.c +++ b/hw/xfree86/loader/dixsym.c @@ -261,10 +261,13 @@ _X_HIDDEN void *dixLookupTab[] = { SYMFUNC(FreeScratchPixmapHeader) /* privates.c */ SYMFUNC(dixRequestPrivate) - SYMFUNC(dixRequestSinglePrivate) - SYMFUNC(dixLookupPrivate) SYMFUNC(dixRegisterPrivateInitFunc) SYMFUNC(dixRegisterPrivateDeleteFunc) + SYMFUNC(dixAllocatePrivate) + SYMFUNC(dixAllocatePrivates) + SYMFUNC(dixFreePrivates) + SYMFUNC(dixRegisterPrivateOffset) + SYMFUNC(dixLookupPrivateOffset) SYMFUNC(AllocateExtensionPrivate) SYMFUNC(AllocateExtensionPrivateIndex) SYMFUNC(AllocateClientPrivate) diff --git a/include/privates.h b/include/privates.h index 8d7427074..898fdd9c9 100644 --- a/include/privates.h +++ b/include/privates.h @@ -19,59 +19,141 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * STUFF FOR PRIVATES *****************************************************************/ +typedef struct _PrivateKey { + int unused; +} devprivate_key_t; + +typedef struct _Private { + devprivate_key_t *key; + int dontfree; + pointer value; + struct _Private *next; +} PrivateRec; + /* - * Request private space for your driver/module in all resources of a type. - * A non-null pScreen argument restricts to resources on a given screen. + * Request pre-allocated private space for your driver/module. + * A non-null pScreen argument restricts to objects on a given screen. */ extern int -dixRequestPrivate(RESTYPE type, unsigned size, pointer pScreen); +dixRequestPrivate(RESTYPE type, devprivate_key_t *const key, + unsigned size, pointer pScreen); /* - * Request private space in just one individual resource object. + * Allocates a new private and attaches it to an existing object. */ -extern int -dixRequestSinglePrivate(RESTYPE type, unsigned size, pointer instance); +extern pointer * +dixAllocatePrivate(PrivateRec **privates, devprivate_key_t *const key); /* * Look up a private pointer. */ -extern pointer -dixLookupPrivate(RESTYPE type, int index, pointer instance); +static _X_INLINE pointer +dixLookupPrivate(PrivateRec **privates, devprivate_key_t *const key) +{ + PrivateRec *rec = *privates; + pointer *ptr; + + while (rec) { + if (rec->key == key) + return rec->value; + rec = rec->next; + } + + ptr = dixAllocatePrivate(privates, key); + return ptr ? *ptr : NULL; +} + +/* + * Look up the address of a private pointer. + */ +static _X_INLINE pointer * +dixLookupPrivateAddr(PrivateRec **privates, devprivate_key_t *const key) +{ + PrivateRec *rec = *privates; + + while (rec) { + if (rec->key == key) + return &rec->value; + rec = rec->next; + } + + return dixAllocatePrivate(privates, key); +} + +/* + * Set a private pointer. + */ +static _X_INLINE int +dixSetPrivate(PrivateRec **privates, devprivate_key_t *const key, pointer val) +{ + PrivateRec *rec; + + top: + rec = *privates; + while (rec) { + if (rec->key == key) { + rec->value = val; + return TRUE; + } + rec = rec->next; + } + + if (!dixAllocatePrivate(privates, key)) + return FALSE; + goto top; +} /* * Register callbacks to be called on private allocation/freeing. * The calldata argument to the callbacks is a PrivateCallbackPtr. */ typedef struct _PrivateCallback { + devprivate_key_t *key; /* private registration key */ pointer value; /* pointer to private */ - int index; /* registration index */ - ResourcePtr resource; /* resource record (do not modify!) */ -} PrivateCallbackRec, *PrivateCallbackPtr; +} PrivateCallbackRec; extern int -dixRegisterPrivateInitFunc(RESTYPE type, int index, +dixRegisterPrivateInitFunc(devprivate_key_t *const key, CallbackProcPtr callback, pointer userdata); extern int -dixRegisterPrivateDeleteFunc(RESTYPE type, int index, +dixRegisterPrivateDeleteFunc(devprivate_key_t *const key, CallbackProcPtr callback, pointer userdata); /* - * Internal functions + * Allocates all pre-requested private space in one chunk. + */ +extern PrivateRec * +dixAllocatePrivates(RESTYPE type, pointer parent); + +/* + * Frees any private space that is not part of an object. */ extern void -dixResetPrivates(void); +dixFreePrivates(PrivateRec *privates); +/* + * Resets the subsystem, called from the main loop. + */ extern int -dixUpdatePrivates(void); +dixResetPrivates(void); -extern ResourcePtr -dixAllocateResourceRec(RESTYPE type, pointer value, pointer parent); +/* + * These next two functions are necessary because the position of + * the devPrivates field varies by structure and calling code might + * only know the resource type, not the structure definition. + */ -extern void -dixCallPrivateInitFuncs(ResourcePtr res); +/* + * Looks up the offset where the devPrivates field is located by type. + */ +extern unsigned +dixLookupPrivateOffset(RESTYPE type); -extern void -dixFreeResourceRec(ResourcePtr res); +/* + * Specifies the offset where the devPrivates field is located. + */ +extern int +dixRegisterPrivateOffset(RESTYPE type, unsigned offset); #endif /* PRIVATES_H */ diff --git a/include/resource.h b/include/resource.h index 902305805..40259ac27 100644 --- a/include/resource.h +++ b/include/resource.h @@ -53,27 +53,10 @@ SOFTWARE. * STUFF FOR RESOURCES *****************************************************************/ -/* Resource structures */ +/* classes for Resource routines */ typedef unsigned long RESTYPE; -typedef struct _Private { - int index; - pointer value; - struct _Private *next; -} PrivateRec, *PrivatePtr; - -typedef struct _Resource { - struct _Resource *next; - struct _Resource *nexttype; - XID id; - RESTYPE type; - pointer value; - PrivatePtr privates; -} ResourceRec, *ResourcePtr; - -/* classes for Resource routines */ - #define RC_VANILLA ((RESTYPE)0) #define RC_CACHED ((RESTYPE)1<<31) #define RC_DRAWABLE ((RESTYPE)1<<30) @@ -84,8 +67,8 @@ typedef struct _Resource { */ #define RC_NEVERRETAIN ((RESTYPE)1<<29) /* Use class RC_PRIVATES for resources that support extra private data. - * Resources having this class must provide a field of type ResourcePtr - * at the top of the resource structure, which must be initalized to NULL. + * Resources having this class must provide a field of type PrivateRec *. + * Refer to the X server documentation on devPrivates for the details. */ #define RC_PRIVATES ((RESTYPE)1<<28) #define RC_LASTPREDEF RC_PRIVATES |