privates.c revision 6747b715
1/* 2 3Copyright 1993, 1998 The Open Group 4 5Permission to use, copy, modify, distribute, and sell this software and its 6documentation for any purpose is hereby granted without fee, provided that 7the above copyright notice appear in all copies and that both that 8copyright notice and this permission notice appear in supporting 9documentation. 10 11The above copyright notice and this permission notice shall be included 12in all copies or substantial portions of the Software. 13 14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20OTHER DEALINGS IN THE SOFTWARE. 21 22Except as contained in this notice, the name of The Open Group shall 23not be used in advertising or otherwise to promote the sale, use or 24other dealings in this Software without prior written authorization 25from The Open Group. 26 27*/ 28/* 29 * Copyright © 2010, Keith Packard 30 * Copyright © 2010, Jamey Sharp 31 * 32 * Permission to use, copy, modify, distribute, and sell this software and its 33 * documentation for any purpose is hereby granted without fee, provided that 34 * the above copyright notice appear in all copies and that both that copyright 35 * notice and this permission notice appear in supporting documentation, and 36 * that the name of the copyright holders not be used in advertising or 37 * publicity pertaining to distribution of the software without specific, 38 * written prior permission. The copyright holders make no representations 39 * about the suitability of this software for any purpose. It is provided "as 40 * is" without express or implied warranty. 41 * 42 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 43 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 44 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR 45 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 46 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 47 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE 48 * OF THIS SOFTWARE. 49 */ 50 51#ifdef HAVE_DIX_CONFIG_H 52#include <dix-config.h> 53#endif 54 55#include <stddef.h> 56#include "windowstr.h" 57#include "resource.h" 58#include "privates.h" 59#include "gcstruct.h" 60#include "cursorstr.h" 61#include "colormapst.h" 62#include "inputstr.h" 63#include "scrnintstr.h" 64#include "extnsionst.h" 65 66static struct { 67 DevPrivateKey key; 68 unsigned offset; 69 int created; 70 int allocated; 71} keys[PRIVATE_LAST]; 72 73static const Bool xselinux_private[PRIVATE_LAST] = { 74 [PRIVATE_SCREEN] = TRUE, 75 [PRIVATE_CLIENT] = TRUE, 76 [PRIVATE_WINDOW] = TRUE, 77 [PRIVATE_PIXMAP] = TRUE, 78 [PRIVATE_GC] = TRUE, 79 [PRIVATE_CURSOR] = TRUE, 80 [PRIVATE_COLORMAP] = TRUE, 81 [PRIVATE_DEVICE] = TRUE, 82 [PRIVATE_EXTENSION] = TRUE, 83 [PRIVATE_SELECTION] = TRUE, 84 [PRIVATE_PROPERTY] = TRUE, 85 [PRIVATE_PICTURE] = TRUE, 86 [PRIVATE_GLYPHSET] = TRUE, 87}; 88 89typedef Bool (*FixupFunc)(PrivatePtr *privates, int offset, unsigned bytes); 90 91static Bool 92dixReallocPrivates(PrivatePtr *privates, int old_offset, unsigned bytes) 93{ 94 void *new_privates; 95 96 new_privates = realloc(*privates, old_offset + bytes); 97 if (!new_privates) 98 return FALSE; 99 memset((char *) new_privates + old_offset, '\0', bytes); 100 *privates = new_privates; 101 return TRUE; 102} 103 104static Bool 105dixMovePrivates(PrivatePtr *privates, int new_offset, unsigned bytes) 106{ 107 memmove((char *) *privates + bytes, *privates, new_offset - bytes); 108 memset(*privates, '\0', bytes); 109 return TRUE; 110} 111 112static Bool 113fixupScreens(FixupFunc fixup, unsigned bytes) 114{ 115 int s; 116 for (s = 0; s < screenInfo.numScreens; s++) 117 if (!fixup(&screenInfo.screens[s]->devPrivates, keys[PRIVATE_SCREEN].offset, bytes)) 118 return FALSE; 119 return TRUE; 120} 121 122static Bool 123fixupServerClient(FixupFunc fixup, unsigned bytes) 124{ 125 if (serverClient) 126 return fixup(&serverClient->devPrivates, keys[PRIVATE_CLIENT].offset, bytes); 127 return TRUE; 128} 129 130static Bool 131fixupExtensions(FixupFunc fixup, unsigned bytes) 132{ 133 unsigned char major; 134 ExtensionEntry *extension; 135 for (major = EXTENSION_BASE; (extension = GetExtensionEntry(major)); major++) 136 if (!fixup(&extension->devPrivates, keys[PRIVATE_EXTENSION].offset, bytes)) 137 return FALSE; 138 return TRUE; 139} 140 141static Bool 142fixupDefaultColormaps(FixupFunc fixup, unsigned bytes) 143{ 144 int s; 145 for (s = 0; s < screenInfo.numScreens; s++) { 146 ColormapPtr cmap; 147 dixLookupResourceByType((pointer *) &cmap, screenInfo.screens[s]->defColormap, 148 RT_COLORMAP, serverClient, DixCreateAccess); 149 if (cmap && !fixup(&cmap->devPrivates, keys[PRIVATE_COLORMAP].offset, bytes)) 150 return FALSE; 151 } 152 return TRUE; 153} 154 155static Bool (* const allocated_early[PRIVATE_LAST])(FixupFunc, unsigned) = { 156 [PRIVATE_SCREEN] = fixupScreens, 157 [PRIVATE_CLIENT] = fixupServerClient, 158 [PRIVATE_EXTENSION] = fixupExtensions, 159 [PRIVATE_COLORMAP] = fixupDefaultColormaps, 160}; 161 162/* 163 * Register a private key. This takes the type of object the key will 164 * be used with, which may be PRIVATE_ALL indicating that this key 165 * will be used with all of the private objects. If 'size' is 166 * non-zero, then the specified amount of space will be allocated in 167 * the private storage. Otherwise, space for a single pointer will 168 * be allocated which can be set with dixSetPrivate 169 */ 170Bool 171dixRegisterPrivateKey(DevPrivateKey key, DevPrivateType type, unsigned size) 172{ 173 DevPrivateType t; 174 int offset; 175 unsigned bytes; 176 177 if (key->initialized) { 178 assert (size == key->size); 179 return TRUE; 180 } 181 182 /* Compute required space */ 183 bytes = size; 184 if (size == 0) 185 bytes = sizeof (void *); 186 187 /* align to void * size */ 188 bytes = (bytes + sizeof (void *) - 1) & ~(sizeof (void *) - 1); 189 190 /* Update offsets for all affected keys */ 191 if (type == PRIVATE_XSELINUX) { 192 DevPrivateKey k; 193 194 /* Resize if we can, or make sure nothing's allocated if we can't 195 */ 196 for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) 197 if (xselinux_private[t]) { 198 if (!allocated_early[t]) 199 assert (!keys[t].created); 200 else if (!allocated_early[t](dixReallocPrivates, bytes)) 201 return FALSE; 202 } 203 204 /* Move all existing keys up in the privates space to make 205 * room for this new global key 206 */ 207 for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) { 208 if (xselinux_private[t]) { 209 for (k = keys[t].key; k; k = k->next) 210 k->offset += bytes; 211 keys[t].offset += bytes; 212 if (allocated_early[t]) 213 allocated_early[t](dixMovePrivates, bytes); 214 } 215 } 216 217 offset = 0; 218 } else { 219 /* Resize if we can, or make sure nothing's allocated if we can't */ 220 if (!allocated_early[type]) 221 assert(!keys[type].created); 222 else if (!allocated_early[type](dixReallocPrivates, bytes)) 223 return FALSE; 224 offset = keys[type].offset; 225 keys[type].offset += bytes; 226 } 227 228 /* Setup this key */ 229 key->offset = offset; 230 key->size = size; 231 key->initialized = TRUE; 232 key->type = type; 233 key->allocated = FALSE; 234 key->next = keys[type].key; 235 keys[type].key = key; 236 237 return TRUE; 238} 239 240/* 241 * Allocate a new private key. 242 * 243 * This manages the storage of the key object itself, freeing it when the 244 * privates system is restarted at server reset time. All other keys 245 * are expected to be statically allocated as the privates must be 246 * reset after all objects have been freed 247 */ 248DevPrivateKey 249dixCreatePrivateKey(DevPrivateType type, unsigned size) 250{ 251 DevPrivateKey key; 252 253 key = calloc(sizeof (DevPrivateKeyRec), 1); 254 if (!key) 255 return NULL; 256 if (!dixRegisterPrivateKey(key, type, size)) { 257 free(key); 258 return NULL; 259 } 260 key->allocated = TRUE; 261 return key; 262} 263 264/* 265 * Initialize privates by zeroing them 266 */ 267void 268_dixInitPrivates(PrivatePtr *privates, void *addr, DevPrivateType type) 269{ 270 keys[type].created++; 271 if (xselinux_private[type]) 272 keys[PRIVATE_XSELINUX].created++; 273 if (keys[type].offset == 0) 274 addr = 0; 275 *privates = addr; 276 memset(addr, '\0', keys[type].offset); 277} 278 279/* 280 * Clean up privates 281 */ 282void 283_dixFiniPrivates(PrivatePtr privates, DevPrivateType type) 284{ 285 keys[type].created--; 286 if (xselinux_private[type]) 287 keys[PRIVATE_XSELINUX].created--; 288} 289 290/* 291 * Allocate new object with privates. 292 * 293 * This is expected to be invoked from the 294 * dixAllocateObjectWithPrivates macro 295 */ 296void * 297_dixAllocateObjectWithPrivates(unsigned baseSize, unsigned clear, unsigned offset, DevPrivateType type) 298{ 299 unsigned totalSize; 300 void *object; 301 PrivatePtr privates; 302 PrivatePtr *devPrivates; 303 304 assert (type > PRIVATE_SCREEN && type < PRIVATE_LAST); 305 306 /* round up so that void * is aligned */ 307 baseSize = (baseSize + sizeof (void *) - 1) & ~(sizeof (void *) - 1); 308 totalSize = baseSize + keys[type].offset; 309 object = malloc(totalSize); 310 if (!object) 311 return NULL; 312 313 memset(object, '\0', clear); 314 privates = (PrivatePtr) (((char *) object) + baseSize); 315 devPrivates = (PrivatePtr *) ((char *) object + offset); 316 317 _dixInitPrivates(devPrivates, privates, type); 318 319 return object; 320} 321 322/* 323 * Allocate privates separately from containing object. 324 * Used for clients and screens. 325 */ 326Bool 327dixAllocatePrivates(PrivatePtr *privates, DevPrivateType type) 328{ 329 unsigned size; 330 PrivatePtr p; 331 332 assert (type > PRIVATE_XSELINUX && type < PRIVATE_LAST); 333 334 size = keys[type].offset; 335 if (!size) { 336 p = NULL; 337 } else { 338 if (!(p = malloc(size))) 339 return FALSE; 340 } 341 342 _dixInitPrivates(privates, p, type); 343 ++keys[type].allocated; 344 345 return TRUE; 346} 347 348/* 349 * Free an object that has privates 350 * 351 * This is expected to be invoked from the 352 * dixFreeObjectWithPrivates macro 353 */ 354void 355_dixFreeObjectWithPrivates(void *object, PrivatePtr privates, DevPrivateType type) 356{ 357 _dixFiniPrivates(privates, type); 358 free(object); 359} 360 361/* 362 * Called to free screen or client privates 363 */ 364void 365dixFreePrivates(PrivatePtr privates, DevPrivateType type) 366{ 367 _dixFiniPrivates(privates, type); 368 --keys[type].allocated; 369 free(privates); 370} 371 372/* 373 * Return size of privates for the specified type 374 */ 375extern _X_EXPORT int 376dixPrivatesSize(DevPrivateType type) 377{ 378 assert (type >= PRIVATE_SCREEN && type < PRIVATE_LAST); 379 380 return keys[type].offset; 381} 382 383/* Table of devPrivates offsets */ 384static const int offsets[] = { 385 -1, /* RT_NONE */ 386 offsetof(WindowRec, devPrivates), /* RT_WINDOW */ 387 offsetof(PixmapRec, devPrivates), /* RT_PIXMAP */ 388 offsetof(GC, devPrivates), /* RT_GC */ 389 -1, /* RT_FONT */ 390 offsetof(CursorRec, devPrivates), /* RT_CURSOR */ 391 offsetof(ColormapRec, devPrivates), /* RT_COLORMAP */ 392}; 393 394#define NUM_OFFSETS (sizeof (offsets) / sizeof (offsets[0])) 395 396int 397dixLookupPrivateOffset(RESTYPE type) 398{ 399 /* 400 * Special kludge for DBE which registers a new resource type that 401 * points at pixmaps (thanks, DBE) 402 */ 403 if (type & RC_DRAWABLE) { 404 if (type == RT_WINDOW) 405 return offsets[RT_WINDOW & TypeMask]; 406 else 407 return offsets[RT_PIXMAP & TypeMask]; 408 } 409 type = type & TypeMask; 410 if (type < NUM_OFFSETS) 411 return offsets[type]; 412 return -1; 413} 414 415static const char *key_names[PRIVATE_LAST] = { 416 /* XSELinux uses the same private keys for numerous objects */ 417 [PRIVATE_XSELINUX] = "XSELINUX", 418 419 /* Otherwise, you get a private in just the requested structure 420 */ 421 /* These can have objects created before all of the keys are registered */ 422 [PRIVATE_SCREEN] = "SCREEN", 423 [PRIVATE_EXTENSION] = "EXTENSION", 424 [PRIVATE_COLORMAP] = "COLORMAP", 425 426 /* These cannot have any objects before all relevant keys are registered */ 427 [PRIVATE_DEVICE] = "DEVICE", 428 [PRIVATE_CLIENT] = "CLIENT", 429 [PRIVATE_PROPERTY] = "PROPERTY", 430 [PRIVATE_SELECTION] = "SELECTION", 431 [PRIVATE_WINDOW] = "WINDOW", 432 [PRIVATE_PIXMAP] = "PIXMAP", 433 [PRIVATE_GC] = "GC", 434 [PRIVATE_CURSOR] = "CURSOR", 435 [PRIVATE_CURSOR_BITS] = "CURSOR_BITS", 436 437 /* extension privates */ 438 [PRIVATE_DBE_WINDOW] = "DBE_WINDOW", 439 [PRIVATE_DAMAGE] = "DAMAGE", 440 [PRIVATE_GLYPH] = "GLYPH", 441 [PRIVATE_GLYPHSET] = "GLYPHSET", 442 [PRIVATE_PICTURE] = "PICTURE", 443}; 444 445void 446dixPrivateUsage(void) 447{ 448 int objects = 0; 449 int bytes = 0; 450 int alloc = 0; 451 DevPrivateType t; 452 453 for (t = PRIVATE_XSELINUX + 1; t < PRIVATE_LAST; t++) { 454 if (keys[t].offset) { 455 ErrorF("%s: %d objects of %d bytes = %d total bytes %d private allocs\n", 456 key_names[t], keys[t].created, keys[t].offset, keys[t].created * keys[t].offset, 457 keys[t].allocated); 458 bytes += keys[t].created * keys[t].offset; 459 objects += keys[t].created; 460 alloc += keys[t].allocated; 461 } 462 } 463 ErrorF("TOTAL: %d objects, %d bytes, %d allocs\n", 464 objects, bytes, alloc); 465} 466 467void 468dixResetPrivates(void) 469{ 470 DevPrivateType t; 471 472 for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) { 473 DevPrivateKey key, next; 474 475 for (key = keys[t].key; key; key = next) { 476 next = key->next; 477 key->offset = 0; 478 key->initialized = FALSE; 479 key->size = 0; 480 key->type = 0; 481 if (key->allocated) 482 free(key); 483 } 484 if (keys[t].created) { 485 ErrorF("%d %ss still allocated at reset\n", 486 keys[t].created, key_names[t]); 487 dixPrivateUsage(); 488 } 489 keys[t].key = NULL; 490 keys[t].offset = 0; 491 keys[t].created = 0; 492 keys[t].allocated = 0; 493 } 494} 495