Quarks.c revision 61b2299d
1/* $Xorg: Quarks.c,v 1.5 2001/02/09 02:03:35 xorgcvs Exp $ */
2
3/***********************************************************
4Copyright 1987, 1988, 1990 by Digital Equipment Corporation, Maynard,
5
6                        All Rights Reserved
7
8Permission to use, copy, modify, and distribute this software and its
9documentation for any purpose and without fee is hereby granted,
10provided that the above copyright notice appear in all copies and that
11both that copyright notice and this permission notice appear in
12supporting documentation, and that the name Digital not be
13used in advertising or publicity pertaining to distribution of the
14software without specific, written prior permission.
15
16DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
17ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
18DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
19ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
20WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
21ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
22SOFTWARE.
23
24******************************************************************/
25/*
26
27Copyright 1987, 1988, 1990, 1998  The Open Group
28
29Permission to use, copy, modify, distribute, and sell this software and its
30documentation for any purpose is hereby granted without fee, provided that
31the above copyright notice appear in all copies and that both that
32copyright notice and this permission notice appear in supporting
33documentation.
34
35The above copyright notice and this permission notice shall be included
36in all copies or substantial portions of the Software.
37
38THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
39OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
40MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
41IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
42OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
43ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
44OTHER DEALINGS IN THE SOFTWARE.
45
46Except as contained in this notice, the name of The Open Group shall
47not be used in advertising or otherwise to promote the sale, use or
48other dealings in this Software without prior written authorization
49from The Open Group.
50
51*/
52/* $XFree86: xc/lib/X11/Quarks.c,v 1.6 2003/04/13 19:22:17 dawes Exp $ */
53
54#ifdef HAVE_CONFIG_H
55#include <config.h>
56#endif
57#include "Xlibint.h"
58#include <X11/Xresource.h>
59#include "Xresinternal.h"
60
61/* Not cost effective, at least for vanilla MIT clients */
62/* #define PERMQ */
63
64#ifdef PERMQ
65typedef unsigned char Bits;
66#endif
67typedef unsigned long Entry; /* dont confuse with EntryRec from Xintatom.h */
68
69static XrmQuark nextQuark = 1;	/* next available quark number */
70static unsigned long quarkMask = 0;
71static Entry zero = 0;
72static Entry *quarkTable = &zero; /* crock */
73static unsigned long quarkRehash;
74static XrmString **stringTable = NULL;
75#ifdef PERMQ
76static Bits **permTable = NULL;
77#endif
78static XrmQuark nextUniq = -1;	/* next quark from XrmUniqueQuark */
79
80#define QUANTUMSHIFT	8
81#define QUANTUMMASK	((1 << QUANTUMSHIFT) - 1)
82#define CHUNKPER	8
83#define CHUNKMASK	((CHUNKPER << QUANTUMSHIFT) - 1)
84
85#define LARGEQUARK	((Entry)0x80000000L)
86#define QUARKSHIFT	18
87#define QUARKMASK	((LARGEQUARK - 1) >> QUARKSHIFT)
88#define XSIGMASK	((1L << QUARKSHIFT) - 1)
89
90#define STRQUANTSIZE	(sizeof(XrmString) * (QUANTUMMASK + 1))
91#ifdef PERMQ
92#define QUANTSIZE	(STRQUANTSIZE + \
93			 (sizeof(Bits) * ((QUANTUMMASK + 1) >> 3))
94#else
95#define QUANTSIZE	STRQUANTSIZE
96#endif
97
98#define HASH(sig) ((sig) & quarkMask)
99#define REHASHVAL(sig) ((((sig) % quarkRehash) + 2) | 1)
100#define REHASH(idx,rehash) ((idx + rehash) & quarkMask)
101#define NAME(q) stringTable[(q) >> QUANTUMSHIFT][(q) & QUANTUMMASK]
102#ifdef PERMQ
103#define BYTEREF(q) permTable[(q) >> QUANTUMSHIFT][((q) & QUANTUMMASK) >> 3]
104#define ISPERM(q) (BYTEREF(q) & (1 << ((q) & 7)))
105#define SETPERM(q) BYTEREF(q) |= (1 << ((q) & 7))
106#define CLEARPERM(q) BYTEREF(q) &= ~(1 << ((q) & 7))
107#endif
108
109/* Permanent memory allocation */
110
111#define WALIGN sizeof(unsigned long)
112#define DALIGN sizeof(double)
113
114#define NEVERFREETABLESIZE ((8192-12) & ~(DALIGN-1))
115static char *neverFreeTable = NULL;
116static int  neverFreeTableSize = 0;
117
118static char *permalloc(unsigned int length)
119{
120    char *ret;
121
122    if (neverFreeTableSize < length) {
123	if (length >= NEVERFREETABLESIZE)
124	    return Xmalloc(length);
125	if (! (ret = Xmalloc(NEVERFREETABLESIZE)))
126	    return (char *) NULL;
127	neverFreeTableSize = NEVERFREETABLESIZE;
128	neverFreeTable = ret;
129    }
130    ret = neverFreeTable;
131    neverFreeTable += length;
132    neverFreeTableSize -= length;
133    return(ret);
134}
135
136#ifndef WORD64
137typedef struct {char a; double b;} TestType1;
138typedef struct {char a; unsigned long b;} TestType2;
139#endif
140
141#ifdef XTHREADS
142static char *_Xpermalloc(unsigned int length);
143
144char *Xpermalloc(unsigned int length)
145{
146    char *p;
147
148    _XLockMutex(_Xglobal_lock);
149    p = _Xpermalloc(length);
150    _XUnlockMutex(_Xglobal_lock);
151    return p;
152}
153#define Xpermalloc _Xpermalloc
154
155static
156#endif /* XTHREADS */
157char *Xpermalloc(unsigned int length)
158{
159    int i;
160
161    if (neverFreeTableSize && length < NEVERFREETABLESIZE) {
162#ifndef WORD64
163	if ((sizeof(TestType1) !=
164	     (sizeof(TestType2) - sizeof(unsigned long) + sizeof(double))) &&
165	    !(length & (DALIGN-1)) &&
166	    ((i = (NEVERFREETABLESIZE - neverFreeTableSize) & (DALIGN-1)))) {
167	    neverFreeTableSize -= DALIGN - i;
168	    neverFreeTable += DALIGN - i;
169	} else
170#endif
171	    if ((i = (NEVERFREETABLESIZE - neverFreeTableSize) & (WALIGN-1))) {
172		neverFreeTableSize -= WALIGN - i;
173		neverFreeTable += WALIGN - i;
174	    }
175    }
176    return permalloc(length);
177}
178
179static Bool
180ExpandQuarkTable(void)
181{
182    unsigned long oldmask, newmask;
183    register char c, *s;
184    register Entry *oldentries, *entries;
185    register Entry entry;
186    register int oldidx, newidx, rehash;
187    Signature sig;
188    XrmQuark q;
189
190    oldentries = quarkTable;
191    if ((oldmask = quarkMask))
192	newmask = (oldmask << 1) + 1;
193    else {
194	if (!stringTable) {
195	    stringTable = (XrmString **)Xmalloc(sizeof(XrmString *) *
196						CHUNKPER);
197	    if (!stringTable)
198		return False;
199	    stringTable[0] = (XrmString *)NULL;
200	}
201#ifdef PERMQ
202	if (!permTable)
203	    permTable = (Bits **)Xmalloc(sizeof(Bits *) * CHUNKPER);
204	if (!permTable)
205	    return False;
206#endif
207	stringTable[0] = (XrmString *)Xpermalloc(QUANTSIZE);
208	if (!stringTable[0])
209	    return False;
210#ifdef PERMQ
211	permTable[0] = (Bits *)((char *)stringTable[0] + STRQUANTSIZE);
212#endif
213	newmask = 0x1ff;
214    }
215    entries = (Entry *)Xmalloc(sizeof(Entry) * (newmask + 1));
216    if (!entries)
217	return False;
218    bzero((char *)entries, sizeof(Entry) * (newmask + 1));
219    quarkTable = entries;
220    quarkMask = newmask;
221    quarkRehash = quarkMask - 2;
222    for (oldidx = 0; oldidx <= oldmask; oldidx++) {
223	if ((entry = oldentries[oldidx])) {
224	    if (entry & LARGEQUARK)
225		q = entry & (LARGEQUARK-1);
226	    else
227		q = (entry >> QUARKSHIFT) & QUARKMASK;
228	    for (sig = 0, s = NAME(q); (c = *s++); )
229		sig = (sig << 1) + c;
230	    newidx = HASH(sig);
231	    if (entries[newidx]) {
232		rehash = REHASHVAL(sig);
233		do {
234		    newidx = REHASH(newidx, rehash);
235		} while (entries[newidx]);
236	    }
237	    entries[newidx] = entry;
238	}
239    }
240    if (oldmask)
241	Xfree((char *)oldentries);
242    return True;
243}
244
245XrmQuark
246_XrmInternalStringToQuark(
247    register _Xconst char *name, register int len, register Signature sig,
248    Bool permstring)
249{
250    register XrmQuark q;
251    register Entry entry;
252    register int idx, rehash;
253    register int i;
254    register char *s1, *s2;
255    char *new;
256
257    rehash = 0;
258    idx = HASH(sig);
259    _XLockMutex(_Xglobal_lock);
260    while ((entry = quarkTable[idx])) {
261	if (entry & LARGEQUARK)
262	    q = entry & (LARGEQUARK-1);
263	else {
264	    if ((entry - sig) & XSIGMASK)
265		goto nomatch;
266	    q = (entry >> QUARKSHIFT) & QUARKMASK;
267	}
268	for (i = len, s1 = (char *)name, s2 = NAME(q); --i >= 0; ) {
269	    if (*s1++ != *s2++)
270		goto nomatch;
271	}
272	if (*s2) {
273nomatch:    if (!rehash)
274		rehash = REHASHVAL(sig);
275	    idx = REHASH(idx, rehash);
276	    continue;
277	}
278#ifdef PERMQ
279	if (permstring && !ISPERM(q)) {
280	    Xfree(NAME(q));
281	    NAME(q) = (char *)name;
282	    SETPERM(q);
283	}
284#endif
285	_XUnlockMutex(_Xglobal_lock);
286	return q;
287    }
288    if (nextUniq == nextQuark)
289	goto fail;
290    if ((nextQuark + (nextQuark >> 2)) > quarkMask) {
291	if (!ExpandQuarkTable())
292	    goto fail;
293	_XUnlockMutex(_Xglobal_lock);
294	return _XrmInternalStringToQuark(name, len, sig, permstring);
295    }
296    q = nextQuark;
297    if (!(q & QUANTUMMASK)) {
298	if (!(q & CHUNKMASK)) {
299	    if (!(new = Xrealloc((char *)stringTable,
300				 sizeof(XrmString *) *
301				 ((q >> QUANTUMSHIFT) + CHUNKPER))))
302		goto fail;
303	    stringTable = (XrmString **)new;
304#ifdef PERMQ
305	    if (!(new = Xrealloc((char *)permTable,
306				 sizeof(Bits *) *
307				 ((q >> QUANTUMSHIFT) + CHUNKPER))))
308		goto fail;
309	    permTable = (Bits **)new;
310#endif
311	}
312	new = Xpermalloc(QUANTSIZE);
313	if (!new)
314	    goto fail;
315	stringTable[q >> QUANTUMSHIFT] = (XrmString *)new;
316#ifdef PERMQ
317	permTable[q >> QUANTUMSHIFT] = (Bits *)(new + STRQUANTSIZE);
318#endif
319    }
320    if (!permstring) {
321	s2 = (char *)name;
322#ifdef PERMQ
323	name = Xmalloc(len+1);
324#else
325	name = permalloc(len+1);
326#endif
327	if (!name)
328	    goto fail;
329	for (i = len, s1 = (char *)name; --i >= 0; )
330	    *s1++ = *s2++;
331	*s1++ = '\0';
332#ifdef PERMQ
333	CLEARPERM(q);
334    }
335    else {
336	SETPERM(q);
337#endif
338    }
339    NAME(q) = (char *)name;
340    if (q <= QUARKMASK)
341	entry = (q << QUARKSHIFT) | (sig & XSIGMASK);
342    else
343	entry = q | LARGEQUARK;
344    quarkTable[idx] = entry;
345    nextQuark++;
346    _XUnlockMutex(_Xglobal_lock);
347    return q;
348 fail:
349    _XUnlockMutex(_Xglobal_lock);
350    return NULLQUARK;
351}
352
353XrmQuark
354XrmStringToQuark(
355    _Xconst char *name)
356{
357    register char c, *tname;
358    register Signature sig = 0;
359
360    if (!name)
361	return (NULLQUARK);
362
363    for (tname = (char *)name; (c = *tname++); )
364	sig = (sig << 1) + c;
365
366    return _XrmInternalStringToQuark(name, tname-(char *)name-1, sig, False);
367}
368
369XrmQuark
370XrmPermStringToQuark(
371    _Xconst char *name)
372{
373    register char c, *tname;
374    register Signature sig = 0;
375
376    if (!name)
377	return (NULLQUARK);
378
379    for (tname = (char *)name; (c = *tname++); )
380	sig = (sig << 1) + c;
381
382    return _XrmInternalStringToQuark(name, tname-(char *)name-1, sig, True);
383}
384
385XrmQuark XrmUniqueQuark(void)
386{
387    XrmQuark q;
388
389    _XLockMutex(_Xglobal_lock);
390    if (nextUniq == nextQuark)
391	q = NULLQUARK;
392    else
393	q = nextUniq--;
394    _XUnlockMutex(_Xglobal_lock);
395    return q;
396}
397
398XrmString XrmQuarkToString(register XrmQuark quark)
399{
400    XrmString s;
401
402    _XLockMutex(_Xglobal_lock);
403    if (quark <= 0 || quark >= nextQuark)
404    	s = NULLSTRING;
405    else {
406#ifdef PERMQ
407	/* We have to mark the quark as permanent, since the caller might hold
408	 * onto the string pointer forver.
409	 */
410	SETPERM(quark);
411#endif
412	s = NAME(quark);
413    }
414    _XUnlockMutex(_Xglobal_lock);
415    return s;
416}
417