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 240Bool 241dixRegisterScreenPrivateKey(DevScreenPrivateKey screenKey, ScreenPtr pScreen, DevPrivateType type, unsigned size) 242{ 243 DevPrivateKey key; 244 245 if (!dixRegisterPrivateKey(&screenKey->screenKey, PRIVATE_SCREEN, 0)) 246 return FALSE; 247 key = dixGetPrivate(&pScreen->devPrivates, &screenKey->screenKey); 248 if (key != NULL) { 249 assert(key->size == size); 250 assert(key->type == type); 251 return TRUE; 252 } 253 key = calloc(sizeof (DevPrivateKeyRec), 1); 254 if (!key) 255 return FALSE; 256 if (!dixRegisterPrivateKey(key, type, size)) { 257 free(key); 258 return FALSE; 259 } 260 key->allocated = TRUE; 261 dixSetPrivate(&pScreen->devPrivates, &screenKey->screenKey, key); 262 return TRUE; 263} 264 265DevPrivateKey 266_dixGetScreenPrivateKey(const DevScreenPrivateKey key, ScreenPtr pScreen) 267{ 268 return dixGetPrivate(&pScreen->devPrivates, &key->screenKey); 269} 270 271/* 272 * Initialize privates by zeroing them 273 */ 274void 275_dixInitPrivates(PrivatePtr *privates, void *addr, DevPrivateType type) 276{ 277 keys[type].created++; 278 if (xselinux_private[type]) 279 keys[PRIVATE_XSELINUX].created++; 280 if (keys[type].offset == 0) 281 addr = 0; 282 *privates = addr; 283 memset(addr, '\0', keys[type].offset); 284} 285 286/* 287 * Clean up privates 288 */ 289void 290_dixFiniPrivates(PrivatePtr privates, DevPrivateType type) 291{ 292 keys[type].created--; 293 if (xselinux_private[type]) 294 keys[PRIVATE_XSELINUX].created--; 295} 296 297/* 298 * Allocate new object with privates. 299 * 300 * This is expected to be invoked from the 301 * dixAllocateObjectWithPrivates macro 302 */ 303void * 304_dixAllocateObjectWithPrivates(unsigned baseSize, unsigned clear, unsigned offset, DevPrivateType type) 305{ 306 unsigned totalSize; 307 void *object; 308 PrivatePtr privates; 309 PrivatePtr *devPrivates; 310 311 assert (type > PRIVATE_SCREEN && type < PRIVATE_LAST); 312 313 /* round up so that void * is aligned */ 314 baseSize = (baseSize + sizeof (void *) - 1) & ~(sizeof (void *) - 1); 315 totalSize = baseSize + keys[type].offset; 316 object = malloc(totalSize); 317 if (!object) 318 return NULL; 319 320 memset(object, '\0', clear); 321 privates = (PrivatePtr) (((char *) object) + baseSize); 322 devPrivates = (PrivatePtr *) ((char *) object + offset); 323 324 _dixInitPrivates(devPrivates, privates, type); 325 326 return object; 327} 328 329/* 330 * Allocate privates separately from containing object. 331 * Used for clients and screens. 332 */ 333Bool 334dixAllocatePrivates(PrivatePtr *privates, DevPrivateType type) 335{ 336 unsigned size; 337 PrivatePtr p; 338 339 assert (type > PRIVATE_XSELINUX && type < PRIVATE_LAST); 340 341 size = keys[type].offset; 342 if (!size) { 343 p = NULL; 344 } else { 345 if (!(p = malloc(size))) 346 return FALSE; 347 } 348 349 _dixInitPrivates(privates, p, type); 350 ++keys[type].allocated; 351 352 return TRUE; 353} 354 355/* 356 * Free an object that has privates 357 * 358 * This is expected to be invoked from the 359 * dixFreeObjectWithPrivates macro 360 */ 361void 362_dixFreeObjectWithPrivates(void *object, PrivatePtr privates, DevPrivateType type) 363{ 364 _dixFiniPrivates(privates, type); 365 free(object); 366} 367 368/* 369 * Called to free screen or client privates 370 */ 371void 372dixFreePrivates(PrivatePtr privates, DevPrivateType type) 373{ 374 _dixFiniPrivates(privates, type); 375 --keys[type].allocated; 376 free(privates); 377} 378 379/* 380 * Return size of privates for the specified type 381 */ 382extern _X_EXPORT int 383dixPrivatesSize(DevPrivateType type) 384{ 385 assert (type >= PRIVATE_SCREEN && type < PRIVATE_LAST); 386 387 return keys[type].offset; 388} 389 390/* Table of devPrivates offsets */ 391static const int offsets[] = { 392 -1, /* RT_NONE */ 393 offsetof(WindowRec, devPrivates), /* RT_WINDOW */ 394 offsetof(PixmapRec, devPrivates), /* RT_PIXMAP */ 395 offsetof(GC, devPrivates), /* RT_GC */ 396 -1, /* RT_FONT */ 397 offsetof(CursorRec, devPrivates), /* RT_CURSOR */ 398 offsetof(ColormapRec, devPrivates), /* RT_COLORMAP */ 399}; 400 401#define NUM_OFFSETS (sizeof (offsets) / sizeof (offsets[0])) 402 403int 404dixLookupPrivateOffset(RESTYPE type) 405{ 406 /* 407 * Special kludge for DBE which registers a new resource type that 408 * points at pixmaps (thanks, DBE) 409 */ 410 if (type & RC_DRAWABLE) { 411 if (type == RT_WINDOW) 412 return offsets[RT_WINDOW & TypeMask]; 413 else 414 return offsets[RT_PIXMAP & TypeMask]; 415 } 416 type = type & TypeMask; 417 if (type < NUM_OFFSETS) 418 return offsets[type]; 419 return -1; 420} 421 422static const char *key_names[PRIVATE_LAST] = { 423 /* XSELinux uses the same private keys for numerous objects */ 424 [PRIVATE_XSELINUX] = "XSELINUX", 425 426 /* Otherwise, you get a private in just the requested structure 427 */ 428 /* These can have objects created before all of the keys are registered */ 429 [PRIVATE_SCREEN] = "SCREEN", 430 [PRIVATE_EXTENSION] = "EXTENSION", 431 [PRIVATE_COLORMAP] = "COLORMAP", 432 433 /* These cannot have any objects before all relevant keys are registered */ 434 [PRIVATE_DEVICE] = "DEVICE", 435 [PRIVATE_CLIENT] = "CLIENT", 436 [PRIVATE_PROPERTY] = "PROPERTY", 437 [PRIVATE_SELECTION] = "SELECTION", 438 [PRIVATE_WINDOW] = "WINDOW", 439 [PRIVATE_PIXMAP] = "PIXMAP", 440 [PRIVATE_GC] = "GC", 441 [PRIVATE_CURSOR] = "CURSOR", 442 [PRIVATE_CURSOR_BITS] = "CURSOR_BITS", 443 444 /* extension privates */ 445 [PRIVATE_DBE_WINDOW] = "DBE_WINDOW", 446 [PRIVATE_DAMAGE] = "DAMAGE", 447 [PRIVATE_GLYPH] = "GLYPH", 448 [PRIVATE_GLYPHSET] = "GLYPHSET", 449 [PRIVATE_PICTURE] = "PICTURE", 450 [PRIVATE_SYNC_FENCE] = "SYNC_FENCE", 451}; 452 453void 454dixPrivateUsage(void) 455{ 456 int objects = 0; 457 int bytes = 0; 458 int alloc = 0; 459 DevPrivateType t; 460 461 for (t = PRIVATE_XSELINUX + 1; t < PRIVATE_LAST; t++) { 462 if (keys[t].offset) { 463 ErrorF("%s: %d objects of %d bytes = %d total bytes %d private allocs\n", 464 key_names[t], keys[t].created, keys[t].offset, keys[t].created * keys[t].offset, 465 keys[t].allocated); 466 bytes += keys[t].created * keys[t].offset; 467 objects += keys[t].created; 468 alloc += keys[t].allocated; 469 } 470 } 471 ErrorF("TOTAL: %d objects, %d bytes, %d allocs\n", 472 objects, bytes, alloc); 473} 474 475void 476dixResetPrivates(void) 477{ 478 DevPrivateType t; 479 480 for (t = PRIVATE_XSELINUX; t < PRIVATE_LAST; t++) { 481 DevPrivateKey key, next; 482 483 for (key = keys[t].key; key; key = next) { 484 next = key->next; 485 key->offset = 0; 486 key->initialized = FALSE; 487 key->size = 0; 488 key->type = 0; 489 if (key->allocated) 490 free(key); 491 } 492 if (keys[t].created) { 493 ErrorF("%d %ss still allocated at reset\n", 494 keys[t].created, key_names[t]); 495 dixPrivateUsage(); 496 } 497 keys[t].key = NULL; 498 keys[t].offset = 0; 499 keys[t].created = 0; 500 keys[t].allocated = 0; 501 } 502} 503