Context.c revision 1ab64890
1/* $Xorg: Context.c,v 1.5 2001/02/09 02:03:31 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/* 27 28Copyright 1987, 1988, 1990, 1994, 1998 The Open Group 29 30Permission to use, copy, modify, distribute, and sell this software and its 31documentation for any purpose is hereby granted without fee, provided that 32the above copyright notice appear in all copies and that both that 33copyright notice and this permission notice appear in supporting 34documentation. 35 36The above copyright notice and this permission notice shall be included 37in all copies or substantial portions of the Software. 38 39THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 40OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 41MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 42IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR 43OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 44ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 45OTHER DEALINGS IN THE SOFTWARE. 46 47Except as contained in this notice, the name of The Open Group shall 48not be used in advertising or otherwise to promote the sale, use or 49other dealings in this Software without prior written authorization 50from The Open Group. 51 52*/ 53/* $XFree86: xc/lib/X11/Context.c,v 1.5 2001/12/14 19:53:58 dawes Exp $ */ 54 55/* This module implements a simple sparse array. 56 57 XSaveContext(a,b,c,d) will store d in position (a,b,c) of the array. 58 XFindContext(a,b,c,&d) will set d to be the value in position (a,b,c). 59 XDeleteContext(a,b,c) will delete the entry in (a,b,c). 60 61 a is a display id, b is a resource id, and c is a Context. d is just an 62 XPointer. This code will work with any range of parameters, but is geared 63 to be most efficient with very few (one or two) different a's. 64 65*/ 66 67#ifdef HAVE_CONFIG_H 68#include <config.h> 69#endif 70#include "Xlibint.h" 71#include "Xutil.h" 72#ifdef XTHREADS 73#include "locking.h" 74#endif 75 76#define INITHASHMASK 63 /* Number of entries originally in the hash table. */ 77 78typedef struct _TableEntryRec { /* Stores one entry. */ 79 XID rid; 80 XContext context; 81 XPointer data; 82 struct _TableEntryRec *next; 83} TableEntryRec, *TableEntry; 84 85typedef struct _XContextDB { /* Stores hash table for one display. */ 86 TableEntry *table; /* Pointer to array of hash entries. */ 87 int mask; /* Current size of hash table minus 1. */ 88 int numentries; /* Number of entries currently in table. */ 89#ifdef XTHREADS 90 LockInfoRec linfo; 91#endif 92} DBRec, *DB; 93 94#ifdef MOTIFBC 95static DB NullDB = (DB)0; 96#endif 97 98/* Given an XID and a context, returns a value between 0 and HashSize-1. 99 Currently, this requires that HashSize be a power of 2. 100*/ 101 102#define Hash(db,rid,context) \ 103 (db)->table[(((rid) << 1) + context) & (db)->mask] 104 105/* Resize the given db */ 106 107static void ResizeTable(DB db) 108{ 109 TableEntry *otable; 110 register TableEntry entry, next, *pold, *head; 111 register int i, j; 112 113 otable = db->table; 114 for (i = INITHASHMASK+1; (i + i) < db->numentries; ) 115 i += i; 116 db->table = (TableEntry *) Xcalloc((unsigned)i, sizeof(TableEntry)); 117 if (!db->table) { 118 db->table = otable; 119 return; 120 } 121 j = db->mask + 1; 122 db->mask = i - 1; 123 for (pold = otable ; --j >= 0; pold++) { 124 for (entry = *pold; entry; entry = next) { 125 next = entry->next; 126 head = &Hash(db, entry->rid, entry->context); 127 entry->next = *head; 128 *head = entry; 129 } 130 } 131 Xfree((char *) otable); 132} 133 134static void _XFreeContextDB(Display *display) 135{ 136 register DB db; 137 register int i; 138 register TableEntry *pentry, entry, next; 139 140 db = display->context_db; 141 if (db) { 142 for (i = db->mask + 1, pentry = db->table ; --i >= 0; pentry++) { 143 for (entry = *pentry; entry; entry = next) { 144 next = entry->next; 145 Xfree((char *)entry); 146 } 147 } 148 Xfree((char *) db->table); 149 _XFreeMutex(&db->linfo); 150 Xfree((char *) db); 151 } 152} 153 154/* Public routines. */ 155 156/* Save the given value of data to correspond with the keys XID and context. 157 Returns nonzero error code if an error has occured, 0 otherwise. 158 Possible errors are Out-of-memory. 159*/ 160 161int XSaveContext( 162 Display *display, 163 register XID rid, 164 register XContext context, 165 _Xconst char* data) 166{ 167 DB *pdb; 168 register DB db; 169 TableEntry *head; 170 register TableEntry entry; 171 172#ifdef MOTIFBC 173 if (!display) { 174 pdb = &NullDB; 175 db = *pdb; 176 } else 177#endif 178 { 179 LockDisplay(display); 180 pdb = &display->context_db; 181 db = *pdb; 182 UnlockDisplay(display); 183 } 184 if (!db) { 185 db = (DB) Xmalloc(sizeof(DBRec)); 186 if (!db) 187 return XCNOMEM; 188 db->mask = INITHASHMASK; 189 db->table = (TableEntry *)Xcalloc(db->mask + 1, sizeof(TableEntry)); 190 if (!db->table) { 191 Xfree((char *)db); 192 return XCNOMEM; 193 } 194 db->numentries = 0; 195 _XCreateMutex(&db->linfo); 196#ifdef MOTIFBC 197 if (!display) *pdb = db; else 198#endif 199 { 200 LockDisplay(display); 201 *pdb = db; 202 display->free_funcs->context_db = _XFreeContextDB; 203 UnlockDisplay(display); 204 } 205 } 206 _XLockMutex(&db->linfo); 207 head = &Hash(db, rid, context); 208 _XUnlockMutex(&db->linfo); 209 for (entry = *head; entry; entry = entry->next) { 210 if (entry->rid == rid && entry->context == context) { 211 entry->data = (XPointer)data; 212 return 0; 213 } 214 } 215 entry = (TableEntry) Xmalloc(sizeof(TableEntryRec)); 216 if (!entry) 217 return XCNOMEM; 218 entry->rid = rid; 219 entry->context = context; 220 entry->data = (XPointer)data; 221 entry->next = *head; 222 *head = entry; 223 _XLockMutex(&db->linfo); 224 db->numentries++; 225 if (db->numentries > (db->mask << 2)) 226 ResizeTable(db); 227 _XUnlockMutex(&db->linfo); 228 return 0; 229} 230 231 232 233/* Given an XID and context, returns the associated data. Note that data 234 here is a pointer since it is a return value. Returns nonzero error code 235 if an error has occured, 0 otherwise. Possible errors are Entry-not-found. 236*/ 237 238int XFindContext(display, rid, context, data) 239 Display *display; 240 register XID rid; 241 register XContext context; 242 XPointer *data; /* RETURN */ 243{ 244 register DB db; 245 register TableEntry entry; 246 247#ifdef MOTIFBC 248 if (!display) db = NullDB; else 249#endif 250 { 251 LockDisplay(display); 252 db = display->context_db; 253 UnlockDisplay(display); 254 } 255 if (!db) 256 return XCNOENT; 257 _XLockMutex(&db->linfo); 258 for (entry = Hash(db, rid, context); entry; entry = entry->next) 259 { 260 if (entry->rid == rid && entry->context == context) { 261 *data = (XPointer)entry->data; 262 _XUnlockMutex(&db->linfo); 263 return 0; 264 } 265 } 266 _XUnlockMutex(&db->linfo); 267 return XCNOENT; 268} 269 270 271 272/* Deletes the entry for the given XID and context from the datastructure. 273 This returns the same thing that FindContext would have returned if called 274 with the same arguments. 275*/ 276 277int XDeleteContext(display, rid, context) 278 Display *display; 279 register XID rid; 280 register XContext context; 281{ 282 register DB db; 283 register TableEntry entry, *prev; 284 285#ifdef MOTIFBC 286 if (!display) db = NullDB; else 287#endif 288 { 289 LockDisplay(display); 290 db = display->context_db; 291 UnlockDisplay(display); 292 } 293 if (!db) 294 return XCNOENT; 295 _XLockMutex(&db->linfo); 296 for (prev = &Hash(db, rid, context); 297 (entry = *prev); 298 prev = &entry->next) { 299 if (entry->rid == rid && entry->context == context) { 300 *prev = entry->next; 301 Xfree((char *) entry); 302 db->numentries--; 303 if (db->numentries < db->mask && db->mask > INITHASHMASK) 304 ResizeTable(db); 305 _XUnlockMutex(&db->linfo); 306 return 0; 307 } 308 } 309 _XUnlockMutex(&db->linfo); 310 return XCNOENT; 311} 312