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