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