Quarks.c revision 258a0ebe
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#include "reallocarray.h" 59 60/* Not cost effective, at least for vanilla MIT clients */ 61/* #define PERMQ */ 62 63#ifdef PERMQ 64typedef unsigned char Bits; 65#endif 66typedef unsigned long Entry; /* dont confuse with EntryRec from Xintatom.h */ 67 68static XrmQuark nextQuark = 1; /* next available quark number */ 69static unsigned long quarkMask = 0; 70static Entry zero = 0; 71static Entry *quarkTable = &zero; /* crock */ 72static unsigned long quarkRehash; 73static XrmString **stringTable = NULL; 74#ifdef PERMQ 75static Bits **permTable = NULL; 76#endif 77static XrmQuark nextUniq = -1; /* next quark from XrmUniqueQuark */ 78 79#define QUANTUMSHIFT 8 80#define QUANTUMMASK ((1 << QUANTUMSHIFT) - 1) 81#define CHUNKPER 8 82#define CHUNKMASK ((CHUNKPER << QUANTUMSHIFT) - 1) 83 84#define LARGEQUARK ((Entry)0x80000000L) 85#define QUARKSHIFT 18 86#define QUARKMASK ((LARGEQUARK - 1) >> QUARKSHIFT) 87#define XSIGMASK ((1L << QUARKSHIFT) - 1) 88 89#define STRQUANTSIZE (sizeof(XrmString) * (QUANTUMMASK + 1)) 90#ifdef PERMQ 91#define QUANTSIZE (STRQUANTSIZE + \ 92 (sizeof(Bits) * ((QUANTUMMASK + 1) >> 3)) 93#else 94#define QUANTSIZE STRQUANTSIZE 95#endif 96 97#define HASH(sig) ((sig) & quarkMask) 98#define REHASHVAL(sig) ((((sig) % quarkRehash) + 2) | 1) 99#define REHASH(idx,rehash) ((idx + rehash) & quarkMask) 100#define NAME(q) stringTable[(q) >> QUANTUMSHIFT][(q) & QUANTUMMASK] 101#ifdef PERMQ 102#define BYTEREF(q) permTable[(q) >> QUANTUMSHIFT][((q) & QUANTUMMASK) >> 3] 103#define ISPERM(q) (BYTEREF(q) & (1 << ((q) & 7))) 104#define SETPERM(q) BYTEREF(q) |= (1 << ((q) & 7)) 105#define CLEARPERM(q) BYTEREF(q) &= ~(1 << ((q) & 7)) 106#endif 107 108/* Permanent memory allocation */ 109 110#define WALIGN sizeof(unsigned long) 111#define DALIGN sizeof(double) 112 113#define NEVERFREETABLESIZE ((8192-12) & ~(DALIGN-1)) 114static char *neverFreeTable = NULL; 115static int neverFreeTableSize = 0; 116 117static char *permalloc(unsigned int length) 118{ 119 char *ret; 120 121 if (neverFreeTableSize < length) { 122 if (length >= NEVERFREETABLESIZE) 123 return Xmalloc(length); 124 if (! (ret = Xmalloc(NEVERFREETABLESIZE))) 125 return (char *) NULL; 126 neverFreeTableSize = NEVERFREETABLESIZE; 127 neverFreeTable = ret; 128 } 129 ret = neverFreeTable; 130 neverFreeTable += length; 131 neverFreeTableSize -= length; 132 return(ret); 133} 134 135typedef struct {char a; double b;} TestType1; 136typedef struct {char a; unsigned long b;} TestType2; 137 138#ifdef XTHREADS 139static char *_Xpermalloc(unsigned int length); 140 141char *Xpermalloc(unsigned int length) 142{ 143 char *p; 144 145 _XLockMutex(_Xglobal_lock); 146 p = _Xpermalloc(length); 147 _XUnlockMutex(_Xglobal_lock); 148 return p; 149} 150#define Xpermalloc _Xpermalloc 151 152static 153#endif /* XTHREADS */ 154char *Xpermalloc(unsigned int length) 155{ 156 int i; 157 158 if (neverFreeTableSize && length < NEVERFREETABLESIZE) { 159 if ((sizeof(TestType1) != 160 (sizeof(TestType2) - sizeof(unsigned long) + sizeof(double))) && 161 !(length & (DALIGN-1)) && 162 ((i = (NEVERFREETABLESIZE - neverFreeTableSize) & (DALIGN-1)))) { 163 neverFreeTableSize -= DALIGN - i; 164 neverFreeTable += DALIGN - i; 165 } else 166 if ((i = (NEVERFREETABLESIZE - neverFreeTableSize) & (WALIGN-1))) { 167 neverFreeTableSize -= WALIGN - i; 168 neverFreeTable += WALIGN - i; 169 } 170 } 171 return permalloc(length); 172} 173 174static Bool 175ExpandQuarkTable(void) 176{ 177 unsigned long oldmask, newmask; 178 register char c, *s; 179 register Entry *oldentries, *entries; 180 register Entry entry; 181 register int oldidx, newidx, rehash; 182 Signature sig; 183 XrmQuark q; 184 185 oldentries = quarkTable; 186 if ((oldmask = quarkMask)) 187 newmask = (oldmask << 1) + 1; 188 else { 189 if (!stringTable) { 190 stringTable = Xmalloc(sizeof(XrmString *) * CHUNKPER); 191 if (!stringTable) 192 return False; 193 stringTable[0] = (XrmString *)NULL; 194 } 195#ifdef PERMQ 196 if (!permTable) 197 permTable = Xmalloc(sizeof(Bits *) * CHUNKPER); 198 if (!permTable) 199 return False; 200#endif 201 stringTable[0] = (XrmString *)Xpermalloc(QUANTSIZE); 202 if (!stringTable[0]) 203 return False; 204#ifdef PERMQ 205 permTable[0] = (Bits *)((char *)stringTable[0] + STRQUANTSIZE); 206#endif 207 newmask = 0x1ff; 208 } 209 entries = Xcalloc(newmask + 1, sizeof(Entry)); 210 if (!entries) 211 return False; 212 quarkTable = entries; 213 quarkMask = newmask; 214 quarkRehash = quarkMask - 2; 215 for (oldidx = 0; oldidx <= oldmask; oldidx++) { 216 if ((entry = oldentries[oldidx])) { 217 if (entry & LARGEQUARK) 218 q = entry & (LARGEQUARK-1); 219 else 220 q = (entry >> QUARKSHIFT) & QUARKMASK; 221 for (sig = 0, s = NAME(q); (c = *s++); ) 222 sig = (sig << 1) + c; 223 newidx = HASH(sig); 224 if (entries[newidx]) { 225 rehash = REHASHVAL(sig); 226 do { 227 newidx = REHASH(newidx, rehash); 228 } while (entries[newidx]); 229 } 230 entries[newidx] = entry; 231 } 232 } 233 if (oldmask) 234 Xfree(oldentries); 235 return True; 236} 237 238XrmQuark 239_XrmInternalStringToQuark( 240 register _Xconst char *name, register int len, register Signature sig, 241 Bool permstring) 242{ 243 register XrmQuark q; 244 register Entry entry; 245 register int idx, rehash; 246 register int i; 247 register char *s1, *s2; 248 char *new; 249 250 rehash = 0; 251 idx = HASH(sig); 252 _XLockMutex(_Xglobal_lock); 253 while ((entry = quarkTable[idx])) { 254 if (entry & LARGEQUARK) 255 q = entry & (LARGEQUARK-1); 256 else { 257 if ((entry - sig) & XSIGMASK) 258 goto nomatch; 259 q = (entry >> QUARKSHIFT) & QUARKMASK; 260 } 261 for (i = len, s1 = (char *)name, s2 = NAME(q); --i >= 0; ) { 262 if (*s1++ != *s2++) 263 goto nomatch; 264 } 265 if (*s2) { 266nomatch: if (!rehash) 267 rehash = REHASHVAL(sig); 268 idx = REHASH(idx, rehash); 269 continue; 270 } 271#ifdef PERMQ 272 if (permstring && !ISPERM(q)) { 273 Xfree(NAME(q)); 274 NAME(q) = (char *)name; 275 SETPERM(q); 276 } 277#endif 278 _XUnlockMutex(_Xglobal_lock); 279 return q; 280 } 281 if (nextUniq == nextQuark) 282 goto fail; 283 if ((nextQuark + (nextQuark >> 2)) > quarkMask) { 284 if (!ExpandQuarkTable()) 285 goto fail; 286 _XUnlockMutex(_Xglobal_lock); 287 return _XrmInternalStringToQuark(name, len, sig, permstring); 288 } 289 q = nextQuark; 290 if (!(q & QUANTUMMASK)) { 291 if (!(q & CHUNKMASK)) { 292 if (!(new = Xreallocarray(stringTable, 293 (q >> QUANTUMSHIFT) + CHUNKPER, 294 sizeof(XrmString *)))) 295 goto fail; 296 stringTable = (XrmString **)new; 297#ifdef PERMQ 298 if (!(new = Xreallocarray(permTable, 299 (q >> QUANTUMSHIFT) + CHUNKPER, 300 sizeof(Bits *)))) 301 goto fail; 302 permTable = (Bits **)new; 303#endif 304 } 305 new = Xpermalloc(QUANTSIZE); 306 if (!new) 307 goto fail; 308 stringTable[q >> QUANTUMSHIFT] = (XrmString *)new; 309#ifdef PERMQ 310 permTable[q >> QUANTUMSHIFT] = (Bits *)(new + STRQUANTSIZE); 311#endif 312 } 313 if (!permstring) { 314 s2 = (char *)name; 315#ifdef PERMQ 316 name = Xmalloc(len+1); 317#else 318 name = permalloc(len+1); 319#endif 320 if (!name) 321 goto fail; 322 for (i = len, s1 = (char *)name; --i >= 0; ) 323 *s1++ = *s2++; 324 *s1++ = '\0'; 325#ifdef PERMQ 326 CLEARPERM(q); 327 } 328 else { 329 SETPERM(q); 330#endif 331 } 332 NAME(q) = (char *)name; 333 if (q <= QUARKMASK) 334 entry = (q << QUARKSHIFT) | (sig & XSIGMASK); 335 else 336 entry = q | LARGEQUARK; 337 quarkTable[idx] = entry; 338 nextQuark++; 339 _XUnlockMutex(_Xglobal_lock); 340 return q; 341 fail: 342 _XUnlockMutex(_Xglobal_lock); 343 return NULLQUARK; 344} 345 346XrmQuark 347XrmStringToQuark( 348 _Xconst char *name) 349{ 350 register char c, *tname; 351 register Signature sig = 0; 352 353 if (!name) 354 return (NULLQUARK); 355 356 for (tname = (char *)name; (c = *tname++); ) 357 sig = (sig << 1) + c; 358 359 return _XrmInternalStringToQuark(name, tname-(char *)name-1, sig, False); 360} 361 362XrmQuark 363XrmPermStringToQuark( 364 _Xconst char *name) 365{ 366 register char c, *tname; 367 register Signature sig = 0; 368 369 if (!name) 370 return (NULLQUARK); 371 372 for (tname = (char *)name; (c = *tname++); ) 373 sig = (sig << 1) + c; 374 375 return _XrmInternalStringToQuark(name, tname-(char *)name-1, sig, True); 376} 377 378XrmQuark XrmUniqueQuark(void) 379{ 380 XrmQuark q; 381 382 _XLockMutex(_Xglobal_lock); 383 if (nextUniq == nextQuark) 384 q = NULLQUARK; 385 else 386 q = nextUniq--; 387 _XUnlockMutex(_Xglobal_lock); 388 return q; 389} 390 391XrmString XrmQuarkToString(register XrmQuark quark) 392{ 393 XrmString s; 394 395 _XLockMutex(_Xglobal_lock); 396 if (quark <= 0 || quark >= nextQuark) 397 s = NULLSTRING; 398 else { 399#ifdef PERMQ 400 /* We have to mark the quark as permanent, since the caller might hold 401 * onto the string pointer forver. 402 */ 403 SETPERM(quark); 404#endif 405 s = NAME(quark); 406 } 407 _XUnlockMutex(_Xglobal_lock); 408 return s; 409} 410