#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <stddef.h>
#include "windowstr.h"
#include "resource.h"
#include "privates.h"
#include "gcstruct.h"
#include "cursorstr.h"
#include "colormapst.h"
#include "inputstr.h"
#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_SCREEN] = TRUE,
[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 Bool (*FixupFunc)(PrivatePtr *privates, int offset, unsigned bytes);
static Bool
dixReallocPrivates(PrivatePtr *privates, int old_offset, unsigned bytes)
{
void *new_privates;
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 Bool
dixMovePrivates(PrivatePtr *privates, int new_offset, unsigned bytes)
{
memmove((char *) *privates + bytes, *privates, new_offset - bytes);
memset(*privates, '\0', bytes);
return TRUE;
}
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;
}
static Bool
fixupServerClient(FixupFunc fixup, unsigned bytes)
{
if (serverClient)
return fixup(&serverClient->devPrivates, keys[PRIVATE_CLIENT].offset, bytes);
return TRUE;
}
static Bool
fixupExtensions(FixupFunc fixup, unsigned bytes)
{
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;
}
static Bool
fixupDefaultColormaps(FixupFunc fixup, unsigned bytes)
{
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,
};
Bool
dixRegisterPrivateKey(DevPrivateKey key, DevPrivateType type, unsigned size)
{
DevPrivateType t;
int offset;
unsigned bytes;
if (key->initialized) {
assert (size == key->size);
return TRUE;
}
bytes = size;
if (size == 0)
bytes = sizeof (void *);
bytes = (bytes + sizeof (void *) - 1) & ~(sizeof (void *) - 1);
if (type == PRIVATE_XSELINUX) {
DevPrivateKey k;
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;
}
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);
}
}
offset = 0;
} else {
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;
}
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;
}
Bool
dixRegisterScreenPrivateKey(DevScreenPrivateKey screenKey, ScreenPtr pScreen, DevPrivateType type, unsigned size)
{
DevPrivateKey key;
if (!dixRegisterPrivateKey(&screenKey->screenKey, PRIVATE_SCREEN, 0))
return FALSE;
key = dixGetPrivate(&pScreen->devPrivates, &screenKey->screenKey);
if (key != NULL) {
assert(key->size == size);
assert(key->type == type);
return TRUE;
}
key = calloc(sizeof (DevPrivateKeyRec), 1);
if (!key)
return FALSE;
if (!dixRegisterPrivateKey(key, type, size)) {
free(key);
return FALSE;
}
key->allocated = TRUE;
dixSetPrivate(&pScreen->devPrivates, &screenKey->screenKey, key);
return TRUE;
}
DevPrivateKey
_dixGetScreenPrivateKey(const DevScreenPrivateKey key, ScreenPtr pScreen)
{
return dixGetPrivate(&pScreen->devPrivates, &key->screenKey);
}
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);
}
void
_dixFiniPrivates(PrivatePtr privates, DevPrivateType type)
{
keys[type].created--;
if (xselinux_private[type])
keys[PRIVATE_XSELINUX].created--;
}
void *
_dixAllocateObjectWithPrivates(unsigned baseSize, unsigned clear, unsigned offset, DevPrivateType type)
{
unsigned totalSize;
void *object;
PrivatePtr privates;
PrivatePtr *devPrivates;
assert (type > PRIVATE_SCREEN && type < PRIVATE_LAST);
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 object;
}
Bool
dixAllocatePrivates(PrivatePtr *privates, DevPrivateType type)
{
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;
}
_dixInitPrivates(privates, p, type);
++keys[type].allocated;
return TRUE;
}
void
_dixFreeObjectWithPrivates(void *object, PrivatePtr privates, DevPrivateType type)
{
_dixFiniPrivates(privates, type);
free(object);
}
void
dixFreePrivates(PrivatePtr privates, DevPrivateType type)
{
_dixFiniPrivates(privates, type);
--keys[type].allocated;
free(privates);
}
extern _X_EXPORT int
dixPrivatesSize(DevPrivateType type)
{
assert (type >= PRIVATE_SCREEN && type < PRIVATE_LAST);
return keys[type].offset;
}
static const int offsets[] = {
-1,
offsetof(WindowRec, devPrivates),
offsetof(PixmapRec, devPrivates),
offsetof(GC, devPrivates),
-1,
offsetof(CursorRec, devPrivates),
offsetof(ColormapRec, devPrivates),
};
#define NUM_OFFSETS (sizeof (offsets) / sizeof (offsets[0]))
int
dixLookupPrivateOffset(RESTYPE type)
{
if (type & RC_DRAWABLE) {
if (type == RT_WINDOW)
return offsets[RT_WINDOW & TypeMask];
else
return offsets[RT_PIXMAP & TypeMask];
}
type = type & TypeMask;
if (type < NUM_OFFSETS)
return offsets[type];
return -1;
}
static const char *key_names[PRIVATE_LAST] = {
[PRIVATE_XSELINUX] = "XSELINUX",
[PRIVATE_SCREEN] = "SCREEN",
[PRIVATE_EXTENSION] = "EXTENSION",
[PRIVATE_COLORMAP] = "COLORMAP",
[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",
[PRIVATE_DBE_WINDOW] = "DBE_WINDOW",
[PRIVATE_DAMAGE] = "DAMAGE",
[PRIVATE_GLYPH] = "GLYPH",
[PRIVATE_GLYPHSET] = "GLYPHSET",
[PRIVATE_PICTURE] = "PICTURE",
[PRIVATE_SYNC_FENCE] = "SYNC_FENCE",
};
void
dixPrivateUsage(void)
{
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);
}
void
dixResetPrivates(void)
{
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;
}
}