Context.c revision eb411b4b
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/* 26 27Copyright 1987, 1988, 1990, 1994, 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 53/* This module implements a simple sparse array. 54 55 XSaveContext(a,b,c,d) will store d in position (a,b,c) of the array. 56 XFindContext(a,b,c,&d) will set d to be the value in position (a,b,c). 57 XDeleteContext(a,b,c) will delete the entry in (a,b,c). 58 59 a is a display id, b is a resource id, and c is a Context. d is just an 60 XPointer. This code will work with any range of parameters, but is geared 61 to be most efficient with very few (one or two) different a's. 62 63*/ 64 65#ifdef HAVE_CONFIG_H 66#include <config.h> 67#endif 68#include "Xlibint.h" 69#include "Xutil.h" 70#ifdef XTHREADS 71#include "locking.h" 72#endif 73 74#define INITHASHMASK 63 /* Number of entries originally in the hash table. */ 75 76typedef struct _TableEntryRec { /* Stores one entry. */ 77 XID rid; 78 XContext context; 79 XPointer data; 80 struct _TableEntryRec *next; 81} TableEntryRec, *TableEntry; 82 83typedef struct _XContextDB { /* Stores hash table for one display. */ 84 TableEntry *table; /* Pointer to array of hash entries. */ 85 int mask; /* Current size of hash table minus 1. */ 86 int numentries; /* Number of entries currently in table. */ 87#ifdef XTHREADS 88 LockInfoRec linfo; 89#endif 90} DBRec, *DB; 91 92#ifdef MOTIFBC 93static DB NullDB = (DB)0; 94#endif 95 96/* Given an XID and a context, returns a value between 0 and HashSize-1. 97 Currently, this requires that HashSize be a power of 2. 98*/ 99 100#define Hash(db,rid,context) \ 101 (db)->table[(((rid) << 1) + context) & (db)->mask] 102 103/* Resize the given db */ 104 105static void ResizeTable(DB db) 106{ 107 TableEntry *otable; 108 register TableEntry entry, next, *pold, *head; 109 register int i, j; 110 111 otable = db->table; 112 for (i = INITHASHMASK+1; (i + i) < db->numentries; ) 113 i += i; 114 db->table = Xcalloc(i, sizeof(TableEntry)); 115 if (!db->table) { 116 db->table = otable; 117 return; 118 } 119 j = db->mask + 1; 120 db->mask = i - 1; 121 for (pold = otable ; --j >= 0; pold++) { 122 for (entry = *pold; entry; entry = next) { 123 next = entry->next; 124 head = &Hash(db, entry->rid, entry->context); 125 entry->next = *head; 126 *head = entry; 127 } 128 } 129 Xfree((char *) otable); 130} 131 132static void _XFreeContextDB(Display *display) 133{ 134 register DB db; 135 register int i; 136 register TableEntry *pentry, entry, next; 137 138 db = display->context_db; 139 if (db) { 140 for (i = db->mask + 1, pentry = db->table ; --i >= 0; pentry++) { 141 for (entry = *pentry; entry; entry = next) { 142 next = entry->next; 143 Xfree((char *)entry); 144 } 145 } 146 Xfree((char *) db->table); 147 _XFreeMutex(&db->linfo); 148 Xfree((char *) db); 149 } 150} 151 152/* Public routines. */ 153 154/* Save the given value of data to correspond with the keys XID and context. 155 Returns nonzero error code if an error has occured, 0 otherwise. 156 Possible errors are Out-of-memory. 157*/ 158 159int XSaveContext( 160 Display *display, 161 register XID rid, 162 register XContext context, 163 _Xconst char* data) 164{ 165 DB *pdb; 166 register DB db; 167 TableEntry *head; 168 register TableEntry entry; 169 170#ifdef MOTIFBC 171 if (!display) { 172 pdb = &NullDB; 173 db = *pdb; 174 } else 175#endif 176 { 177 LockDisplay(display); 178 pdb = &display->context_db; 179 db = *pdb; 180 UnlockDisplay(display); 181 } 182 if (!db) { 183 db = Xmalloc(sizeof(DBRec)); 184 if (!db) 185 return XCNOMEM; 186 db->mask = INITHASHMASK; 187 db->table = Xcalloc(db->mask + 1, sizeof(TableEntry)); 188 if (!db->table) { 189 Xfree((char *)db); 190 return XCNOMEM; 191 } 192 db->numentries = 0; 193 _XCreateMutex(&db->linfo); 194#ifdef MOTIFBC 195 if (!display) *pdb = db; else 196#endif 197 { 198 LockDisplay(display); 199 *pdb = db; 200 display->free_funcs->context_db = _XFreeContextDB; 201 UnlockDisplay(display); 202 } 203 } 204 _XLockMutex(&db->linfo); 205 head = &Hash(db, rid, context); 206 _XUnlockMutex(&db->linfo); 207 for (entry = *head; entry; entry = entry->next) { 208 if (entry->rid == rid && entry->context == context) { 209 entry->data = (XPointer)data; 210 return 0; 211 } 212 } 213 entry = Xmalloc(sizeof(TableEntryRec)); 214 if (!entry) 215 return XCNOMEM; 216 entry->rid = rid; 217 entry->context = context; 218 entry->data = (XPointer)data; 219 entry->next = *head; 220 *head = entry; 221 _XLockMutex(&db->linfo); 222 db->numentries++; 223 if (db->numentries > (db->mask << 2)) 224 ResizeTable(db); 225 _XUnlockMutex(&db->linfo); 226 return 0; 227} 228 229 230 231/* Given an XID and context, returns the associated data. Note that data 232 here is a pointer since it is a return value. Returns nonzero error code 233 if an error has occured, 0 otherwise. Possible errors are Entry-not-found. 234*/ 235 236int XFindContext(Display *display, XID rid, XContext context, XPointer *data) 237{ 238 register DB db; 239 register TableEntry entry; 240 241#ifdef MOTIFBC 242 if (!display) db = NullDB; else 243#endif 244 { 245 LockDisplay(display); 246 db = display->context_db; 247 UnlockDisplay(display); 248 } 249 if (!db) 250 return XCNOENT; 251 _XLockMutex(&db->linfo); 252 for (entry = Hash(db, rid, context); entry; entry = entry->next) 253 { 254 if (entry->rid == rid && entry->context == context) { 255 *data = (XPointer)entry->data; 256 _XUnlockMutex(&db->linfo); 257 return 0; 258 } 259 } 260 _XUnlockMutex(&db->linfo); 261 return XCNOENT; 262} 263 264 265 266/* Deletes the entry for the given XID and context from the datastructure. 267 This returns the same thing that FindContext would have returned if called 268 with the same arguments. 269*/ 270 271int XDeleteContext(Display *display, XID rid, XContext context) 272{ 273 register DB db; 274 register TableEntry entry, *prev; 275 276#ifdef MOTIFBC 277 if (!display) db = NullDB; else 278#endif 279 { 280 LockDisplay(display); 281 db = display->context_db; 282 UnlockDisplay(display); 283 } 284 if (!db) 285 return XCNOENT; 286 _XLockMutex(&db->linfo); 287 for (prev = &Hash(db, rid, context); 288 (entry = *prev); 289 prev = &entry->next) { 290 if (entry->rid == rid && entry->context == context) { 291 *prev = entry->next; 292 Xfree((char *) entry); 293 db->numentries--; 294 if (db->numentries < db->mask && db->mask > INITHASHMASK) 295 ResizeTable(db); 296 _XUnlockMutex(&db->linfo); 297 return 0; 298 } 299 } 300 _XUnlockMutex(&db->linfo); 301 return XCNOENT; 302} 303