Context.c revision 61b2299d
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 *display, XID rid, XContext context, XPointer *data) 239{ 240 register DB db; 241 register TableEntry entry; 242 243#ifdef MOTIFBC 244 if (!display) db = NullDB; else 245#endif 246 { 247 LockDisplay(display); 248 db = display->context_db; 249 UnlockDisplay(display); 250 } 251 if (!db) 252 return XCNOENT; 253 _XLockMutex(&db->linfo); 254 for (entry = Hash(db, rid, context); entry; entry = entry->next) 255 { 256 if (entry->rid == rid && entry->context == context) { 257 *data = (XPointer)entry->data; 258 _XUnlockMutex(&db->linfo); 259 return 0; 260 } 261 } 262 _XUnlockMutex(&db->linfo); 263 return XCNOENT; 264} 265 266 267 268/* Deletes the entry for the given XID and context from the datastructure. 269 This returns the same thing that FindContext would have returned if called 270 with the same arguments. 271*/ 272 273int XDeleteContext(Display *display, XID rid, XContext context) 274{ 275 register DB db; 276 register TableEntry entry, *prev; 277 278#ifdef MOTIFBC 279 if (!display) db = NullDB; else 280#endif 281 { 282 LockDisplay(display); 283 db = display->context_db; 284 UnlockDisplay(display); 285 } 286 if (!db) 287 return XCNOENT; 288 _XLockMutex(&db->linfo); 289 for (prev = &Hash(db, rid, context); 290 (entry = *prev); 291 prev = &entry->next) { 292 if (entry->rid == rid && entry->context == context) { 293 *prev = entry->next; 294 Xfree((char *) entry); 295 db->numentries--; 296 if (db->numentries < db->mask && db->mask > INITHASHMASK) 297 ResizeTable(db); 298 _XUnlockMutex(&db->linfo); 299 return 0; 300 } 301 } 302 _XUnlockMutex(&db->linfo); 303 return XCNOENT; 304} 305