PageRenderTime 313ms CodeModel.GetById 74ms app.highlight 206ms RepoModel.GetById 2ms app.codeStats 0ms

/erts/emulator/beam/atom.c

https://github.com/djui/otp
C | 358 lines | 252 code | 51 blank | 55 comment | 24 complexity | e340308d66c7850d2a990755e17d3ce6 MD5 | raw file
  1/*
  2 * %CopyrightBegin%
  3 *
  4 * Copyright Ericsson AB 1996-2010. All Rights Reserved.
  5 *
  6 * The contents of this file are subject to the Erlang Public License,
  7 * Version 1.1, (the "License"); you may not use this file except in
  8 * compliance with the License. You should have received a copy of the
  9 * Erlang Public License along with this software. If not, it can be
 10 * retrieved online at http://www.erlang.org/.
 11 *
 12 * Software distributed under the License is distributed on an "AS IS"
 13 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
 14 * the License for the specific language governing rights and limitations
 15 * under the License.
 16 *
 17 * %CopyrightEnd%
 18 */
 19
 20#ifdef HAVE_CONFIG_H
 21#  include "config.h"
 22#endif
 23
 24#include "sys.h"
 25#include "erl_sys_driver.h"
 26#include "erl_vm.h"
 27#include "global.h"
 28#include "hash.h"
 29#include "atom.h"
 30
 31
 32#define ATOM_SIZE  3000
 33
 34IndexTable erts_atom_table;	/* The index table */
 35
 36#include "erl_smp.h"
 37
 38static erts_smp_rwmtx_t atom_table_lock;
 39
 40#define atom_read_lock()	erts_smp_rwmtx_rlock(&atom_table_lock)
 41#define atom_read_unlock()	erts_smp_rwmtx_runlock(&atom_table_lock)
 42#define atom_write_lock()	erts_smp_rwmtx_rwlock(&atom_table_lock)
 43#define atom_write_unlock()	erts_smp_rwmtx_rwunlock(&atom_table_lock)
 44
 45#if 0
 46#define ERTS_ATOM_PUT_OPS_STAT
 47#endif
 48#ifdef ERTS_ATOM_PUT_OPS_STAT
 49static erts_smp_atomic_t atom_put_ops;
 50#endif
 51
 52/* Functions for allocating space for the ext of atoms. We do not
 53 * use malloc for each atom to prevent excessive memory fragmentation
 54 */
 55
 56typedef struct _atom_text {
 57    struct _atom_text* next;
 58    unsigned char text[ATOM_TEXT_SIZE];
 59} AtomText;
 60
 61static AtomText* text_list;	/* List of text buffers */
 62static byte *atom_text_pos;
 63static byte *atom_text_end;
 64static Uint reserved_atom_space;	/* Total amount of atom text space */
 65static Uint atom_space;		/* Amount of atom text space used */
 66
 67/*
 68 * Print info about atom tables
 69 */
 70void atom_info(int to, void *to_arg)
 71{
 72    int lock = !ERTS_IS_CRASH_DUMPING;
 73    if (lock)
 74	atom_read_lock();
 75    index_info(to, to_arg, &erts_atom_table);
 76#ifdef ERTS_ATOM_PUT_OPS_STAT
 77    erts_print(to, to_arg, "atom_put_ops: %ld\n",
 78	       erts_smp_atomic_read(&atom_put_ops));
 79#endif
 80
 81    if (lock)
 82	atom_read_unlock();
 83}
 84
 85/*
 86 * Allocate an atom text segment.
 87 */
 88static void
 89more_atom_space(void)
 90{
 91    AtomText* ptr;
 92
 93    ptr = (AtomText*) erts_alloc(ERTS_ALC_T_ATOM_TXT, sizeof(AtomText));
 94
 95    ptr->next = text_list;
 96    text_list = ptr;
 97
 98    atom_text_pos = ptr->text;
 99    atom_text_end = atom_text_pos + ATOM_TEXT_SIZE;
100    reserved_atom_space += sizeof(AtomText);
101
102    VERBOSE(DEBUG_SYSTEM,("Allocated %d atom space\n",ATOM_TEXT_SIZE));
103}
104
105/*
106 * Allocate string space within an atom text segment.
107 */
108
109static byte*
110atom_text_alloc(int bytes)
111{
112    byte *res;
113
114    ASSERT(bytes <= MAX_ATOM_LENGTH);
115    if (atom_text_pos + bytes >= atom_text_end) {
116	more_atom_space();
117    }
118    res = atom_text_pos;
119    atom_text_pos += bytes;
120    atom_space    += bytes;
121    return res;
122}
123
124/*
125 * Calculate atom hash value (using the hash algorithm
126 * hashpjw from the Dragon Book).
127 */
128
129static HashValue
130atom_hash(Atom* obj)
131{
132    byte* p = obj->name;
133    int len = obj->len;
134    HashValue h = 0, g;
135
136    while(len--) {
137	h = (h << 4) + *p++;
138	if ((g = h & 0xf0000000)) {
139	    h ^= (g >> 24);
140	    h ^= g;
141	}
142    }
143    return h;
144}
145
146
147static int 
148atom_cmp(Atom* tmpl, Atom* obj)
149{
150    if (tmpl->len == obj->len &&
151	sys_memcmp(tmpl->name, obj->name, tmpl->len) == 0)
152	return 0;
153    return 1;
154}
155
156
157static Atom*
158atom_alloc(Atom* tmpl)
159{
160    Atom* obj = (Atom*) erts_alloc(ERTS_ALC_T_ATOM, sizeof(Atom));
161
162    obj->name = atom_text_alloc(tmpl->len);
163    sys_memcpy(obj->name, tmpl->name, tmpl->len);
164    obj->len = tmpl->len;
165    obj->slot.index = -1;
166
167    /*
168     * Precompute ordinal value of first 3 bytes + 7 bits.
169     * This is used by utils.c:cmp_atoms().
170     * We cannot use the full 32 bits of the first 4 bytes,
171     * since we use the sign of the difference between two
172     * ordinal values to represent their relative order.
173     */
174    {
175	unsigned char c[4];
176	int i;
177	int j;
178
179	j = (tmpl->len < 4) ? tmpl->len : 4;
180	for(i = 0; i < j; ++i)
181	    c[i] = tmpl->name[i];
182	for(; i < 4; ++i)
183	    c[i] = '\0';
184	obj->ord0 = (c[0] << 23) + (c[1] << 15) + (c[2] << 7) + (c[3] >> 1);
185    }
186    return obj;
187}
188
189static void
190atom_free(Atom* obj)
191{
192    erts_free(ERTS_ALC_T_ATOM, (void*) obj);
193}
194
195Eterm
196am_atom_put(const char* name, int len)
197{
198    Atom a;
199    Eterm ret;
200    int aix;
201
202    /*
203     * Silently truncate the atom if it is too long. Overlong atoms
204     * could occur in situations where we have no good way to return
205     * an error, such as in the I/O system. (Unfortunately, many
206     * drivers don't check for errors.)
207     *
208     * If an error should be produced for overlong atoms (such in
209     * list_to_atom/1), the caller should check the length before
210     * calling this function.
211     */
212    if (len > MAX_ATOM_LENGTH) {
213	len = MAX_ATOM_LENGTH;
214    }
215#ifdef ERTS_ATOM_PUT_OPS_STAT
216    erts_smp_atomic_inc(&atom_put_ops);
217#endif
218    a.len = len;
219    a.name = (byte*)name;
220    atom_read_lock();
221    aix = index_get(&erts_atom_table, (void*) &a);
222    atom_read_unlock();
223    if (aix >= 0)
224	ret = make_atom(aix);
225    else {
226	atom_write_lock();
227	ret = make_atom(index_put(&erts_atom_table, (void*) &a));
228	atom_write_unlock();
229    }
230    return ret;
231}
232
233
234int atom_table_size(void)
235{
236    int ret;
237#ifdef ERTS_SMP
238    int lock = !ERTS_IS_CRASH_DUMPING;
239    if (lock)
240	atom_read_lock();
241#endif
242    ret = erts_atom_table.entries;
243#ifdef ERTS_SMP
244    if (lock)
245	atom_read_unlock();
246#endif
247    return ret;
248}
249
250int atom_table_sz(void)
251{
252    int ret;
253#ifdef ERTS_SMP
254    int lock = !ERTS_IS_CRASH_DUMPING;
255    if (lock)
256	atom_read_lock();
257#endif
258    ret = index_table_sz(&erts_atom_table);
259#ifdef ERTS_SMP
260    if (lock)
261	atom_read_unlock();
262#endif
263    return ret;
264}
265
266int
267erts_atom_get(const char *name, int len, Eterm* ap)
268{
269    Atom a;
270    int i;
271    int res;
272
273    a.len = len;
274    a.name = (byte *)name;
275    atom_read_lock();
276    i = index_get(&erts_atom_table, (void*) &a);
277    res = i < 0 ? 0 : (*ap = make_atom(i), 1);
278    atom_read_unlock();
279    return res;
280}
281
282void
283erts_atom_get_text_space_sizes(Uint *reserved, Uint *used)
284{
285#ifdef ERTS_SMP
286    int lock = !ERTS_IS_CRASH_DUMPING;
287    if (lock)
288	atom_read_lock();
289#endif
290    if (reserved)
291	*reserved = reserved_atom_space;
292    if (used)
293	*used = atom_space;
294#ifdef ERTS_SMP
295    if (lock)
296	atom_read_unlock();
297#endif
298}
299
300void
301init_atom_table(void)
302{
303    HashFunctions f;
304    int i;
305    Atom a;
306    erts_smp_rwmtx_opt_t rwmtx_opt = ERTS_SMP_RWMTX_OPT_DEFAULT_INITER;
307
308    rwmtx_opt.type = ERTS_SMP_RWMTX_TYPE_FREQUENT_READ;
309    rwmtx_opt.lived = ERTS_SMP_RWMTX_LONG_LIVED;
310
311#ifdef ERTS_ATOM_PUT_OPS_STAT
312    erts_smp_atomic_init(&atom_put_ops, 0);
313#endif
314
315    erts_smp_rwmtx_init_opt(&atom_table_lock, &rwmtx_opt, "atom_tab");
316
317    f.hash = (H_FUN) atom_hash;
318    f.cmp  = (HCMP_FUN) atom_cmp;
319    f.alloc = (HALLOC_FUN) atom_alloc;
320    f.free = (HFREE_FUN) atom_free;
321
322    atom_text_pos = NULL;
323    atom_text_end = NULL;
324    reserved_atom_space = 0;
325    atom_space = 0;
326    text_list = NULL;
327
328    erts_index_init(ERTS_ALC_T_ATOM_TABLE, &erts_atom_table,
329		    "atom_tab", ATOM_SIZE, erts_atom_table_size, f);
330    more_atom_space();
331
332    /* Ordinary atoms */
333    for (i = 0; erl_atom_names[i] != 0; i++) {
334	int ix;
335	a.len = strlen(erl_atom_names[i]);
336	a.name = (byte*)erl_atom_names[i];
337	a.slot.index = i;
338	ix = index_put(&erts_atom_table, (void*) &a);
339	atom_text_pos -= a.len;
340	atom_space -= a.len;
341	atom_tab(ix)->name = (byte*)erl_atom_names[i];
342    }
343}
344
345void
346dump_atoms(int to, void *to_arg)
347{
348    int i = erts_atom_table.entries;
349
350    /*
351     * Print out the atom table starting from the end.
352     */
353    while (--i >= 0) {
354	if (erts_index_lookup(&erts_atom_table, i)) {
355	    erts_print(to, to_arg, "%T\n", make_atom(i));
356	}
357    }
358}