PageRenderTime 50ms CodeModel.GetById 4ms RepoModel.GetById 0ms app.codeStats 0ms

/erts/emulator/beam/erl_ptab.c

https://github.com/bsmr-erlang/otp
C | 1694 lines | 1335 code | 251 blank | 108 comment | 246 complexity | 1b4df33fd19b32c78e2a99b8f7b77671 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0
  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 2012-2017. All Rights Reserved.
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * %CopyrightEnd%
  19. */
  20. /*
  21. * Description: Process/Port table implementation.
  22. *
  23. * Author: Rickard Green
  24. */
  25. #ifdef HAVE_CONFIG_H
  26. # include "config.h"
  27. #endif
  28. #define ERTS_PTAB_WANT_BIF_IMPL__
  29. #define ERTS_PTAB_WANT_DEBUG_FUNCS__
  30. #include "erl_ptab.h"
  31. #include "global.h"
  32. #include "erl_binary.h"
  33. typedef struct ErtsPTabListBifData_ ErtsPTabListBifData;
  34. #define ERTS_PTAB_NEW_MAX_RESERVE_FAIL 1000
  35. #define ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED 25
  36. #define ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE 1000
  37. #define ERTS_PTAB_LIST_BIF_MIN_START_REDS \
  38. (ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE \
  39. / ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED)
  40. #define ERTS_PTAB_LIST_BIF_TAB_FREE_DELETED_REDS 1
  41. #define ERTS_PTAB_LIST_BIF_INSPECT_DELETED_PER_RED 10
  42. #define ERTS_PTAB_LIST_INSPECT_DELETED_MAX_REDS \
  43. (ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE \
  44. / ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED)
  45. #define ERTS_PTAB_LIST_BIF_BUILD_RESULT_CONSES_PER_RED 75
  46. #define ERTS_PTAB_LIST_DBG_DO_TRACE 0
  47. #ifdef DEBUG
  48. # define ERTS_PTAB_LIST_BIF_DEBUGLEVEL 100
  49. #else
  50. # define ERTS_PTAB_LIST_BIF_DEBUGLEVEL 0
  51. #endif
  52. #define ERTS_PTAB_LIST_DBGLVL_CHK_HALLOC 1
  53. #define ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS 5
  54. #define ERTS_PTAB_LIST_DBGLVL_CHK_PIDS 10
  55. #define ERTS_PTAB_LIST_DBGLVL_CHK_DEL_LIST 20
  56. #define ERTS_PTAB_LIST_DBGLVL_CHK_RESLIST 20
  57. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL == 0
  58. # define ERTS_PTAB_LIST_ASSERT(EXP)
  59. #else
  60. # define ERTS_PTAB_LIST_ASSERT(EXP) \
  61. ((void) ((EXP) \
  62. ? 1 \
  63. : (debug_ptab_list_assert_error(#EXP, \
  64. __FILE__, \
  65. __LINE__, \
  66. __func__), \
  67. 0)))
  68. #endif
  69. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_HALLOC
  70. # define ERTS_PTAB_LIST_DBG_SAVE_HEAP_ALLOC(PTLBDP, HP, SZ) \
  71. do { \
  72. ERTS_PTAB_LIST_ASSERT(!(PTLBDP)->debug.heap); \
  73. ERTS_PTAB_LIST_ASSERT(!(PTLBDP)->debug.heap_size); \
  74. (PTLBDP)->debug.heap = (HP); \
  75. (PTLBDP)->debug.heap_size = (SZ); \
  76. } while (0)
  77. # define ERTS_PTAB_LIST_DBG_VERIFY_HEAP_ALLOC_USED(PTLBDP, HP) \
  78. do { \
  79. ERTS_PTAB_LIST_ASSERT((PTLBDP)->debug.heap); \
  80. ERTS_PTAB_LIST_ASSERT((PTLBDP)->debug.heap_size); \
  81. ERTS_PTAB_LIST_ASSERT(((PTLBDP)->debug.heap \
  82. + (PTLBDP)->debug.heap_size) \
  83. == (HP)); \
  84. (PTLBDP)->debug.heap = NULL; \
  85. (PTLBDP)->debug.heap_size = 0; \
  86. } while (0)
  87. # define ERTS_PTAB_LIST_DBG_HEAP_ALLOC_INIT(PTLBDP) \
  88. do { \
  89. (PTLBDP)->debug.heap = NULL; \
  90. (PTLBDP)->debug.heap_size = 0; \
  91. } while (0)
  92. #else
  93. # define ERTS_PTAB_LIST_DBG_SAVE_HEAP_ALLOC(PTLBDP, HP, SZ)
  94. # define ERTS_PTAB_LIST_DBG_VERIFY_HEAP_ALLOC_USED(PTLBDP, HP)
  95. # define ERTS_PTAB_LIST_DBG_HEAP_ALLOC_INIT(PTLBDP)
  96. #endif
  97. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_RESLIST
  98. # define ERTS_PTAB_LIST_DBG_CHK_RESLIST(R) \
  99. debug_ptab_list_check_res_list((R))
  100. #else
  101. # define ERTS_PTAB_LIST_DBG_CHK_RESLIST(R)
  102. #endif
  103. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_PIDS
  104. # define ERTS_PTAB_LIST_DBG_SAVE_PIDS(PTLBDP) \
  105. debug_ptab_list_save_all_pids((PTLBDP))
  106. # define ERTS_PTAB_LIST_DBG_VERIFY_PIDS(PTLBDP) \
  107. do { \
  108. if (!(PTLBDP)->debug.correct_pids_verified) \
  109. debug_ptab_list_verify_all_pids((PTLBDP)); \
  110. } while (0)
  111. # define ERTS_PTAB_LIST_DBG_CLEANUP_CHK_PIDS(PTLBDP) \
  112. do { \
  113. if ((PTLBDP)->debug.correct_pids) { \
  114. erts_free(ERTS_ALC_T_PTAB_LIST_PIDS, \
  115. (PTLBDP)->debug.correct_pids); \
  116. (PTLBDP)->debug.correct_pids = NULL; \
  117. } \
  118. } while(0)
  119. # define ERTS_PTAB_LIST_DBG_CHK_PIDS_INIT(PTLBDP) \
  120. do { \
  121. (PTLBDP)->debug.correct_pids_verified = 0; \
  122. (PTLBDP)->debug.correct_pids = NULL; \
  123. } while (0)
  124. #else
  125. # define ERTS_PTAB_LIST_DBG_SAVE_PIDS(PTLBDP)
  126. # define ERTS_PTAB_LIST_DBG_VERIFY_PIDS(PTLBDP)
  127. # define ERTS_PTAB_LIST_DBG_CLEANUP_CHK_PIDS(PTLBDP)
  128. # define ERTS_PTAB_LIST_DBG_CHK_PIDS_INIT(PTLBDP)
  129. #endif
  130. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
  131. # define ERTS_PTAB_LIST_DBG_CHK_PID_FOUND(PTLBDP, PID, IC) \
  132. debug_ptab_list_check_found_pid((PTLBDP), (PID), (IC), 1)
  133. # define ERTS_PTAB_LIST_DBG_CHK_PID_NOT_FOUND(PTLBDP, PID, IC) \
  134. debug_ptab_list_check_found_pid((PTLBDP), (PID), (IC), 0)
  135. #else
  136. # define ERTS_PTAB_LIST_DBG_CHK_PID_FOUND(PTLBDP, PID, IC)
  137. # define ERTS_PTAB_LIST_DBG_CHK_PID_NOT_FOUND(PTLBDP, PID, IC)
  138. #endif
  139. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_DEL_LIST
  140. # define ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(PTab) \
  141. debug_ptab_list_check_del_list((PTab))
  142. # define ERTS_PTAB_LIST_DBG_CHK_FREELIST(PTab, FL) \
  143. debug_ptab_list_check_del_free_list((PTab), (FL))
  144. #else
  145. # define ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(PTab)
  146. # define ERTS_PTAB_LIST_DBG_CHK_FREELIST(PTab, FL)
  147. #endif
  148. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL == 0
  149. #if ERTS_PTAB_LIST_DBG_DO_TRACE
  150. # define ERTS_PTAB_LIST_DBG_INIT(P, PTLBDP) \
  151. (PTLBDP)->debug.caller = (P)->common.id
  152. # else
  153. # define ERTS_PTAB_LIST_DBG_INIT(P, PTLBDP)
  154. # endif
  155. # define ERTS_PTAB_LIST_DBG_CLEANUP(PTLBDP)
  156. #else
  157. # define ERTS_PTAB_LIST_DBG_INIT(P, PTLBDP) \
  158. do { \
  159. (PTLBDP)->debug.caller = (P)->common.id; \
  160. ERTS_PTAB_LIST_DBG_HEAP_ALLOC_INIT((PTLBDP)); \
  161. ERTS_PTAB_LIST_DBG_CHK_PIDS_INIT((PTLBDP)); \
  162. } while (0)
  163. # define ERTS_PTAB_LIST_DBG_CLEANUP(PTLBDP) \
  164. do { \
  165. ERTS_PTAB_LIST_DBG_CLEANUP_CHK_PIDS((PTLBDP)); \
  166. } while (0)
  167. #endif
  168. #if ERTS_PTAB_LIST_DBG_DO_TRACE
  169. # define ERTS_PTAB_LIST_DBG_TRACE(PID, WHAT) \
  170. erts_fprintf(stderr, "%T %s:%d:%s(): %s\n", \
  171. (PID), __FILE__, __LINE__, __func__, #WHAT)
  172. #else
  173. # define ERTS_PTAB_LIST_DBG_TRACE(PID, WHAT)
  174. #endif
  175. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL != 0
  176. static void debug_ptab_list_assert_error(char* expr,
  177. const char* file,
  178. int line,
  179. const char *func);
  180. #endif
  181. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_RESLIST
  182. static void debug_ptab_list_check_res_list(Eterm list);
  183. #endif
  184. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_PIDS
  185. static void debug_ptab_list_save_all_pids(ErtsPTabListBifData *ptlbdp);
  186. static void debug_ptab_list_verify_all_pids(ErtsPTabListBifData *ptlbdp);
  187. #endif
  188. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
  189. static void debug_ptab_list_check_found_pid(ErtsPTabListBifData *ptlbdp,
  190. Eterm pid,
  191. Uint64 ic,
  192. int pid_should_be_found);
  193. #endif
  194. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_DEL_LIST
  195. static void debug_ptab_list_check_del_list(ErtsPTab *ptab);
  196. static void debug_ptab_list_check_del_free_list(ErtsPTab *ptab,
  197. ErtsPTabDeletedElement *ptdep);
  198. #endif
  199. struct ErtsPTabDeletedElement_ {
  200. ErtsPTabDeletedElement *next;
  201. ErtsPTabDeletedElement *prev;
  202. int ix;
  203. union {
  204. struct {
  205. Eterm id;
  206. Uint64 inserted;
  207. Uint64 deleted;
  208. } element;
  209. struct {
  210. Uint64 interval;
  211. } bif_invocation;
  212. } u;
  213. };
  214. static Export ptab_list_continue_export;
  215. typedef struct {
  216. Uint64 interval;
  217. } ErtsPTabListBifChunkInfo;
  218. typedef enum {
  219. INITIALIZING,
  220. INSPECTING_TABLE,
  221. INSPECTING_DELETED,
  222. BUILDING_RESULT,
  223. RETURN_RESULT
  224. } ErtsPTabListBifState;
  225. struct ErtsPTabListBifData_ {
  226. ErtsPTab *ptab;
  227. ErtsPTabListBifState state;
  228. Eterm caller;
  229. ErtsPTabListBifChunkInfo *chunk;
  230. int tix;
  231. int pid_ix;
  232. int pid_sz;
  233. Eterm *pid;
  234. ErtsPTabDeletedElement *bif_invocation; /* Only used when > 1 chunk */
  235. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL != 0 || ERTS_PTAB_LIST_DBG_DO_TRACE
  236. struct {
  237. Eterm caller;
  238. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
  239. Uint64 *pid_started;
  240. #endif
  241. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_HALLOC
  242. Eterm *heap;
  243. Uint heap_size;
  244. #endif
  245. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_PIDS
  246. int correct_pids_verified;
  247. Eterm *correct_pids;
  248. #endif
  249. } debug;
  250. #endif
  251. };
  252. static ERTS_INLINE void
  253. last_data_init_nob(ErtsPTab *ptab, Uint64 val)
  254. {
  255. erts_atomic64_init_nob(&ptab->vola.tile.last_data, (erts_aint64_t) val);
  256. }
  257. static ERTS_INLINE void
  258. last_data_set_relb(ErtsPTab *ptab, Uint64 val)
  259. {
  260. erts_atomic64_set_relb(&ptab->vola.tile.last_data, (erts_aint64_t) val);
  261. }
  262. static ERTS_INLINE Uint64
  263. last_data_read_nob(ErtsPTab *ptab)
  264. {
  265. return (Uint64) erts_atomic64_read_nob(&ptab->vola.tile.last_data);
  266. }
  267. static ERTS_INLINE Uint64
  268. last_data_read_acqb(ErtsPTab *ptab)
  269. {
  270. return (Uint64) erts_atomic64_read_acqb(&ptab->vola.tile.last_data);
  271. }
  272. static ERTS_INLINE Uint64
  273. last_data_cmpxchg_relb(ErtsPTab *ptab, Uint64 new, Uint64 exp)
  274. {
  275. return (Uint64) erts_atomic64_cmpxchg_relb(&ptab->vola.tile.last_data,
  276. (erts_aint64_t) new,
  277. (erts_aint64_t) exp);
  278. }
  279. static ERTS_INLINE int
  280. last_data_cmp(Uint64 ld1, Uint64 ld2)
  281. {
  282. Uint64 ld1_wrap;
  283. if (ld1 == ld2)
  284. return 0;
  285. ld1_wrap = ld1 + (((Uint64) 1) << 63);
  286. if (ld1 < ld1_wrap)
  287. return (ld1 < ld2 && ld2 < ld1_wrap) ? -1 : 1;
  288. else
  289. return (ld1_wrap <= ld2 && ld2 < ld1) ? 1 : -1;
  290. }
  291. #define ERTS_PTAB_LastData2EtermData(LD) \
  292. ((Eterm) ((LD) & ~(~((Uint64) 0) << ERTS_PTAB_ID_DATA_SIZE)))
  293. static ERTS_INLINE Uint32
  294. ix_to_free_id_data_ix(ErtsPTab *ptab, Uint32 ix)
  295. {
  296. Uint32 dix;
  297. dix = ((ix & ptab->r.o.dix_cl_mask) << ptab->r.o.dix_cl_shift);
  298. dix += ((ix >> ptab->r.o.dix_cli_shift) & ptab->r.o.dix_cli_mask);
  299. ASSERT(0 <= dix && dix < ptab->r.o.max);
  300. return dix;
  301. }
  302. UWord
  303. erts_ptab_mem_size(ErtsPTab *ptab)
  304. {
  305. UWord size = ptab->r.o.max*sizeof(erts_atomic_t);
  306. if (ptab->r.o.free_id_data)
  307. size += ptab->r.o.max*sizeof(erts_atomic32_t);
  308. return size;
  309. }
  310. void
  311. erts_ptab_init_table(ErtsPTab *ptab,
  312. ErtsAlcType_t atype,
  313. void (*release_element)(void *),
  314. ErtsPTabElementCommon *invalid_element,
  315. int size,
  316. UWord element_size,
  317. char *name,
  318. int legacy,
  319. int atomic_refc)
  320. {
  321. size_t tab_sz, alloc_sz;
  322. Uint32 bits, cl, cli, ix, ix_per_cache_line, tab_cache_lines;
  323. char *tab_end;
  324. erts_atomic_t *tab_entry;
  325. erts_rwmtx_opt_t rwmtx_opts = ERTS_RWMTX_OPT_DEFAULT_INITER;
  326. rwmtx_opts.type = ERTS_RWMTX_TYPE_EXTREMELY_FREQUENT_READ;
  327. rwmtx_opts.lived = ERTS_RWMTX_LONG_LIVED;
  328. erts_rwmtx_init_opt(&ptab->list.data.rwmtx, &rwmtx_opts, name, NIL,
  329. ERTS_LOCK_FLAGS_PROPERTY_STATIC | ERTS_LOCK_FLAGS_CATEGORY_GENERIC);
  330. erts_atomic32_init_nob(&ptab->vola.tile.count, 0);
  331. last_data_init_nob(ptab, ~((Uint64) 0));
  332. /* A size that is a power of 2 is to prefer performance wise */
  333. bits = erts_fit_in_bits_int32(size-1);
  334. size = 1 << bits;
  335. if (size > ERTS_PTAB_MAX_SIZE) {
  336. size = ERTS_PTAB_MAX_SIZE;
  337. bits = erts_fit_in_bits_int32((Sint32) size - 1);
  338. }
  339. ptab->r.o.element_size = element_size;
  340. ptab->r.o.max = size;
  341. tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_atomic_t));
  342. alloc_sz = tab_sz;
  343. if (!legacy)
  344. alloc_sz += ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_atomic32_t));
  345. ptab->r.o.tab = erts_alloc_permanent_cache_aligned(atype, alloc_sz);
  346. tab_end = ((char *) ptab->r.o.tab) + tab_sz;
  347. tab_entry = ptab->r.o.tab;
  348. while (tab_end > ((char *) tab_entry)) {
  349. erts_atomic_init_nob(tab_entry, ERTS_AINT_NULL);
  350. tab_entry++;
  351. }
  352. tab_cache_lines = tab_sz/ERTS_CACHE_LINE_SIZE;
  353. ix_per_cache_line = (ERTS_CACHE_LINE_SIZE/sizeof(erts_atomic_t));
  354. ASSERT((ptab->r.o.max & (ptab->r.o.max - 1)) == 0); /* power of 2 */
  355. ASSERT((ix_per_cache_line & (ix_per_cache_line - 1)) == 0); /* power of 2 */
  356. ASSERT((tab_cache_lines & (tab_cache_lines - 1)) == 0); /* power of 2 */
  357. ptab->r.o.pix_mask = (1 << bits) - 1;
  358. ptab->r.o.pix_cl_mask = tab_cache_lines-1;
  359. ptab->r.o.pix_cl_shift = erts_fit_in_bits_int32(ix_per_cache_line-1);
  360. ptab->r.o.pix_cli_shift = erts_fit_in_bits_int32(ptab->r.o.pix_cl_mask);
  361. ptab->r.o.pix_cli_mask = (1 << (bits - ptab->r.o.pix_cli_shift)) - 1;
  362. ASSERT(ptab->r.o.pix_cl_shift + ptab->r.o.pix_cli_shift == bits);
  363. ptab->r.o.invalid_element = invalid_element;
  364. ptab->r.o.invalid_data = erts_ptab_id2data(ptab, invalid_element->id);
  365. ptab->r.o.release_element = release_element;
  366. ptab->r.o.atomic_refc = atomic_refc;
  367. if (legacy) {
  368. ptab->r.o.free_id_data = NULL;
  369. ptab->r.o.dix_cl_mask = 0;
  370. ptab->r.o.dix_cl_shift = 0;
  371. ptab->r.o.dix_cli_shift = 0;
  372. ptab->r.o.dix_cli_mask = 0;
  373. }
  374. else {
  375. tab_sz = ERTS_ALC_CACHE_LINE_ALIGN_SIZE(size*sizeof(erts_atomic32_t));
  376. ptab->r.o.free_id_data = (erts_atomic32_t *) tab_end;
  377. tab_cache_lines = tab_sz/ERTS_CACHE_LINE_SIZE;
  378. ix_per_cache_line = (ERTS_CACHE_LINE_SIZE/sizeof(erts_atomic32_t));
  379. ptab->r.o.dix_cl_mask = tab_cache_lines-1;
  380. ptab->r.o.dix_cl_shift = erts_fit_in_bits_int32(ix_per_cache_line-1);
  381. ptab->r.o.dix_cli_shift = erts_fit_in_bits_int32(ptab->r.o.dix_cl_mask);
  382. ptab->r.o.dix_cli_mask = (1 << (bits - ptab->r.o.dix_cli_shift)) - 1;
  383. ASSERT((ix_per_cache_line & (ix_per_cache_line - 1)) == 0); /* power of 2 */
  384. ASSERT((tab_cache_lines & (tab_cache_lines - 1)) == 0); /* power of 2 */
  385. ASSERT(ptab->r.o.dix_cl_shift + ptab->r.o.dix_cli_shift == bits);
  386. ix = 0;
  387. for (cl = 0; cl < tab_cache_lines; cl++) {
  388. for (cli = 0; cli < ix_per_cache_line; cli++) {
  389. erts_atomic32_init_nob(&ptab->r.o.free_id_data[ix],
  390. cli*tab_cache_lines+cl);
  391. ASSERT(erts_atomic32_read_nob(&ptab->r.o.free_id_data[ix]) != ptab->r.o.invalid_data);
  392. ix++;
  393. }
  394. }
  395. erts_atomic32_init_nob(&ptab->vola.tile.aid_ix, -1);
  396. erts_atomic32_init_nob(&ptab->vola.tile.fid_ix, -1);
  397. }
  398. erts_interval_init(&ptab->list.data.interval);
  399. ptab->list.data.deleted.start = NULL;
  400. ptab->list.data.deleted.end = NULL;
  401. ptab->list.data.chunks = (((ptab->r.o.max - 1)
  402. / ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE)
  403. + 1);
  404. if (size == ERTS_PTAB_MAX_SIZE) {
  405. int pix;
  406. /*
  407. * We want a table size of a power of 2 which ERTS_PTAB_MAX_SIZE
  408. * is. We only have ERTS_PTAB_MAX_SIZE-1 unique identifiers and
  409. * we don't want to shrink the size to ERTS_PTAB_MAX_SIZE/2.
  410. *
  411. * In order to fix this, we insert a pointer from the table
  412. * to the invalid_element, which will be interpreted as a
  413. * slot currently being modified. This way we will be able to
  414. * have ERTS_PTAB_MAX_SIZE-1 valid elements in the table while
  415. * still having a table size of the power of 2.
  416. */
  417. erts_atomic32_inc_nob(&ptab->vola.tile.count);
  418. pix = erts_ptab_data2pix(ptab, ptab->r.o.invalid_data);
  419. erts_atomic_set_relb(&ptab->r.o.tab[pix],
  420. (erts_aint_t) ptab->r.o.invalid_element);
  421. }
  422. }
  423. int
  424. erts_ptab_initialized(ErtsPTab *ptab)
  425. {
  426. return ptab->r.o.tab != NULL;
  427. }
  428. int
  429. erts_ptab_new_element(ErtsPTab *ptab,
  430. ErtsPTabElementCommon *ptab_el,
  431. void *init_arg,
  432. void (*init_ptab_el)(void *, Eterm))
  433. {
  434. Uint32 pix, ix, data;
  435. erts_aint32_t count;
  436. erts_aint_t invalid = (erts_aint_t) ptab->r.o.invalid_element;
  437. erts_ptab_rlock(ptab);
  438. count = erts_atomic32_inc_read_acqb(&ptab->vola.tile.count);
  439. if (count > ptab->r.o.max) {
  440. while (1) {
  441. erts_aint32_t act_count;
  442. act_count = erts_atomic32_cmpxchg_relb(&ptab->vola.tile.count,
  443. count-1,
  444. count);
  445. if (act_count == count) {
  446. erts_ptab_runlock(ptab);
  447. return 0;
  448. }
  449. count = act_count;
  450. if (count <= ptab->r.o.max)
  451. break;
  452. }
  453. }
  454. ptab_el->u.alive.started_interval
  455. = erts_current_interval_nob(erts_ptab_interval(ptab));
  456. if (ptab->r.o.free_id_data) {
  457. do {
  458. ix = (Uint32) erts_atomic32_inc_read_acqb(&ptab->vola.tile.aid_ix);
  459. ix = ix_to_free_id_data_ix(ptab, ix);
  460. data = erts_atomic32_xchg_nob(&ptab->r.o.free_id_data[ix],
  461. (erts_aint32_t)ptab->r.o.invalid_data);
  462. }while ((Eterm)data == ptab->r.o.invalid_data);
  463. init_ptab_el(init_arg, (Eterm) data);
  464. if (ptab->r.o.atomic_refc)
  465. erts_atomic_init_nob(&ptab_el->refc.atmc, 1);
  466. else
  467. ptab_el->refc.sint = 1;
  468. pix = erts_ptab_data2pix(ptab, (Eterm) data);
  469. #ifdef DEBUG
  470. ASSERT(ERTS_AINT_NULL == erts_atomic_xchg_relb(&ptab->r.o.tab[pix],
  471. (erts_aint_t) ptab_el));
  472. #else
  473. erts_atomic_set_relb(&ptab->r.o.tab[pix], (erts_aint_t) ptab_el);
  474. #endif
  475. erts_ptab_runlock(ptab);
  476. }
  477. else {
  478. int rlocked = ERTS_PTAB_NEW_MAX_RESERVE_FAIL;
  479. Uint64 ld, exp_ld;
  480. /* Deprecated legacy algorithm... */
  481. restart:
  482. ptab_el->u.alive.started_interval
  483. = erts_current_interval_nob(erts_ptab_interval(ptab));
  484. ld = last_data_read_acqb(ptab);
  485. /* Reserve slot */
  486. while (1) {
  487. ld++;
  488. pix = erts_ptab_data2pix(ptab, ERTS_PTAB_LastData2EtermData(ld));
  489. if (erts_atomic_read_nob(&ptab->r.o.tab[pix])
  490. == ERTS_AINT_NULL) {
  491. erts_aint_t val;
  492. val = erts_atomic_cmpxchg_relb(&ptab->r.o.tab[pix],
  493. invalid,
  494. ERTS_AINT_NULL);
  495. if (ERTS_AINT_NULL == val)
  496. break;
  497. }
  498. if (rlocked && --rlocked == 0) {
  499. erts_ptab_runlock(ptab);
  500. erts_ptab_rwlock(ptab);
  501. goto restart;
  502. }
  503. }
  504. data = ERTS_PTAB_LastData2EtermData(ld);
  505. if (data == ptab->r.o.invalid_data) {
  506. /* Do not use invalid data; fix it... */
  507. ld += ptab->r.o.max;
  508. ASSERT(pix == erts_ptab_data2pix(ptab,
  509. ERTS_PTAB_LastData2EtermData(ld)));
  510. data = ERTS_PTAB_LastData2EtermData(ld);
  511. ASSERT(data != ptab->r.o.invalid_data);
  512. }
  513. exp_ld = last_data_read_nob(ptab);
  514. /* Move last data forward */
  515. while (1) {
  516. Uint64 act_ld;
  517. if (last_data_cmp(ld, exp_ld) < 0)
  518. break;
  519. act_ld = last_data_cmpxchg_relb(ptab, ld, exp_ld);
  520. if (act_ld == exp_ld)
  521. break;
  522. exp_ld = act_ld;
  523. }
  524. init_ptab_el(init_arg, data);
  525. if (ptab->r.o.atomic_refc)
  526. erts_atomic_init_nob(&ptab_el->refc.atmc, 1);
  527. else
  528. ptab_el->refc.sint = 1;
  529. /* Move into slot reserved */
  530. #ifdef DEBUG
  531. ASSERT(invalid == erts_atomic_xchg_relb(&ptab->r.o.tab[pix],
  532. (erts_aint_t) ptab_el));
  533. #else
  534. erts_atomic_set_relb(&ptab->r.o.tab[pix], (erts_aint_t) ptab_el);
  535. #endif
  536. if (rlocked)
  537. erts_ptab_runlock(ptab);
  538. else
  539. erts_ptab_rwunlock(ptab);
  540. }
  541. return 1;
  542. }
  543. static void
  544. save_deleted_element(ErtsPTab *ptab, ErtsPTabElementCommon *ptab_el)
  545. {
  546. ErtsPTabDeletedElement *ptdep = erts_alloc(ERTS_ALC_T_PTAB_LIST_DEL,
  547. sizeof(ErtsPTabDeletedElement));
  548. ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start
  549. && ptab->list.data.deleted.end);
  550. ERTS_LC_ASSERT(erts_lc_ptab_is_rwlocked(ptab));
  551. ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
  552. ptdep->prev = ptab->list.data.deleted.end;
  553. ptdep->next = NULL;
  554. ptdep->ix = erts_ptab_id2pix(ptab, ptab_el->id);
  555. ptdep->u.element.id = ptab_el->id;
  556. ptdep->u.element.inserted = ptab_el->u.alive.started_interval;
  557. ptdep->u.element.deleted =
  558. erts_current_interval_nob(erts_ptab_interval(ptab));
  559. ptab->list.data.deleted.end->next = ptdep;
  560. ptab->list.data.deleted.end = ptdep;
  561. ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
  562. ERTS_PTAB_LIST_ASSERT(ptdep->prev->ix >= 0
  563. ? (ptdep->u.element.deleted
  564. >= ptdep->prev->u.element.deleted)
  565. : (ptdep->u.element.deleted
  566. >= ptdep->prev->u.bif_invocation.interval));
  567. }
  568. void
  569. erts_ptab_delete_element(ErtsPTab *ptab,
  570. ErtsPTabElementCommon *ptab_el)
  571. {
  572. int maybe_save;
  573. Uint32 pix, ix, data;
  574. pix = erts_ptab_id2pix(ptab, ptab_el->id);
  575. /* *Need* to be an managed thread */
  576. ERTS_LC_ASSERT(erts_thr_progress_is_managed_thread());
  577. erts_ptab_rlock(ptab);
  578. maybe_save = ptab->list.data.deleted.end != NULL;
  579. if (maybe_save) {
  580. erts_ptab_runlock(ptab);
  581. erts_ptab_rwlock(ptab);
  582. }
  583. erts_atomic_set_relb(&ptab->r.o.tab[pix], ERTS_AINT_NULL);
  584. if (ptab->r.o.free_id_data) {
  585. Uint32 prev_data;
  586. /* Next data for this slot... */
  587. data = (Uint32) erts_ptab_id2data(ptab, ptab_el->id);
  588. data += ptab->r.o.max;
  589. data &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE);
  590. if (data == ptab->r.o.invalid_data) { /* make sure not invalid */
  591. data += ptab->r.o.max;
  592. data &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE);
  593. }
  594. ASSERT(data != ptab->r.o.invalid_data);
  595. ASSERT(pix == erts_ptab_data2pix(ptab, data));
  596. do {
  597. ix = (Uint32) erts_atomic32_inc_read_relb(&ptab->vola.tile.fid_ix);
  598. ix = ix_to_free_id_data_ix(ptab, ix);
  599. prev_data = erts_atomic32_cmpxchg_nob(&ptab->r.o.free_id_data[ix],
  600. data,
  601. ptab->r.o.invalid_data);
  602. }while ((Eterm)prev_data != ptab->r.o.invalid_data);
  603. }
  604. ASSERT(erts_atomic32_read_nob(&ptab->vola.tile.count) > 0);
  605. erts_atomic32_dec_relb(&ptab->vola.tile.count);
  606. if (!maybe_save)
  607. erts_ptab_runlock(ptab);
  608. else {
  609. if (ptab->list.data.deleted.end)
  610. save_deleted_element(ptab, ptab_el);
  611. erts_ptab_rwunlock(ptab);
  612. }
  613. if (ptab->r.o.release_element)
  614. erts_schedule_thr_prgr_later_cleanup_op(ptab->r.o.release_element,
  615. (void *) ptab_el,
  616. &ptab_el->u.release,
  617. ptab->r.o.element_size);
  618. }
  619. /*
  620. * erts_ptab_list() implements BIFs listing the content of the table,
  621. * e.g. erlang:processes/0.
  622. */
  623. static int cleanup_ptab_list_bif_data(Binary *bp);
  624. static int ptab_list_bif_engine(Process *c_p, Eterm *res_accp, Binary *mbp);
  625. BIF_RETTYPE
  626. erts_ptab_list(Process *c_p, ErtsPTab *ptab)
  627. {
  628. /*
  629. * A requirement: The list of identifiers returned should be a
  630. * consistent snapshot of all elements existing
  631. * in the table at some point in time during the
  632. * execution of the BIF calling this function.
  633. * Since elements might be deleted while the BIF
  634. * is executing, we have to keep track of all
  635. * deleted elements and add them to the result.
  636. * We also ignore elements created after the BIF
  637. * has begun executing.
  638. */
  639. BIF_RETTYPE ret_val;
  640. Eterm res_acc = NIL;
  641. Binary *mbp = erts_create_magic_binary(sizeof(ErtsPTabListBifData),
  642. cleanup_ptab_list_bif_data);
  643. ErtsPTabListBifData *ptlbdp = ERTS_MAGIC_BIN_DATA(mbp);
  644. ERTS_PTAB_LIST_DBG_TRACE(c_p->common.id, call);
  645. ptlbdp->ptab = ptab;
  646. ptlbdp->state = INITIALIZING;
  647. ERTS_PTAB_LIST_DBG_INIT(c_p, ptlbdp);
  648. if (ERTS_BIF_REDS_LEFT(c_p) >= ERTS_PTAB_LIST_BIF_MIN_START_REDS
  649. && ptab_list_bif_engine(c_p, &res_acc, mbp)) {
  650. erts_bin_free(mbp);
  651. ERTS_PTAB_LIST_DBG_CHK_RESLIST(res_acc);
  652. ERTS_PTAB_LIST_DBG_TRACE(c_p->common.id, return);
  653. ERTS_BIF_PREP_RET(ret_val, res_acc);
  654. }
  655. else {
  656. Eterm *hp;
  657. Eterm magic_ref;
  658. ERTS_PTAB_LIST_DBG_CHK_RESLIST(res_acc);
  659. hp = HAlloc(c_p, ERTS_MAGIC_REF_THING_SIZE);
  660. ERTS_PTAB_LIST_DBG_SAVE_HEAP_ALLOC(ptlbdp, hp, ERTS_MAGIC_REF_THING_SIZE);
  661. magic_ref = erts_mk_magic_ref(&hp, &MSO(c_p), mbp);
  662. ERTS_PTAB_LIST_DBG_VERIFY_HEAP_ALLOC_USED(ptlbdp, hp);
  663. ERTS_PTAB_LIST_DBG_TRACE(c_p->common.id, trap);
  664. ERTS_BIF_PREP_YIELD2(ret_val,
  665. &ptab_list_continue_export,
  666. c_p,
  667. res_acc,
  668. magic_ref);
  669. }
  670. return ret_val;
  671. }
  672. static int
  673. cleanup_ptab_list_bif_data(Binary *bp)
  674. {
  675. ErtsPTabListBifData *ptlbdp = ERTS_MAGIC_BIN_DATA(bp);
  676. ErtsPTab *ptab = ptlbdp->ptab;
  677. ERTS_PTAB_LIST_DBG_TRACE(ptlbdp->debug.caller, call);
  678. if (ptlbdp->state != INITIALIZING) {
  679. if (ptlbdp->chunk) {
  680. erts_free(ERTS_ALC_T_PTAB_LIST_CNKI, ptlbdp->chunk);
  681. ptlbdp->chunk = NULL;
  682. }
  683. if (ptlbdp->pid) {
  684. erts_free(ERTS_ALC_T_PTAB_LIST_PIDS, ptlbdp->pid);
  685. ptlbdp->pid = NULL;
  686. }
  687. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
  688. if (ptlbdp->debug.pid_started) {
  689. erts_free(ERTS_ALC_T_PTAB_LIST_PIDS, ptlbdp->debug.pid_started);
  690. ptlbdp->debug.pid_started = NULL;
  691. }
  692. #endif
  693. if (ptlbdp->bif_invocation) {
  694. ErtsPTabDeletedElement *ptdep;
  695. erts_ptab_rwlock(ptab);
  696. ERTS_PTAB_LIST_DBG_TRACE(ptlbdp->debug.caller, deleted_cleanup);
  697. ptdep = ptlbdp->bif_invocation;
  698. ptlbdp->bif_invocation = NULL;
  699. ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
  700. if (ptdep->prev) {
  701. /*
  702. * Only remove this bif invokation when we
  703. * have preceding invokations.
  704. */
  705. ptdep->prev->next = ptdep->next;
  706. if (ptdep->next)
  707. ptdep->next->prev = ptdep->prev;
  708. else {
  709. /*
  710. * At the time of writing this branch cannot be
  711. * reached. I don't want to remove this code though
  712. * since it may be possible to reach this line
  713. * in the future if the cleanup order in
  714. * erts_do_exit_process() is changed. The ASSERT(0)
  715. * is only here to make us aware that the reorder
  716. * has happened. /rickard
  717. */
  718. ASSERT(0);
  719. ptab->list.data.deleted.end = ptdep->prev;
  720. }
  721. erts_free(ERTS_ALC_T_PTAB_LIST_DEL, ptdep);
  722. }
  723. else {
  724. /*
  725. * Free all elements until next bif invokation
  726. * is found.
  727. */
  728. ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start == ptdep);
  729. do {
  730. ErtsPTabDeletedElement *fptdep = ptdep;
  731. ptdep = ptdep->next;
  732. erts_free(ERTS_ALC_T_PTAB_LIST_DEL, fptdep);
  733. } while (ptdep && ptdep->ix >= 0);
  734. ptab->list.data.deleted.start = ptdep;
  735. if (ptdep)
  736. ptdep->prev = NULL;
  737. else
  738. ptab->list.data.deleted.end = NULL;
  739. }
  740. ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
  741. erts_ptab_rwunlock(ptab);
  742. }
  743. }
  744. ERTS_PTAB_LIST_DBG_TRACE(ptlbdp->debug.caller, return);
  745. ERTS_PTAB_LIST_DBG_CLEANUP(ptlbdp);
  746. return 1;
  747. }
  748. static int
  749. ptab_list_bif_engine(Process *c_p, Eterm *res_accp, Binary *mbp)
  750. {
  751. ErtsPTabListBifData *ptlbdp = ERTS_MAGIC_BIN_DATA(mbp);
  752. ErtsPTab *ptab = ptlbdp->ptab;
  753. int have_reds;
  754. int reds;
  755. int locked = 0;
  756. do {
  757. switch (ptlbdp->state) {
  758. case INITIALIZING:
  759. ptlbdp->chunk = erts_alloc(ERTS_ALC_T_PTAB_LIST_CNKI,
  760. (sizeof(ErtsPTabListBifChunkInfo)
  761. * ptab->list.data.chunks));
  762. ptlbdp->tix = 0;
  763. ptlbdp->pid_ix = 0;
  764. erts_ptab_rwlock(ptab);
  765. locked = 1;
  766. ERTS_PTAB_LIST_DBG_TRACE(c_p->common.id, init);
  767. ptlbdp->pid_sz = erts_ptab_count(ptab);
  768. ptlbdp->pid = erts_alloc(ERTS_ALC_T_PTAB_LIST_PIDS,
  769. sizeof(Eterm)*ptlbdp->pid_sz);
  770. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
  771. ptlbdp->debug.pid_started
  772. = erts_alloc(ERTS_ALC_T_PTAB_LIST_PIDS,
  773. sizeof(Uint64)*ptlbdp->pid_sz);
  774. #endif
  775. ERTS_PTAB_LIST_DBG_SAVE_PIDS(ptlbdp);
  776. if (ptab->list.data.chunks == 1)
  777. ptlbdp->bif_invocation = NULL;
  778. else {
  779. /*
  780. * We will have to access the table multiple times
  781. * releasing the table lock in between chunks.
  782. */
  783. ptlbdp->bif_invocation
  784. = erts_alloc(ERTS_ALC_T_PTAB_LIST_DEL,
  785. sizeof(ErtsPTabDeletedElement));
  786. ptlbdp->bif_invocation->ix = -1;
  787. ptlbdp->bif_invocation->u.bif_invocation.interval
  788. = erts_step_interval_nob(erts_ptab_interval(ptab));
  789. ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
  790. ptlbdp->bif_invocation->next = NULL;
  791. if (ptab->list.data.deleted.end) {
  792. ptlbdp->bif_invocation->prev = ptab->list.data.deleted.end;
  793. ptab->list.data.deleted.end->next = ptlbdp->bif_invocation;
  794. ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start);
  795. }
  796. else {
  797. ptlbdp->bif_invocation->prev = NULL;
  798. ptab->list.data.deleted.start = ptlbdp->bif_invocation;
  799. }
  800. ptab->list.data.deleted.end = ptlbdp->bif_invocation;
  801. ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
  802. }
  803. ptlbdp->state = INSPECTING_TABLE;
  804. /* Fall through */
  805. case INSPECTING_TABLE: {
  806. int ix = ptlbdp->tix;
  807. int indices = ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE;
  808. int cix = ix / ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE;
  809. int end_ix = ix + indices;
  810. Uint64 *invocation_interval_p;
  811. ErtsPTabElementCommon *invalid_element;
  812. invocation_interval_p
  813. = (ptlbdp->bif_invocation
  814. ? &ptlbdp->bif_invocation->u.bif_invocation.interval
  815. : NULL);
  816. ERTS_PTAB_LIST_ASSERT(is_nil(*res_accp));
  817. if (!locked) {
  818. erts_ptab_rwlock(ptab);
  819. locked = 1;
  820. }
  821. ERTS_LC_ASSERT(erts_lc_ptab_is_rwlocked(ptab));
  822. ERTS_PTAB_LIST_DBG_TRACE(p->common.id, insp_table);
  823. if (cix != 0)
  824. ptlbdp->chunk[cix].interval
  825. = erts_step_interval_nob(erts_ptab_interval(ptab));
  826. else if (ptlbdp->bif_invocation)
  827. ptlbdp->chunk[0].interval = *invocation_interval_p;
  828. /* else: interval is irrelevant */
  829. if (end_ix >= ptab->r.o.max) {
  830. ERTS_PTAB_LIST_ASSERT(cix+1 == ptab->list.data.chunks);
  831. end_ix = ptab->r.o.max;
  832. indices = end_ix - ix;
  833. /* What to do when done with this chunk */
  834. ptlbdp->state = (ptab->list.data.chunks == 1
  835. ? BUILDING_RESULT
  836. : INSPECTING_DELETED);
  837. }
  838. invalid_element = ptab->r.o.invalid_element;
  839. for (; ix < end_ix; ix++) {
  840. ErtsPTabElementCommon *el;
  841. el = (ErtsPTabElementCommon *) erts_ptab_pix2intptr_nob(ptab,
  842. ix);
  843. if (el
  844. && el != invalid_element
  845. && (!invocation_interval_p
  846. || el->u.alive.started_interval < *invocation_interval_p)) {
  847. ERTS_PTAB_LIST_ASSERT(erts_ptab_is_valid_id(el->id));
  848. ptlbdp->pid[ptlbdp->pid_ix] = el->id;
  849. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
  850. ptlbdp->debug.pid_started[ptlbdp->pid_ix]
  851. = el->u.alive.started_interval;
  852. #endif
  853. ptlbdp->pid_ix++;
  854. ERTS_PTAB_LIST_ASSERT(ptlbdp->pid_ix <= ptlbdp->pid_sz);
  855. }
  856. }
  857. ptlbdp->tix = end_ix;
  858. erts_ptab_rwunlock(ptab);
  859. locked = 0;
  860. reds = indices/ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED;
  861. BUMP_REDS(c_p, reds);
  862. have_reds = ERTS_BIF_REDS_LEFT(c_p);
  863. if (have_reds && ptlbdp->state == INSPECTING_TABLE) {
  864. ix = ptlbdp->tix;
  865. indices = ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE;
  866. end_ix = ix + indices;
  867. if (end_ix > ptab->r.o.max) {
  868. end_ix = ptab->r.o.max;
  869. indices = end_ix - ix;
  870. }
  871. reds = indices/ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED;
  872. /* Pretend we have no reds left if we haven't got enough
  873. reductions to complete next chunk */
  874. if (reds > have_reds)
  875. have_reds = 0;
  876. }
  877. break;
  878. }
  879. case INSPECTING_DELETED: {
  880. int i;
  881. int max_reds;
  882. int free_deleted = 0;
  883. Uint64 invocation_interval;
  884. ErtsPTabDeletedElement *ptdep;
  885. ErtsPTabDeletedElement *free_list = NULL;
  886. ptdep = ptlbdp->bif_invocation;
  887. ERTS_PTAB_LIST_ASSERT(ptdep);
  888. invocation_interval = ptdep->u.bif_invocation.interval;
  889. max_reds = have_reds = ERTS_BIF_REDS_LEFT(c_p);
  890. if (max_reds > ERTS_PTAB_LIST_INSPECT_DELETED_MAX_REDS)
  891. max_reds = ERTS_PTAB_LIST_INSPECT_DELETED_MAX_REDS;
  892. reds = 0;
  893. erts_ptab_rwlock(ptab);
  894. ERTS_PTAB_LIST_DBG_TRACE(p->common.id, insp_term_procs);
  895. ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
  896. if (ptdep->prev)
  897. ptdep->prev->next = ptdep->next;
  898. else {
  899. ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start == ptdep);
  900. ptab->list.data.deleted.start = ptdep->next;
  901. if (ptab->list.data.deleted.start
  902. && ptab->list.data.deleted.start->ix >= 0) {
  903. free_list = ptab->list.data.deleted.start;
  904. free_deleted = 1;
  905. }
  906. }
  907. if (ptdep->next)
  908. ptdep->next->prev = ptdep->prev;
  909. else
  910. ptab->list.data.deleted.end = ptdep->prev;
  911. ptdep = ptdep->next;
  912. i = 0;
  913. while (reds < max_reds && ptdep) {
  914. if (ptdep->ix < 0) {
  915. if (free_deleted) {
  916. ERTS_PTAB_LIST_ASSERT(free_list);
  917. ERTS_PTAB_LIST_ASSERT(ptdep->prev);
  918. ptdep->prev->next = NULL; /* end of free_list */
  919. ptab->list.data.deleted.start = ptdep;
  920. ptdep->prev = NULL;
  921. free_deleted = 0;
  922. }
  923. }
  924. else {
  925. int cix = ptdep->ix/ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE;
  926. Uint64 chunk_interval = ptlbdp->chunk[cix].interval;
  927. Eterm pid = ptdep->u.element.id;
  928. ERTS_PTAB_LIST_ASSERT(erts_ptab_is_valid_id(pid));
  929. if (ptdep->u.element.inserted < invocation_interval) {
  930. if (ptdep->u.element.deleted < chunk_interval) {
  931. ERTS_PTAB_LIST_DBG_CHK_PID_NOT_FOUND(
  932. ptlbdp,
  933. pid,
  934. ptdep->u.element.inserted);
  935. ptlbdp->pid[ptlbdp->pid_ix] = pid;
  936. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
  937. ptlbdp->debug.pid_started[ptlbdp->pid_ix]
  938. = ptdep->u.element.inserted;
  939. #endif
  940. ptlbdp->pid_ix++;
  941. ERTS_PTAB_LIST_ASSERT(ptlbdp->pid_ix
  942. <= ptlbdp->pid_sz);
  943. }
  944. else {
  945. ERTS_PTAB_LIST_DBG_CHK_PID_FOUND(
  946. ptlbdp,
  947. pid,
  948. ptdep->u.element.inserted);
  949. }
  950. }
  951. else {
  952. ERTS_PTAB_LIST_DBG_CHK_PID_NOT_FOUND(
  953. ptlbdp,
  954. pid,
  955. ptdep->u.element.inserted);
  956. }
  957. i++;
  958. if (i == ERTS_PTAB_LIST_BIF_INSPECT_DELETED_PER_RED) {
  959. reds++;
  960. i = 0;
  961. }
  962. if (free_deleted)
  963. reds += ERTS_PTAB_LIST_BIF_TAB_FREE_DELETED_REDS;
  964. }
  965. ptdep = ptdep->next;
  966. }
  967. if (free_deleted) {
  968. ERTS_PTAB_LIST_ASSERT(free_list);
  969. ptab->list.data.deleted.start = ptdep;
  970. if (!ptdep)
  971. ptab->list.data.deleted.end = NULL;
  972. else {
  973. ERTS_PTAB_LIST_ASSERT(ptdep->prev);
  974. ptdep->prev->next = NULL; /* end of free_list */
  975. ptdep->prev = NULL;
  976. }
  977. }
  978. if (!ptdep) {
  979. /* Done */
  980. ERTS_PTAB_LIST_ASSERT(ptlbdp->pid_ix == ptlbdp->pid_sz);
  981. ptlbdp->state = BUILDING_RESULT;
  982. ptlbdp->bif_invocation->next = free_list;
  983. free_list = ptlbdp->bif_invocation;
  984. ptlbdp->bif_invocation = NULL;
  985. }
  986. else {
  987. /* Link in bif_invocation again where we left off */
  988. ptlbdp->bif_invocation->prev = ptdep->prev;
  989. ptlbdp->bif_invocation->next = ptdep;
  990. ptdep->prev = ptlbdp->bif_invocation;
  991. if (ptlbdp->bif_invocation->prev)
  992. ptlbdp->bif_invocation->prev->next = ptlbdp->bif_invocation;
  993. else {
  994. ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start
  995. == ptdep);
  996. ptab->list.data.deleted.start = ptlbdp->bif_invocation;
  997. }
  998. }
  999. ERTS_PTAB_LIST_DBG_CHK_DEL_LIST(ptab);
  1000. ERTS_PTAB_LIST_DBG_CHK_FREELIST(ptab, free_list);
  1001. erts_ptab_rwunlock(ptab);
  1002. /*
  1003. * We do the actual free of deleted structures now when we
  1004. * have released the table lock instead of when we encountered
  1005. * them. This since free() isn't for free and we don't want to
  1006. * unnecessarily block other schedulers.
  1007. */
  1008. while (free_list) {
  1009. ptdep = free_list;
  1010. free_list = ptdep->next;
  1011. erts_free(ERTS_ALC_T_PTAB_LIST_DEL, ptdep);
  1012. }
  1013. have_reds -= reds;
  1014. if (have_reds < 0)
  1015. have_reds = 0;
  1016. BUMP_REDS(c_p, reds);
  1017. break;
  1018. }
  1019. case BUILDING_RESULT: {
  1020. int conses, ix, min_ix;
  1021. Eterm *hp;
  1022. Eterm res = *res_accp;
  1023. ERTS_PTAB_LIST_DBG_VERIFY_PIDS(ptlbdp);
  1024. ERTS_PTAB_LIST_DBG_CHK_RESLIST(res);
  1025. ERTS_PTAB_LIST_DBG_TRACE(p->common.id, begin_build_res);
  1026. have_reds = ERTS_BIF_REDS_LEFT(c_p);
  1027. conses = ERTS_PTAB_LIST_BIF_BUILD_RESULT_CONSES_PER_RED*have_reds;
  1028. min_ix = ptlbdp->pid_ix - conses;
  1029. if (min_ix < 0) {
  1030. min_ix = 0;
  1031. conses = ptlbdp->pid_ix;
  1032. }
  1033. if (conses) {
  1034. hp = HAlloc(c_p, conses*2);
  1035. ERTS_PTAB_LIST_DBG_SAVE_HEAP_ALLOC(ptlbdp, hp, conses*2);
  1036. for (ix = ptlbdp->pid_ix - 1; ix >= min_ix; ix--) {
  1037. ERTS_PTAB_LIST_ASSERT(erts_ptab_is_valid_id(ptlbdp->pid[ix]));
  1038. res = CONS(hp, ptlbdp->pid[ix], res);
  1039. hp += 2;
  1040. }
  1041. ERTS_PTAB_LIST_DBG_VERIFY_HEAP_ALLOC_USED(ptlbdp, hp);
  1042. }
  1043. ptlbdp->pid_ix = min_ix;
  1044. if (min_ix == 0)
  1045. ptlbdp->state = RETURN_RESULT;
  1046. else {
  1047. ptlbdp->pid_sz = min_ix;
  1048. ptlbdp->pid = erts_realloc(ERTS_ALC_T_PTAB_LIST_PIDS,
  1049. ptlbdp->pid,
  1050. sizeof(Eterm)*ptlbdp->pid_sz);
  1051. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
  1052. ptlbdp->debug.pid_started
  1053. = erts_realloc(ERTS_ALC_T_PTAB_LIST_PIDS,
  1054. ptlbdp->debug.pid_started,
  1055. sizeof(Uint64) * ptlbdp->pid_sz);
  1056. #endif
  1057. }
  1058. reds = conses/ERTS_PTAB_LIST_BIF_BUILD_RESULT_CONSES_PER_RED;
  1059. BUMP_REDS(c_p, reds);
  1060. have_reds -= reds;
  1061. ERTS_PTAB_LIST_DBG_CHK_RESLIST(res);
  1062. ERTS_PTAB_LIST_DBG_TRACE(c_p->common.id, end_build_res);
  1063. *res_accp = res;
  1064. break;
  1065. }
  1066. case RETURN_RESULT:
  1067. cleanup_ptab_list_bif_data(mbp);
  1068. return 1;
  1069. default:
  1070. erts_exit(ERTS_ABORT_EXIT,
  1071. "%s:%d:ptab_list_bif_engine(): Invalid state: %d\n",
  1072. __FILE__, __LINE__, (int) ptlbdp->state);
  1073. }
  1074. } while (have_reds || ptlbdp->state == RETURN_RESULT);
  1075. return 0;
  1076. }
  1077. /*
  1078. * ptab_list_continue/2 is a hidden BIF that the original BIF traps to
  1079. * if there are too much work to do in one go.
  1080. */
  1081. static BIF_RETTYPE ptab_list_continue(BIF_ALIST_2)
  1082. {
  1083. Eterm res_acc;
  1084. Binary *mbp;
  1085. /*
  1086. * This bif cannot be called from erlang code. It can only be
  1087. * trapped to from other BIFs; therefore, a bad argument
  1088. * is an internal error and should never occur...
  1089. */
  1090. ERTS_PTAB_LIST_DBG_TRACE(BIF_P->common.id, call);
  1091. ERTS_PTAB_LIST_ASSERT(is_nil(BIF_ARG_1) || is_list(BIF_ARG_1));
  1092. res_acc = BIF_ARG_1;
  1093. mbp = erts_magic_ref2bin(BIF_ARG_2);
  1094. ERTS_PTAB_LIST_ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(mbp)
  1095. == cleanup_ptab_list_bif_data);
  1096. ERTS_PTAB_LIST_ASSERT(
  1097. ((ErtsPTabListBifData *) ERTS_MAGIC_BIN_DATA(mbp))->debug.caller
  1098. == BIF_P->common.id);
  1099. if (ptab_list_bif_engine(BIF_P, &res_acc, mbp)) {
  1100. ERTS_PTAB_LIST_DBG_TRACE(BIF_P->common.id, return);
  1101. BIF_RET(res_acc);
  1102. }
  1103. else {
  1104. ERTS_PTAB_LIST_DBG_TRACE(BIF_P->common.id, trap);
  1105. ERTS_BIF_YIELD2(&ptab_list_continue_export, BIF_P, res_acc, BIF_ARG_2);
  1106. }
  1107. }
  1108. void
  1109. erts_ptab_init(void)
  1110. {
  1111. /* ptab_list_continue/2 is a hidden BIF that the original BIF traps to. */
  1112. erts_init_trap_export(&ptab_list_continue_export,
  1113. am_erlang, am_ptab_list_continue, 2,
  1114. &ptab_list_continue);
  1115. }
  1116. /*
  1117. * Debug stuff
  1118. */
  1119. static void assert_ptab_consistency(ErtsPTab *ptab)
  1120. {
  1121. #ifdef DEBUG
  1122. if (ptab->r.o.free_id_data) {
  1123. Uint32 ix, pix, data;
  1124. int free_pids = 0;
  1125. int null_slots = 0;
  1126. for (ix=0; ix < ptab->r.o.max; ix++) {
  1127. if (erts_atomic32_read_nob(&ptab->r.o.free_id_data[ix]) != ptab->r.o.invalid_data) {
  1128. ++free_pids;
  1129. data = erts_atomic32_read_nob(&ptab->r.o.free_id_data[ix]);
  1130. pix = erts_ptab_data2pix(ptab, (Eterm) data);
  1131. ASSERT(erts_ptab_pix2intptr_nob(ptab, pix) == ERTS_AINT_NULL);
  1132. }
  1133. if (erts_atomic_read_nob(&ptab->r.o.tab[ix]) == ERTS_AINT_NULL) {
  1134. ++null_slots;
  1135. }
  1136. }
  1137. ASSERT(free_pids == null_slots);
  1138. ASSERT(free_pids == ptab->r.o.max - erts_atomic32_read_nob(&ptab->vola.tile.count));
  1139. }
  1140. #endif
  1141. }
  1142. Sint
  1143. erts_ptab_test_next_id(ErtsPTab *ptab, int set, Uint next)
  1144. {
  1145. Uint64 ld;
  1146. Sint res;
  1147. Eterm data;
  1148. int first_pix = -1;
  1149. erts_ptab_rwlock(ptab);
  1150. assert_ptab_consistency(ptab);
  1151. if (ptab->r.o.free_id_data) {
  1152. Uint32 id_ix, dix;
  1153. if (set) {
  1154. Uint32 i, max_ix, num, stop_id_ix;
  1155. max_ix = ptab->r.o.max - 1;
  1156. num = next;
  1157. id_ix = (Uint32) erts_atomic32_read_nob(&ptab->vola.tile.aid_ix);
  1158. for (i=0; i <= max_ix; ++i) {
  1159. Uint32 pix;
  1160. ++num;
  1161. num &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE);
  1162. if (num == ptab->r.o.invalid_data) {
  1163. num += ptab->r.o.max;
  1164. num &= ~(~((Uint32) 0) << ERTS_PTAB_ID_DATA_SIZE);
  1165. }
  1166. pix = erts_ptab_data2pix(ptab, num);
  1167. if (ERTS_AINT_NULL == erts_ptab_pix2intptr_nob(ptab, pix)) {
  1168. ++id_ix;
  1169. dix = ix_to_free_id_data_ix(ptab, id_ix);
  1170. erts_atomic32_set_nob(&ptab->r.o.free_id_data[dix], num);
  1171. ASSERT(pix == erts_ptab_data2pix(ptab, num));
  1172. }
  1173. }
  1174. erts_atomic32_set_nob(&ptab->vola.tile.fid_ix, id_ix);
  1175. /* Write invalid_data in rest of free_id_data[]: */
  1176. stop_id_ix = (1 + erts_atomic32_read_nob(&ptab->vola.tile.aid_ix)) & max_ix;
  1177. while (1) {
  1178. id_ix = (id_ix+1) & max_ix;
  1179. if (id_ix == stop_id_ix)
  1180. break;
  1181. dix = ix_to_free_id_data_ix(ptab, id_ix);
  1182. erts_atomic32_set_nob(&ptab->r.o.free_id_data[dix],
  1183. ptab->r.o.invalid_data);
  1184. }
  1185. }
  1186. id_ix = (Uint32) erts_atomic32_read_nob(&ptab->vola.tile.aid_ix) + 1;
  1187. dix = ix_to_free_id_data_ix(ptab, id_ix);
  1188. res = (Sint) erts_atomic32_read_nob(&ptab->r.o.free_id_data[dix]);
  1189. }
  1190. else {
  1191. /* Deprecated legacy algorithm... */
  1192. if (!set)
  1193. ld = last_data_read_nob(ptab);
  1194. else {
  1195. ld = (Uint64) next;
  1196. data = ERTS_PTAB_LastData2EtermData(ld);
  1197. if (ptab->r.o.invalid_data == data) {
  1198. ld += ptab->r.o.max;
  1199. ASSERT(erts_ptab_data2pix(ptab, data)
  1200. == erts_ptab_data2pix(ptab,
  1201. ERTS_PTAB_LastData2EtermData(ld)));
  1202. }
  1203. last_data_set_relb(ptab, ld);
  1204. }
  1205. while (1) {
  1206. int pix;
  1207. ld++;
  1208. pix = (int) (ld % ptab->r.o.max);
  1209. if (first_pix < 0)
  1210. first_pix = pix;
  1211. else if (pix == first_pix) {
  1212. res = -1;
  1213. break;
  1214. }
  1215. if (ERTS_AINT_NULL == erts_ptab_pix2intptr_nob(ptab, pix)) {
  1216. data = ERTS_PTAB_LastData2EtermData(ld);
  1217. if (ptab->r.o.invalid_data == data) {
  1218. ld += ptab->r.o.max;
  1219. ASSERT(erts_ptab_data2pix(ptab, data)
  1220. == erts_ptab_data2pix(ptab,
  1221. ERTS_PTAB_LastData2EtermData(ld)));
  1222. data = ERTS_PTAB_LastData2EtermData(ld);
  1223. }
  1224. res = data;
  1225. break;
  1226. }
  1227. }
  1228. }
  1229. assert_ptab_consistency(ptab);
  1230. erts_ptab_rwunlock(ptab);
  1231. return res;
  1232. }
  1233. static ERTS_INLINE ErtsPTabElementCommon *
  1234. ptab_pix2el(ErtsPTab *ptab, int ix)
  1235. {
  1236. ErtsPTabElementCommon *ptab_el;
  1237. ASSERT(0 <= ix && ix < ptab->r.o.max);
  1238. ptab_el = (ErtsPTabElementCommon *) erts_ptab_pix2intptr_nob(ptab, ix);
  1239. if (ptab_el == ptab->r.o.invalid_element)
  1240. return NULL;
  1241. else
  1242. return ptab_el;
  1243. }
  1244. Eterm
  1245. erts_debug_ptab_list(Process *c_p, ErtsPTab *ptab)
  1246. {
  1247. int i;
  1248. Uint need;
  1249. Eterm res;
  1250. Eterm* hp;
  1251. Eterm *hp_end;
  1252. erts_ptab_rwlock(ptab);
  1253. res = NIL;
  1254. need = erts_ptab_count(ptab) * 2;
  1255. hp = HAlloc(c_p, need); /* we need two heap words for each id */
  1256. hp_end = hp + need;
  1257. /* make the list by scanning bakward */
  1258. for (i = ptab->r.o.max-1; i >= 0; i--) {
  1259. ErtsPTabElementCommon *el = ptab_pix2el(ptab, i);
  1260. if (el) {
  1261. res = CONS(hp, el->id, res);
  1262. hp += 2;
  1263. }
  1264. }
  1265. erts_ptab_rwunlock(ptab);
  1266. HRelease(c_p, hp_end, hp);
  1267. return res;
  1268. }
  1269. Eterm
  1270. erts_debug_ptab_list_bif_info(Process *c_p, ErtsPTab *ptab)
  1271. {
  1272. ERTS_DECL_AM(ptab_list_bif_info);
  1273. Eterm elements[] = {
  1274. AM_ptab_list_bif_info,
  1275. make_small((Uint) ERTS_PTAB_LIST_BIF_MIN_START_REDS),
  1276. make_small((Uint) ptab->list.data.chunks),
  1277. make_small((Uint) ERTS_PTAB_LIST_BIF_TAB_CHUNK_SIZE),
  1278. make_small((Uint) ERTS_PTAB_LIST_BIF_TAB_INSPECT_INDICES_PER_RED),
  1279. make_small((Uint) ERTS_PTAB_LIST_BIF_TAB_FREE_DELETED_REDS),
  1280. make_small((Uint) ERTS_PTAB_LIST_BIF_INSPECT_DELETED_PER_RED),
  1281. make_small((Uint) ERTS_PTAB_LIST_INSPECT_DELETED_MAX_REDS),
  1282. make_small((Uint) ERTS_PTAB_LIST_BIF_BUILD_RESULT_CONSES_PER_RED),
  1283. make_small((Uint) ERTS_PTAB_LIST_BIF_DEBUGLEVEL)
  1284. };
  1285. Uint sz = 0;
  1286. Eterm *hp;
  1287. (void) erts_bld_tuplev(NULL, &sz, sizeof(elements)/sizeof(Eterm), elements);
  1288. hp = HAlloc(c_p, sz);
  1289. return erts_bld_tuplev(&hp, NULL, sizeof(elements)/sizeof(Eterm), elements);
  1290. }
  1291. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_FOUND_PIDS
  1292. static void
  1293. debug_ptab_list_check_found_pid(ErtsPTabListBifData *ptlbdp,
  1294. Eterm pid,
  1295. Uint64 ic,
  1296. int pid_should_be_found)
  1297. {
  1298. int i;
  1299. for (i = 0; i < ptlbdp->pid_ix; i++) {
  1300. if (ptlbdp->pid[i] == pid && ptlbdp->debug.pid_started[i] == ic) {
  1301. ERTS_PTAB_LIST_ASSERT(pid_should_be_found);
  1302. return;
  1303. }
  1304. }
  1305. ERTS_PTAB_LIST_ASSERT(!pid_should_be_found);
  1306. }
  1307. #endif
  1308. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_RESLIST
  1309. static void
  1310. debug_ptab_list_check_res_list(Eterm list)
  1311. {
  1312. while (is_list(list)) {
  1313. Eterm* consp = list_val(list);
  1314. Eterm hd = CAR(consp);
  1315. ERTS_PTAB_LIST_ASSERT(erts_ptab_is_valid_id(hd));
  1316. list = CDR(consp);
  1317. }
  1318. ERTS_PTAB_LIST_ASSERT(is_nil(list));
  1319. }
  1320. #endif
  1321. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_PIDS
  1322. static void
  1323. debug_ptab_list_save_all_pids(ErtsPTabListBifData *ptlbdp)
  1324. {
  1325. int ix, tix, cpix;
  1326. ErtsPTab *ptab = ptlbdp->ptab;
  1327. ptlbdp->debug.correct_pids_verified = 0;
  1328. ptlbdp->debug.correct_pids = erts_alloc(ERTS_ALC_T_PTAB_LIST_PIDS,
  1329. sizeof(Eterm)*ptlbdp->pid_sz);
  1330. for (tix = 0, cpix = 0; tix < ptab->r.o.max; tix++) {
  1331. ErtsPTabElementCommon *el = ptab_pix2el(ptab, tix);
  1332. if (el) {
  1333. ERTS_PTAB_LIST_ASSERT(erts_ptab_is_valid_id(el->id));
  1334. ptlbdp->debug.correct_pids[cpix++] = el->id;
  1335. ERTS_PTAB_LIST_ASSERT(cpix <= ptlbdp->pid_sz);
  1336. }
  1337. }
  1338. ERTS_PTAB_LIST_ASSERT(cpix == ptlbdp->pid_sz);
  1339. for (ix = 0; ix < ptlbdp->pid_sz; ix++)
  1340. ptlbdp->pid[ix] = make_small(ix);
  1341. }
  1342. static void
  1343. debug_ptab_list_verify_all_pids(ErtsPTabListBifData *ptlbdp)
  1344. {
  1345. int ix, cpix;
  1346. ERTS_PTAB_LIST_ASSERT(ptlbdp->pid_ix == ptlbdp->pid_sz);
  1347. for (ix = 0; ix < ptlbdp->pid_sz; ix++) {
  1348. int found = 0;
  1349. Eterm pid = ptlbdp->pid[ix];
  1350. ERTS_PTAB_LIST_ASSERT(erts_ptab_is_valid_id(pid));
  1351. for (cpix = ix; cpix < ptlbdp->pid_sz; cpix++) {
  1352. if (ptlbdp->debug.correct_pids[cpix] == pid) {
  1353. ptlbdp->debug.correct_pids[cpix] = NIL;
  1354. found = 1;
  1355. break;
  1356. }
  1357. }
  1358. if (!found) {
  1359. for (cpix = 0; cpix < ix; cpix++) {
  1360. if (ptlbdp->debug.correct_pids[cpix] == pid) {
  1361. ptlbdp->debug.correct_pids[cpix] = NIL;
  1362. found = 1;
  1363. break;
  1364. }
  1365. }
  1366. }
  1367. ERTS_PTAB_LIST_ASSERT(found);
  1368. }
  1369. ptlbdp->debug.correct_pids_verified = 1;
  1370. erts_free(ERTS_ALC_T_PTAB_LIST_PIDS, ptlbdp->debug.correct_pids);
  1371. ptlbdp->debug.correct_pids = NULL;
  1372. }
  1373. #endif /* ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_PIDS */
  1374. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL >= ERTS_PTAB_LIST_DBGLVL_CHK_DEL_LIST
  1375. static void
  1376. debug_ptab_list_check_del_list(ErtsPTab *ptab)
  1377. {
  1378. ERTS_LC_ASSERT(erts_lc_ptab_is_rwlocked(ptab));
  1379. if (!ptab->list.data.deleted.start)
  1380. ERTS_PTAB_LIST_ASSERT(!ptab->list.data.deleted.end);
  1381. else {
  1382. Uint64 curr_interval = erts_current_interval_nob(erts_ptab_interval(ptab));
  1383. Uint64 *prev_x_interval_p = NULL;
  1384. ErtsPTabDeletedElement *ptdep;
  1385. for (ptdep = ptab->list.data.deleted.start;
  1386. ptdep;
  1387. ptdep = ptdep->next) {
  1388. if (!ptdep->prev)
  1389. ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.start == ptdep);
  1390. else
  1391. ERTS_PTAB_LIST_ASSERT(ptdep->prev->next == ptdep);
  1392. if (!ptdep->next)
  1393. ERTS_PTAB_LIST_ASSERT(ptab->list.data.deleted.end == ptdep);
  1394. else
  1395. ERTS_PTAB_LIST_ASSERT(ptdep->next->prev == ptdep);
  1396. if (ptdep->ix < 0) {
  1397. Uint64 interval = ptdep->u.bif_invocation.interval;
  1398. ERTS_PTAB_LIST_ASSERT(interval <= curr_interval);
  1399. }
  1400. else {
  1401. Uint64 s_interval = ptdep->u.element.inserted;
  1402. Uint64 x_interval = ptdep->u.element.deleted;
  1403. ERTS_PTAB_LIST_ASSERT(s_interval <= x_interval);
  1404. if (prev_x_interval_p)
  1405. ERTS_PTAB_LIST_ASSERT(*prev_x_interval_p <= x_interval);
  1406. prev_x_interval_p = &ptdep->u.element.deleted;
  1407. ERTS_PTAB_LIST_ASSERT(
  1408. erts_ptab_is_valid_id(ptdep->u.element.id));
  1409. ERTS_PTAB_LIST_ASSERT(erts_ptab_id2pix(ptab,
  1410. ptdep->u.element.id)
  1411. == ptdep->ix);
  1412. }
  1413. }
  1414. }
  1415. }
  1416. static void
  1417. debug_ptab_list_check_del_free_list(ErtsPTab *ptab,
  1418. ErtsPTabDeletedElement *free_list)
  1419. {
  1420. if (ptab->list.data.deleted.start) {
  1421. ErtsPTabDeletedElement *fptdep;
  1422. ErtsPTabDeletedElement *ptdep;
  1423. for (fptdep = free_list; fptdep; fptdep = fptdep->next) {
  1424. for (ptdep = ptab->list.data.deleted.start;
  1425. ptdep;
  1426. ptdep = ptdep->next) {
  1427. ERTS_PTAB_LIST_ASSERT(fptdep != ptdep);
  1428. }
  1429. }
  1430. }
  1431. }
  1432. #endif
  1433. #if ERTS_PTAB_LIST_BIF_DEBUGLEVEL != 0
  1434. static void
  1435. debug_ptab_list_assert_error(char* expr, const char* file, int line, const char *func)
  1436. {
  1437. fflush(stdout);
  1438. erts_fprintf(stderr, "%s:%d:%s(): Assertion failed: %s\n",
  1439. (char *) file, line, (char *) func, expr);
  1440. fflush(stderr);
  1441. abort();
  1442. }
  1443. #endif