devPrivates rework: redo interface and implementation.

This commit is contained in:
Eamon Walsh 2007-03-01 15:00:02 -05:00 committed by Eamon Walsh
parent 74f1de1de9
commit e684824709
6 changed files with 323 additions and 297 deletions

View File

@ -357,7 +357,8 @@ main(int argc, char *argv[], char *envp[])
InitAtoms(); InitAtoms();
InitEvents(); InitEvents();
InitGlyphCaching(); InitGlyphCaching();
dixResetPrivates(); if (!dixResetPrivates())
FatalError("couldn't init private data storage");
ResetExtensionPrivates(); ResetExtensionPrivates();
ResetClientPrivates(); ResetClientPrivates();
ResetScreenPrivates(); ResetScreenPrivates();

View File

@ -31,6 +31,7 @@ from The Open Group.
#endif #endif
#include <X11/X.h> #include <X11/X.h>
#include <stddef.h>
#include "scrnintstr.h" #include "scrnintstr.h"
#include "misc.h" #include "misc.h"
#include "os.h" #include "os.h"
@ -45,315 +46,265 @@ from The Open Group.
#include "inputstr.h" #include "inputstr.h"
#include "extnsionst.h" #include "extnsionst.h"
typedef struct _PrivateDescItem { typedef struct _PrivateDesc {
int index; devprivate_key_t *key;
RESTYPE type; RESTYPE type;
pointer parent; pointer parent;
unsigned size; unsigned size;
CallbackListPtr initfuncs; CallbackListPtr initfuncs;
CallbackListPtr deletefuncs; CallbackListPtr deletefuncs;
} PrivateDescItemRec, *PrivateDescItemPtr; struct _PrivateDesc *next;
} PrivateDescRec;
/* keeps track of whether resource objects have been created */
static char *instances = NULL;
static RESTYPE instancesSize = 0;
static char anyInstances = 0;
/* list of all allocated privates */ /* list of all allocated privates */
static PrivateDescItemPtr items = NULL; static PrivateDescRec *items = NULL;
static unsigned itemsSize = 0;
static unsigned nextPrivateIndex = 0;
/* number of extra slots to add when resizing the tables */ static _X_INLINE PrivateDescRec *
#define PRIV_TAB_INCREMENT 48 findItem(devprivate_key_t *const key)
/* set in index value for privates registered after resources were created */ {
#define PRIV_DYN_MASK (1<<30) PrivateDescRec *item = items;
/* descriptor item lookup convenience macro */ while (item) {
#define GET_DESCRIPTOR(index) (items + ((index) & (PRIV_DYN_MASK - 1))) if (item->key == key)
/* type mask convenience macro */ return item;
#define TYPE_BITS(type) ((type) & TypeMask) item = item->next;
}
static _X_INLINE ResourcePtr return NULL;
findResourceBucket(RESTYPE type, pointer instance) {
ResourcePtr res = *((ResourcePtr *)instance);
while (res->type != type)
res = res->nexttype;
return res;
} }
/* /*
* Request functions; the latter calls the former internally. * Request pre-allocated space in resources of a given type.
*/ */
_X_EXPORT int _X_EXPORT int
dixRequestPrivate(RESTYPE type, unsigned size, pointer parent) dixRequestPrivate(RESTYPE type, devprivate_key_t *const key,
unsigned size, pointer parent)
{ {
int index = nextPrivateIndex; PrivateDescRec *item = findItem(key);
if (item) {
/* check if privates descriptor table needs to be resized */ assert(item->type == type);
if (nextPrivateIndex >= itemsSize) { if (size > item->size)
unsigned bytes; item->size = size;
unsigned size = itemsSize; } else {
item = (PrivateDescRec *)xalloc(sizeof(PrivateDescRec));
while (nextPrivateIndex >= size) if (!item)
size += PRIV_TAB_INCREMENT; return FALSE;
memset(item, 0, sizeof(PrivateDescRec));
bytes = size * sizeof(PrivateDescItemRec);
items = (PrivateDescItemPtr)xrealloc(items, bytes);
if (!items) {
itemsSize = nextPrivateIndex = 0;
return -1;
}
memset(items + itemsSize, 0,
(size - itemsSize) * sizeof(PrivateDescItemRec));
}
/* 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 */ /* add privates descriptor */
items[nextPrivateIndex].index = index; item->key = key;
items[nextPrivateIndex].type = type; item->type = type;
items[nextPrivateIndex].parent = parent; item->parent = parent;
items[nextPrivateIndex].size = size; item->size = size;
nextPrivateIndex++; item->next = items;
return index; items = item;
} }
return TRUE;
_X_EXPORT int
dixRequestSinglePrivate(RESTYPE type, unsigned size, pointer instance)
{
PrivatePtr ptr;
ResourcePtr res = findResourceBucket(type, instance);
int index = dixRequestPrivate(type, size, instance);
if (index < 0)
return index;
ptr = (PrivatePtr)xalloc(sizeof(PrivateRec) + size);
if (!ptr)
return -1;
ptr->index = index;
ptr->value = ptr + 1;
ptr->next = res->privates;
res->privates = ptr;
return index;
} }
/* /*
* Lookup function (some of this could be static inlined) * Allocate a private and attach it to an existing object.
*/ */
_X_EXPORT pointer _X_EXPORT pointer *
dixLookupPrivate(RESTYPE type, int index, pointer instance) dixAllocatePrivate(PrivateRec **privates, devprivate_key_t *const key)
{ {
ResourcePtr res = findResourceBucket(type, instance); PrivateDescRec *item = findItem(key);
PrivatePtr ptr = res->privates; PrivateRec *ptr;
PrivateDescItemPtr item; unsigned size = sizeof(PrivateRec);
PrivateCallbackRec calldata;
/* see if private has already been allocated (likely) */ if (item)
while (ptr) { size += item->size;
if (ptr->index == index)
return ptr->value;
ptr = ptr->next;
}
/* past this point, need to create private on the fly */ ptr = (PrivateRec *)xalloc(size);
/* create the new private */
item = GET_DESCRIPTOR(index);
ptr = (PrivatePtr)xalloc(sizeof(PrivateRec) + item->size);
if (!ptr) if (!ptr)
return NULL; return NULL;
memset(ptr, 0, sizeof(PrivateRec) + item->size); memset(ptr, 0, size);
ptr->index = index; ptr->key = key;
ptr->value = ptr + 1; ptr->value = (size > sizeof(PrivateRec)) ? (ptr + 1) : NULL;
ptr->next = res->privates; ptr->next = *privates;
res->privates = ptr; *privates = ptr;
/* call any init funcs and return */ /* call any init funcs and return */
calldata.value = ptr->value; if (item) {
calldata.index = index; PrivateCallbackRec calldata = { key, ptr->value };
calldata.resource = res;
CallCallbacks(&item->initfuncs, &calldata); CallCallbacks(&item->initfuncs, &calldata);
return ptr->value; }
return &ptr->value;
}
/*
* Allocates pre-requested privates in a single chunk.
*/
_X_EXPORT PrivateRec *
dixAllocatePrivates(RESTYPE type, pointer parent)
{
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++;
}
/* allocate one chunk of memory for everything */
ptr = (PrivateRec *)xalloc(size);
if (!ptr)
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;
}
/*
* Called to free privates at object deletion time.
*/
_X_EXPORT void
dixFreePrivates(PrivateRec *privates)
{
PrivateRec *ptr, *next;
PrivateDescRec *item;
PrivateCallbackRec calldata;
/* 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->dontfree)
ptr = ptr->next;
else {
next = ptr->next;
while (next && next->dontfree)
next = next->next;
xfree(ptr);
ptr = next;
}
}
/* no more use of privates permitted */
*privates = NULL;
} }
/* /*
* Callback registration * Callback registration
*/ */
_X_EXPORT int _X_EXPORT int
dixRegisterPrivateInitFunc(RESTYPE type, int index, dixRegisterPrivateInitFunc(devprivate_key_t *const key,
CallbackProcPtr callback, pointer data) 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 _X_EXPORT int
dixRegisterPrivateDeleteFunc(RESTYPE type, int index, dixRegisterPrivateDeleteFunc(devprivate_key_t *const key,
CallbackProcPtr callback, pointer data) 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);
} }
/* /* Table of devPrivates offsets */
* Internal function called from the main loop to reset the subsystem. static unsigned *offsets = NULL;
*/ static unsigned offsetsSize = 0;
void
dixResetPrivates(void)
{
if (items)
xfree(items);
items = NULL;
itemsSize = 0;
nextPrivateIndex = 0;
if (instances)
xfree(instances);
instances = NULL;
instancesSize = 0;
anyInstances = 0;
}
/* /*
* Internal function called from CreateNewResourceType. * Specify where the devPrivates field is located in a structure type
*/ */
int _X_EXPORT int
dixUpdatePrivates(void) dixRegisterPrivateOffset(RESTYPE type, unsigned offset)
{ {
RESTYPE next = lastResourceType + 1; type = type & TypeMask;
/* check if instances table needs to be resized */ /* resize offsets table if necessary */
if (next >= instancesSize) { while (type >= offsetsSize) {
RESTYPE size = instancesSize; offsets = (unsigned *)xrealloc(offsets,
offsetsSize * 2 * sizeof(unsigned));
while (next >= size) if (!offsets) {
size += PRIV_TAB_INCREMENT; offsetsSize = 0;
instances = (char *)xrealloc(instances, size);
if (!instances) {
instancesSize = 0;
return FALSE; return FALSE;
} }
memset(instances + instancesSize, 0, size - instancesSize); offsetsSize *= 2;
instancesSize = size;
} }
offsets[type] = offset;
return TRUE; return TRUE;
} }
/* _X_EXPORT unsigned
* Internal function called from dixAddResource. dixLookupPrivateOffset(RESTYPE type)
* Allocates a ResourceRec along with any private space all in one chunk.
*/
ResourcePtr
dixAllocateResourceRec(RESTYPE type, pointer instance, pointer parent)
{ {
unsigned i, count = 0, size = sizeof(ResourceRec); assert(type & RC_PRIVATES);
ResourcePtr res; type = type & TypeMask;
PrivatePtr ptr; assert(type < offsetsSize);
char *value; return offsets[type];
/* 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;
} }
/* /*
* Internal function called from dixAddResource. * Called from the main loop to reset the subsystem.
* Calls the init functions on a newly allocated resource.
*/ */
void int
dixCallPrivateInitFuncs(ResourcePtr res) dixResetPrivates(void)
{ {
PrivatePtr ptr = res->privates; PrivateDescRec *next;
PrivateCallbackRec calldata; while (items) {
next = items->next;
calldata.resource = res; xfree(items);
while (ptr) { items = next;
calldata.value = ptr->value;
calldata.index = ptr->index;
CallCallbacks(&GET_DESCRIPTOR(ptr->index)->initfuncs, &calldata);
ptr = ptr->next;
}
} }
/* if (offsets)
* Internal function called from the various delete resource functions. xfree(offsets);
* Calls delete callbacks before freeing the ResourceRec and other bits.
*/
void
dixFreeResourceRec(ResourcePtr res)
{
ResourcePtr *tmp;
PrivatePtr ptr, next, base;
PrivateCallbackRec calldata;
/* first pass calls the delete callbacks */ offsetsSize = 16;
ptr = res->privates; offsets = (unsigned *)xalloc(offsetsSize * sizeof(unsigned));
calldata.resource = res; if (!offsets)
while (ptr) { return FALSE;
calldata.value = ptr->value;
calldata.index = ptr->index;
CallCallbacks(&GET_DESCRIPTOR(ptr->index)->deletefuncs, &calldata);
ptr = ptr->next;
}
/* second pass frees any off-struct private records */ /* register basic resource offsets */
ptr = res->privates; if (!dixRegisterPrivateOffset(RT_WINDOW, offsetof(WindowRec,devPrivates)))
base = (PrivatePtr)(res + 1); return FALSE;
while (ptr && ptr != base) {
next = ptr->next;
xfree(ptr);
ptr = next;
}
/* remove the record from the nexttype linked list and free it*/ return TRUE;
if (res->type & RC_PRIVATES) {
tmp = (ResourcePtr *)res->value;
while (*tmp != res)
tmp = &(*tmp)->nexttype;
*tmp = (*tmp)->nexttype;
}
xfree(res);
} }
/* /*

View File

@ -169,6 +169,12 @@ static void RebuildTable(
#define INITHASHSIZE 6 #define INITHASHSIZE 6
#define MAXHASHSIZE 11 #define MAXHASHSIZE 11
typedef struct _Resource {
struct _Resource *next;
XID id;
RESTYPE type;
pointer value;
} ResourceRec, *ResourcePtr;
#define NullResource ((ResourcePtr)NULL) #define NullResource ((ResourcePtr)NULL)
typedef struct _ClientResource { typedef struct _ClientResource {

View File

@ -261,10 +261,13 @@ _X_HIDDEN void *dixLookupTab[] = {
SYMFUNC(FreeScratchPixmapHeader) SYMFUNC(FreeScratchPixmapHeader)
/* privates.c */ /* privates.c */
SYMFUNC(dixRequestPrivate) SYMFUNC(dixRequestPrivate)
SYMFUNC(dixRequestSinglePrivate)
SYMFUNC(dixLookupPrivate)
SYMFUNC(dixRegisterPrivateInitFunc) SYMFUNC(dixRegisterPrivateInitFunc)
SYMFUNC(dixRegisterPrivateDeleteFunc) SYMFUNC(dixRegisterPrivateDeleteFunc)
SYMFUNC(dixAllocatePrivate)
SYMFUNC(dixAllocatePrivates)
SYMFUNC(dixFreePrivates)
SYMFUNC(dixRegisterPrivateOffset)
SYMFUNC(dixLookupPrivateOffset)
SYMFUNC(AllocateExtensionPrivate) SYMFUNC(AllocateExtensionPrivate)
SYMFUNC(AllocateExtensionPrivateIndex) SYMFUNC(AllocateExtensionPrivateIndex)
SYMFUNC(AllocateClientPrivate) SYMFUNC(AllocateClientPrivate)

View File

@ -19,59 +19,141 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
* STUFF FOR PRIVATES * STUFF FOR PRIVATES
*****************************************************************/ *****************************************************************/
/* typedef struct _PrivateKey {
* Request private space for your driver/module in all resources of a type. int unused;
* A non-null pScreen argument restricts to resources on a given screen. } devprivate_key_t;
*/
extern int typedef struct _Private {
dixRequestPrivate(RESTYPE type, unsigned size, pointer pScreen); devprivate_key_t *key;
int dontfree;
pointer value;
struct _Private *next;
} PrivateRec;
/* /*
* Request private space in just one individual resource object. * Request pre-allocated private space for your driver/module.
* A non-null pScreen argument restricts to objects on a given screen.
*/ */
extern int extern int
dixRequestSinglePrivate(RESTYPE type, unsigned size, pointer instance); dixRequestPrivate(RESTYPE type, devprivate_key_t *const key,
unsigned size, pointer pScreen);
/*
* Allocates a new private and attaches it to an existing object.
*/
extern pointer *
dixAllocatePrivate(PrivateRec **privates, devprivate_key_t *const key);
/* /*
* Look up a private pointer. * Look up a private pointer.
*/ */
extern pointer static _X_INLINE pointer
dixLookupPrivate(RESTYPE type, int index, pointer instance); 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. * Register callbacks to be called on private allocation/freeing.
* The calldata argument to the callbacks is a PrivateCallbackPtr. * The calldata argument to the callbacks is a PrivateCallbackPtr.
*/ */
typedef struct _PrivateCallback { typedef struct _PrivateCallback {
devprivate_key_t *key; /* private registration key */
pointer value; /* pointer to private */ pointer value; /* pointer to private */
int index; /* registration index */ } PrivateCallbackRec;
ResourcePtr resource; /* resource record (do not modify!) */
} PrivateCallbackRec, *PrivateCallbackPtr;
extern int extern int
dixRegisterPrivateInitFunc(RESTYPE type, int index, dixRegisterPrivateInitFunc(devprivate_key_t *const key,
CallbackProcPtr callback, pointer userdata); CallbackProcPtr callback, pointer userdata);
extern int extern int
dixRegisterPrivateDeleteFunc(RESTYPE type, int index, dixRegisterPrivateDeleteFunc(devprivate_key_t *const key,
CallbackProcPtr callback, pointer userdata); 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 extern void
dixFreePrivates(PrivateRec *privates);
/*
* Resets the subsystem, called from the main loop.
*/
extern int
dixResetPrivates(void); dixResetPrivates(void);
/*
* 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.
*/
/*
* Looks up the offset where the devPrivates field is located by type.
*/
extern unsigned
dixLookupPrivateOffset(RESTYPE type);
/*
* Specifies the offset where the devPrivates field is located.
*/
extern int extern int
dixUpdatePrivates(void); dixRegisterPrivateOffset(RESTYPE type, unsigned offset);
extern ResourcePtr
dixAllocateResourceRec(RESTYPE type, pointer value, pointer parent);
extern void
dixCallPrivateInitFuncs(ResourcePtr res);
extern void
dixFreeResourceRec(ResourcePtr res);
#endif /* PRIVATES_H */ #endif /* PRIVATES_H */

View File

@ -53,27 +53,10 @@ SOFTWARE.
* STUFF FOR RESOURCES * STUFF FOR RESOURCES
*****************************************************************/ *****************************************************************/
/* Resource structures */ /* classes for Resource routines */
typedef unsigned long RESTYPE; 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_VANILLA ((RESTYPE)0)
#define RC_CACHED ((RESTYPE)1<<31) #define RC_CACHED ((RESTYPE)1<<31)
#define RC_DRAWABLE ((RESTYPE)1<<30) #define RC_DRAWABLE ((RESTYPE)1<<30)
@ -84,8 +67,8 @@ typedef struct _Resource {
*/ */
#define RC_NEVERRETAIN ((RESTYPE)1<<29) #define RC_NEVERRETAIN ((RESTYPE)1<<29)
/* Use class RC_PRIVATES for resources that support extra private data. /* Use class RC_PRIVATES for resources that support extra private data.
* Resources having this class must provide a field of type ResourcePtr * Resources having this class must provide a field of type PrivateRec *.
* at the top of the resource structure, which must be initalized to NULL. * Refer to the X server documentation on devPrivates for the details.
*/ */
#define RC_PRIVATES ((RESTYPE)1<<28) #define RC_PRIVATES ((RESTYPE)1<<28)
#define RC_LASTPREDEF RC_PRIVATES #define RC_LASTPREDEF RC_PRIVATES