aboutsummaryrefslogtreecommitdiff
path: root/xorg-server/dix/privates.c
diff options
context:
space:
mode:
Diffstat (limited to 'xorg-server/dix/privates.c')
-rw-r--r--xorg-server/dix/privates.c537
1 files changed, 374 insertions, 163 deletions
diff --git a/xorg-server/dix/privates.c b/xorg-server/dix/privates.c
index 52a8df3f6..6d76ccff2 100644
--- a/xorg-server/dix/privates.c
+++ b/xorg-server/dix/privates.c
@@ -25,6 +25,28 @@ other dealings in this Software without prior written authorization
from The Open Group.
*/
+/*
+ * Copyright © 2010, Keith Packard
+ * Copyright © 2010, Jamey Sharp
+ *
+ * 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 name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS 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.
+ */
#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
@@ -38,177 +60,327 @@ from The Open Group.
#include "cursorstr.h"
#include "colormapst.h"
#include "inputstr.h"
-
-struct _Private {
- int state;
- pointer value;
+#include "scrnintstr.h"
+#include "extnsionst.h"
+
+static struct {
+ DevPrivateKey key;
+ unsigned offset;
+ int created;
+ int allocated;
+} keys[PRIVATE_LAST];
+
+static const Bool xselinux_private[PRIVATE_LAST] = {
+ [PRIVATE_CLIENT] = TRUE,
+ [PRIVATE_WINDOW] = TRUE,
+ [PRIVATE_PIXMAP] = TRUE,
+ [PRIVATE_GC] = TRUE,
+ [PRIVATE_CURSOR] = TRUE,
+ [PRIVATE_COLORMAP] = TRUE,
+ [PRIVATE_DEVICE] = TRUE,
+ [PRIVATE_EXTENSION] = TRUE,
+ [PRIVATE_SELECTION] = TRUE,
+ [PRIVATE_PROPERTY] = TRUE,
+ [PRIVATE_PICTURE] = TRUE,
+ [PRIVATE_GLYPHSET] = TRUE,
};
-typedef struct _PrivateDesc {
- DevPrivateKey key;
- unsigned size;
-} PrivateDescRec;
+typedef Bool (*FixupFunc)(PrivatePtr *privates, int offset, unsigned bytes);
-#define PRIV_MAX 256
-#define PRIV_STEP 16
+static Bool
+dixReallocPrivates(PrivatePtr *privates, int old_offset, unsigned bytes)
+{
+ void *new_privates;
-/* list of all allocated privates */
-static PrivateDescRec items[PRIV_MAX];
-static int nextPriv;
+ new_privates = realloc(*privates, old_offset + bytes);
+ if (!new_privates)
+ return FALSE;
+ memset((char *) new_privates + old_offset, '\0', bytes);
+ *privates = new_privates;
+ return TRUE;
+}
-static PrivateDescRec *
-findItem(const DevPrivateKey key)
+static Bool
+dixMovePrivates(PrivatePtr *privates, int new_offset, unsigned bytes)
{
- if (!*key) {
- if (nextPriv >= PRIV_MAX)
- return NULL;
+ memmove((char *) *privates + bytes, *privates, new_offset - bytes);
+ memset(*privates, '\0', bytes);
+ return TRUE;
+}
- items[nextPriv].key = key;
- *key = nextPriv;
- nextPriv++;
- }
+static Bool
+fixupScreens(FixupFunc fixup, unsigned bytes)
+{
+ int s;
+ for (s = 0; s < screenInfo.numScreens; s++)
+ if (!fixup(&screenInfo.screens[s]->devPrivates, keys[PRIVATE_SCREEN].offset, bytes))
+ return FALSE;
+ return TRUE;
+}
- return items + *key;
+static Bool
+fixupServerClient(FixupFunc fixup, unsigned bytes)
+{
+ if (serverClient)
+ return fixup(&serverClient->devPrivates, keys[PRIVATE_CLIENT].offset, bytes);
+ return TRUE;
}
-static _X_INLINE int
-privateExists(PrivateRec **privates, const DevPrivateKey key)
+static Bool
+fixupExtensions(FixupFunc fixup, unsigned bytes)
{
- return *key && *privates &&
- (*privates)[0].state > *key &&
- (*privates)[*key].state;
+ unsigned char major;
+ ExtensionEntry *extension;
+ for (major = EXTENSION_BASE; (extension = GetExtensionEntry(major)); major++)
+ if (!fixup(&extension->devPrivates, keys[PRIVATE_EXTENSION].offset, bytes))
+ return FALSE;
+ return TRUE;
}
-/*
- * Request pre-allocated space.
- */
-int
-dixRequestPrivate(const DevPrivateKey key, unsigned size)
+static Bool
+fixupDefaultColormaps(FixupFunc fixup, unsigned bytes)
{
- PrivateDescRec *item = findItem(key);
- if (!item)
- return FALSE;
- if (size > item->size)
- item->size = size;
+ int s;
+ for (s = 0; s < screenInfo.numScreens; s++) {
+ ColormapPtr cmap;
+ dixLookupResourceByType((pointer *) &cmap, screenInfo.screens[s]->defColormap,
+ RT_COLORMAP, serverClient, DixCreateAccess);
+ if (cmap && !fixup(&cmap->devPrivates, keys[PRIVATE_COLORMAP].offset, bytes))
+ return FALSE;
+ }
return TRUE;
}
+static Bool (* const allocated_early[PRIVATE_LAST])(FixupFunc, unsigned) = {
+ [PRIVATE_SCREEN] = fixupScreens,
+ [PRIVATE_CLIENT] = fixupServerClient,
+ [PRIVATE_EXTENSION] = fixupExtensions,
+ [PRIVATE_COLORMAP] = fixupDefaultColormaps,
+};
+
/*
- * Allocate a private and attach it to an existing object.
+ * Register a private key. This takes the type of object the key will
+ * be used with, which may be PRIVATE_ALL indicating that this key
+ * will be used with all of the private objects. If 'size' is
+ * non-zero, then the specified amount of space will be allocated in
+ * the private storage. Otherwise, space for a single pointer will
+ * be allocated which can be set with dixSetPrivate
*/
-pointer *
-dixAllocatePrivate(PrivateRec **privates, const DevPrivateKey key)
+Bool
+dixRegisterPrivateKey(DevPrivateKey key, DevPrivateType type, unsigned size)
{
- PrivateDescRec *item = findItem(key);
- PrivateRec *ptr;
- pointer value;
- int oldsize, newsize;
-
- newsize = (*key / PRIV_STEP + 1) * PRIV_STEP;
-
- /* resize or init privates array */
- if (!item)
- return NULL;
+ DevPrivateType t;
+ int offset;
+ unsigned bytes;
- /* initialize privates array if necessary */
- if (!*privates) {
- ptr = calloc(newsize, sizeof(*ptr));
- if (!ptr)
- return NULL;
- *privates = ptr;
- (*privates)[0].state = newsize;
+ if (key->initialized) {
+ assert (size == key->size);
+ return TRUE;
}
- oldsize = (*privates)[0].state;
+ /* Compute required space */
+ bytes = size;
+ if (size == 0)
+ bytes = sizeof (void *);
+
+ /* align to void * size */
+ bytes = (bytes + sizeof (void *) - 1) & ~(sizeof (void *) - 1);
+
+ /* Update offsets for all affected keys */
+ if (type == PRIVATE_XSELINUX) {
+ DevPrivateKey k;
+
+ /* Resize if we can, or make sure nothing's allocated if we can't
+ */
+ for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++)
+ if (xselinux_private[t]) {
+ if (!allocated_early[t])
+ assert (!keys[t].created);
+ else if (!allocated_early[t](dixReallocPrivates, bytes))
+ return FALSE;
+ }
- /* resize privates array if necessary */
- if (*key >= oldsize) {
- ptr = realloc(*privates, newsize * sizeof(*ptr));
- if (!ptr)
- return NULL;
- memset(ptr + oldsize, 0, (newsize - oldsize) * sizeof(*ptr));
- *privates = ptr;
- (*privates)[0].state = newsize;
- }
+ /* Move all existing keys up in the privates space to make
+ * room for this new global key
+ */
+ for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) {
+ if (xselinux_private[t]) {
+ for (k = keys[t].key; k; k = k->next)
+ k->offset += bytes;
+ keys[t].offset += bytes;
+ if (allocated_early[t])
+ allocated_early[t](dixMovePrivates, bytes);
+ }
+ }
- /* initialize slot */
- ptr = *privates + *key;
- ptr->state = 1;
- if (item->size) {
- value = calloc(item->size, 1);
- if (!value)
- return NULL;
- ptr->value = value;
+ offset = 0;
+ } else {
+ /* Resize if we can, or make sure nothing's allocated if we can't */
+ if (!allocated_early[type])
+ assert(!keys[type].created);
+ else if (!allocated_early[type](dixReallocPrivates, bytes))
+ return FALSE;
+ offset = keys[type].offset;
+ keys[type].offset += bytes;
}
- return &ptr->value;
+ /* Setup this key */
+ key->offset = offset;
+ key->size = size;
+ key->initialized = TRUE;
+ key->type = type;
+ key->allocated = FALSE;
+ key->next = keys[type].key;
+ keys[type].key = key;
+
+ return TRUE;
}
/*
- * Look up a private pointer.
+ * Allocate a new private key.
+ *
+ * This manages the storage of the key object itself, freeing it when the
+ * privates system is restarted at server reset time. All other keys
+ * are expected to be statically allocated as the privates must be
+ * reset after all objects have been freed
*/
-pointer
-dixLookupPrivate(PrivateRec **privates, const DevPrivateKey key)
+DevPrivateKey
+dixCreatePrivateKey(DevPrivateType type, unsigned size)
{
- pointer *ptr;
+ DevPrivateKey key;
- if (privateExists(privates, key))
- return (*privates)[*key].value;
+ key = calloc(sizeof (DevPrivateKeyRec), 1);
+ if (!key)
+ return NULL;
+ if (!dixRegisterPrivateKey(key, type, size)) {
+ free(key);
+ return NULL;
+ }
+ key->allocated = TRUE;
+ return key;
+}
+
+/*
+ * Initialize privates by zeroing them
+ */
+void
+_dixInitPrivates(PrivatePtr *privates, void *addr, DevPrivateType type)
+{
+ keys[type].created++;
+ if (xselinux_private[type])
+ keys[PRIVATE_XSELINUX].created++;
+ if (keys[type].offset == 0)
+ addr = 0;
+ *privates = addr;
+ memset(addr, '\0', keys[type].offset);
+}
- ptr = dixAllocatePrivate(privates, key);
- return ptr ? *ptr : NULL;
+/*
+ * Clean up privates
+ */
+void
+_dixFiniPrivates(PrivatePtr privates, DevPrivateType type)
+{
+ keys[type].created--;
+ if (xselinux_private[type])
+ keys[PRIVATE_XSELINUX].created--;
}
/*
- * Look up the address of a private pointer.
+ * Allocate new object with privates.
+ *
+ * This is expected to be invoked from the
+ * dixAllocateObjectWithPrivates macro
*/
-pointer *
-dixLookupPrivateAddr(PrivateRec **privates, const DevPrivateKey key)
+void *
+_dixAllocateObjectWithPrivates(unsigned baseSize, unsigned clear, unsigned offset, DevPrivateType type)
{
- if (privateExists(privates, key))
- return &(*privates)[*key].value;
+ unsigned totalSize;
+ void *object;
+ PrivatePtr privates;
+ PrivatePtr *devPrivates;
+
+ assert (type > PRIVATE_SCREEN && type < PRIVATE_LAST);
+
+ /* round up so that void * is aligned */
+ baseSize = (baseSize + sizeof (void *) - 1) & ~(sizeof (void *) - 1);
+ totalSize = baseSize + keys[type].offset;
+ object = malloc(totalSize);
+ if (!object)
+ return NULL;
+
+ memset(object, '\0', clear);
+ privates = (PrivatePtr) (((char *) object) + baseSize);
+ devPrivates = (PrivatePtr *) ((char *) object + offset);
+
+ _dixInitPrivates(devPrivates, privates, type);
- return dixAllocatePrivate(privates, key);
+ return object;
}
/*
- * Set a private pointer.
+ * Allocate privates separately from containing object.
+ * Used for clients and screens.
*/
-int
-dixSetPrivate(PrivateRec **privates, const DevPrivateKey key, pointer val)
+Bool
+dixAllocatePrivates(PrivatePtr *privates, DevPrivateType type)
{
- top:
- if (privateExists(privates, key)) {
- (*privates)[*key].value = val;
- return TRUE;
+ unsigned size;
+ PrivatePtr p;
+
+ assert (type > PRIVATE_XSELINUX && type < PRIVATE_LAST);
+
+ size = keys[type].offset;
+ if (!size) {
+ p = NULL;
+ } else {
+ if (!(p = malloc(size)))
+ return FALSE;
}
- if (!dixAllocatePrivate(privates, key))
- return FALSE;
- goto top;
+ _dixInitPrivates(privates, p, type);
+ ++keys[type].allocated;
+
+ return TRUE;
}
/*
- * Called to free privates at object deletion time.
+ * Free an object that has privates
+ *
+ * This is expected to be invoked from the
+ * dixFreeObjectWithPrivates macro
*/
void
-dixFreePrivates(PrivateRec *privates)
+_dixFreeObjectWithPrivates(void *object, PrivatePtr privates, DevPrivateType type)
{
- int i;
-
- if (privates)
- for (i = 1; i < privates->state; i++)
- if (privates[i].state) {
- /* free pre-allocated memory */
- if (items[i].size)
- free(privates[i].value);
- }
+ _dixFiniPrivates(privates, type);
+ free(object);
+}
+/*
+ * Called to free screen or client privates
+ */
+void
+dixFreePrivates(PrivatePtr privates, DevPrivateType type)
+{
+ _dixFiniPrivates(privates, type);
+ --keys[type].allocated;
free(privates);
}
+/*
+ * Return size of privates for the specified type
+ */
+extern _X_EXPORT int
+dixPrivatesSize(DevPrivateType type)
+{
+ assert (type >= PRIVATE_SCREEN && type < PRIVATE_LAST);
+
+ return keys[type].offset;
+}
+
/* Table of devPrivates offsets */
-static const int offsetDefaults[] = {
+static const int offsets[] = {
-1, /* RT_NONE */
offsetof(WindowRec, devPrivates), /* RT_WINDOW */
offsetof(PixmapRec, devPrivates), /* RT_PIXMAP */
@@ -216,67 +388,106 @@ static const int offsetDefaults[] = {
-1, /* RT_FONT */
offsetof(CursorRec, devPrivates), /* RT_CURSOR */
offsetof(ColormapRec, devPrivates), /* RT_COLORMAP */
- -1, /* RT_CMAPENTRY */
- -1, /* RT_OTHERCLIENT */
- -1 /* RT_PASSIVEGRAB */
};
-
-static int *offsets = NULL;
-static int offsetsSize = 0;
-/*
- * Specify where the devPrivates field is located in a structure type
- */
+#define NUM_OFFSETS (sizeof (offsets) / sizeof (offsets[0]))
+
int
-dixRegisterPrivateOffset(RESTYPE type, int offset)
+dixLookupPrivateOffset(RESTYPE type)
{
- type = type & TypeMask;
-
- /* resize offsets table if necessary */
- while (type >= offsetsSize) {
- unsigned i = offsetsSize * 2 * sizeof(int);
- offsets = (int *)realloc(offsets, i);
- if (!offsets) {
- offsetsSize = 0;
- return FALSE;
- }
- for (i=offsetsSize; i < 2*offsetsSize; i++)
- offsets[i] = -1;
- offsetsSize *= 2;
+ /*
+ * Special kludge for DBE which registers a new resource type that
+ * points at pixmaps (thanks, DBE)
+ */
+ if (type & RC_DRAWABLE) {
+ if (type == RT_WINDOW)
+ return offsets[RT_WINDOW & TypeMask];
+ else
+ return offsets[RT_PIXMAP & TypeMask];
}
-
- offsets[type] = offset;
- return TRUE;
+ type = type & TypeMask;
+ if (type < NUM_OFFSETS)
+ return offsets[type];
+ return -1;
}
-int
-dixLookupPrivateOffset(RESTYPE type)
+static const char *key_names[PRIVATE_LAST] = {
+ /* XSELinux uses the same private keys for numerous objects */
+ [PRIVATE_XSELINUX] = "XSELINUX",
+
+ /* Otherwise, you get a private in just the requested structure
+ */
+ /* These can have objects created before all of the keys are registered */
+ [PRIVATE_SCREEN] = "SCREEN",
+ [PRIVATE_EXTENSION] = "EXTENSION",
+ [PRIVATE_COLORMAP] = "COLORMAP",
+
+ /* These cannot have any objects before all relevant keys are registered */
+ [PRIVATE_DEVICE] = "DEVICE",
+ [PRIVATE_CLIENT] = "CLIENT",
+ [PRIVATE_PROPERTY] = "PROPERTY",
+ [PRIVATE_SELECTION] = "SELECTION",
+ [PRIVATE_WINDOW] = "WINDOW",
+ [PRIVATE_PIXMAP] = "PIXMAP",
+ [PRIVATE_GC] = "GC",
+ [PRIVATE_CURSOR] = "CURSOR",
+ [PRIVATE_CURSOR_BITS] = "CURSOR_BITS",
+
+ /* extension privates */
+ [PRIVATE_DBE_WINDOW] = "DBE_WINDOW",
+ [PRIVATE_DAMAGE] = "DAMAGE",
+ [PRIVATE_GLYPH] = "GLYPH",
+ [PRIVATE_GLYPHSET] = "GLYPHSET",
+ [PRIVATE_PICTURE] = "PICTURE",
+};
+
+void
+dixPrivateUsage(void)
{
- type = type & TypeMask;
- assert(type < offsetsSize);
- return offsets[type];
+ int objects = 0;
+ int bytes = 0;
+ int alloc = 0;
+ DevPrivateType t;
+
+ for (t = PRIVATE_XSELINUX + 1; t < PRIVATE_LAST; t++) {
+ if (keys[t].offset) {
+ ErrorF("%s: %d objects of %d bytes = %d total bytes %d private allocs\n",
+ key_names[t], keys[t].created, keys[t].offset, keys[t].created * keys[t].offset,
+ keys[t].allocated);
+ bytes += keys[t].created * keys[t].offset;
+ objects += keys[t].created;
+ alloc += keys[t].allocated;
+ }
+ }
+ ErrorF("TOTAL: %d objects, %d bytes, %d allocs\n",
+ objects, bytes, alloc);
}
-int
+void
dixResetPrivates(void)
{
- int i;
-
- /* reset private descriptors */
- for (i = 1; i < nextPriv; i++) {
- *items[i].key = 0;
- items[i].size = 0;
+ DevPrivateType t;
+
+ for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) {
+ DevPrivateKey key, next;
+
+ for (key = keys[t].key; key; key = next) {
+ next = key->next;
+ key->offset = 0;
+ key->initialized = FALSE;
+ key->size = 0;
+ key->type = 0;
+ if (key->allocated)
+ free(key);
+ }
+ if (keys[t].created) {
+ ErrorF("%d %ss still allocated at reset\n",
+ keys[t].created, key_names[t]);
+ dixPrivateUsage();
+ }
+ keys[t].key = NULL;
+ keys[t].offset = 0;
+ keys[t].created = 0;
+ keys[t].allocated = 0;
}
- nextPriv = 1;
-
- /* reset offsets */
- if (offsets)
- free(offsets);
- offsetsSize = sizeof(offsetDefaults);
- offsets = malloc(offsetsSize);
- offsetsSize /= sizeof(int);
- if (!offsets)
- return FALSE;
- memcpy(offsets, offsetDefaults, sizeof(offsetDefaults));
- return TRUE;
}