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