PageRenderTime 187ms CodeModel.GetById 28ms RepoModel.GetById 0ms app.codeStats 0ms

/erts/emulator/beam/atom.c

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