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