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

/erts/emulator/beam/atom.c

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