PageRenderTime 68ms CodeModel.GetById 24ms RepoModel.GetById 1ms app.codeStats 1ms

/erts/emulator/beam/erl_bif_info.c

https://github.com/bsmr-erlang/otp
C | 5205 lines | 4420 code | 555 blank | 230 comment | 1150 complexity | dc4aed70d905f906d55343d1d7cc2755 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.1, MPL-2.0-no-copyleft-exception, Apache-2.0

Large files files are truncated, but you can click here to view the full file

  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 1999-2018. 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. #ifdef HAVE_CONFIG_H
  21. # include "config.h"
  22. #endif
  23. #define ERTS_WANT_MEM_MAPPERS
  24. #include "sys.h"
  25. #include "erl_vm.h"
  26. #include "global.h"
  27. #include "erl_process.h"
  28. #include "error.h"
  29. #include "erl_driver.h"
  30. #include "erl_nif.h"
  31. #include "bif.h"
  32. #include "big.h"
  33. #include "erl_version.h"
  34. #include "erl_compile_flags.h"
  35. #include "erl_db_util.h"
  36. #include "erl_message.h"
  37. #include "erl_binary.h"
  38. #include "erl_db.h"
  39. #include "erl_mtrace.h"
  40. #include "dist.h"
  41. #include "erl_gc.h"
  42. #include "erl_cpu_topology.h"
  43. #include "erl_async.h"
  44. #include "erl_thr_progress.h"
  45. #include "erl_bif_unique.h"
  46. #include "erl_map.h"
  47. #include "erl_check_io.h"
  48. #define ERTS_PTAB_WANT_DEBUG_FUNCS__
  49. #include "erl_ptab.h"
  50. #include "erl_time.h"
  51. #include "erl_proc_sig_queue.h"
  52. #include "erl_alloc_util.h"
  53. #ifdef HIPE
  54. #include "hipe_arch.h"
  55. #endif
  56. #ifdef ERTS_ENABLE_LOCK_COUNT
  57. #include "erl_lock_count.h"
  58. #endif
  59. #ifdef VALGRIND
  60. #include <valgrind/valgrind.h>
  61. #include <valgrind/memcheck.h>
  62. #endif
  63. static Export* alloc_info_trap = NULL;
  64. static Export* alloc_sizes_trap = NULL;
  65. static Export* gather_io_bytes_trap = NULL;
  66. static Export *gather_sched_wall_time_res_trap;
  67. static Export *gather_msacc_res_trap;
  68. static Export *gather_gc_info_res_trap;
  69. static Export *gather_system_check_res_trap;
  70. static Export *is_process_alive_trap;
  71. #define DECL_AM(S) Eterm AM_ ## S = am_atom_put(#S, sizeof(#S) - 1)
  72. static char otp_version[] = ERLANG_OTP_VERSION;
  73. /* Keep erts_system_version as a global variable for easy access from a core */
  74. static char erts_system_version[] = ("Erlang/OTP " ERLANG_OTP_RELEASE
  75. "%s"
  76. " [erts-" ERLANG_VERSION "]"
  77. #ifndef OTP_RELEASE
  78. #ifdef ERLANG_GIT_VERSION
  79. " [source-" ERLANG_GIT_VERSION "]"
  80. #else
  81. " [source]"
  82. #endif
  83. #endif
  84. #ifdef ARCH_64
  85. " [64-bit]"
  86. #endif
  87. " [smp:%beu:%beu]"
  88. " [ds:%beu:%beu:%beu]"
  89. #if defined(ERTS_DIRTY_SCHEDULERS_TEST)
  90. " [dirty-schedulers-TEST]"
  91. #endif
  92. " [async-threads:%d]"
  93. #ifdef HIPE
  94. " [hipe]"
  95. #endif
  96. #ifdef ET_DEBUG
  97. #if ET_DEBUG
  98. " [type-assertions]"
  99. #endif
  100. #endif
  101. #ifdef DEBUG
  102. " [debug-compiled]"
  103. #endif
  104. #ifdef ERTS_ENABLE_LOCK_CHECK
  105. " [lock-checking]"
  106. #endif
  107. #ifdef ERTS_ENABLE_LOCK_COUNT
  108. " [lock-counting]"
  109. #endif
  110. #ifdef ERTS_OPCODE_COUNTER_SUPPORT
  111. " [instruction-counting]"
  112. #endif
  113. #ifdef PURIFY
  114. " [purify-compiled]"
  115. #endif
  116. #ifdef VALGRIND
  117. " [valgrind-compiled]"
  118. #endif
  119. #ifdef ERTS_FRMPTR
  120. " [frame-pointer]"
  121. #endif
  122. #ifdef USE_LTTNG
  123. " [lttng]"
  124. #endif
  125. #ifdef USE_DTRACE
  126. " [dtrace]"
  127. #endif
  128. #ifdef USE_SYSTEMTAP
  129. " [systemtap]"
  130. #endif
  131. #ifdef SHCOPY
  132. " [sharing-preserving]"
  133. #endif
  134. "\n");
  135. #define ASIZE(a) (sizeof(a)/sizeof(a[0]))
  136. #if defined(HAVE_SOLARIS_SPARC_PERFMON)
  137. # include <sys/ioccom.h>
  138. # define PERFMON_SETPCR _IOW('P', 1, unsigned long long)
  139. # define PERFMON_GETPCR _IOR('P', 2, unsigned long long)
  140. #endif
  141. /* Cached, pre-built {OsType,OsFlavor} and {Major,Minor,Build} tuples */
  142. static Eterm os_type_tuple;
  143. static Eterm os_version_tuple;
  144. static Eterm
  145. current_function(Process* p, ErtsHeapFactory *hfact, Process* rp,
  146. int full_info, Uint reserve_size, int flags);
  147. static Eterm current_stacktrace(ErtsHeapFactory *hfact, Process* rp,
  148. Uint reserve_size);
  149. static Eterm
  150. bld_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh)
  151. {
  152. struct erl_off_heap_header* ohh;
  153. Eterm res = NIL;
  154. Eterm tuple;
  155. for (ohh = oh->first; ohh; ohh = ohh->next) {
  156. if (ohh->thing_word == HEADER_PROC_BIN) {
  157. ProcBin* pb = (ProcBin*) ohh;
  158. Eterm val = erts_bld_uword(hpp, szp, (UWord) pb->val);
  159. Eterm orig_size = erts_bld_uint(hpp, szp, pb->val->orig_size);
  160. if (szp)
  161. *szp += 4+2;
  162. if (hpp) {
  163. Uint refc = (Uint) erts_refc_read(&pb->val->intern.refc, 1);
  164. tuple = TUPLE3(*hpp, val, orig_size, make_small(refc));
  165. res = CONS(*hpp + 4, tuple, res);
  166. *hpp += 4+2;
  167. }
  168. }
  169. }
  170. return res;
  171. }
  172. static Eterm
  173. bld_magic_ref_bin_list(Uint **hpp, Uint *szp, ErlOffHeap* oh)
  174. {
  175. struct erl_off_heap_header* ohh;
  176. Eterm res = NIL;
  177. Eterm tuple;
  178. for (ohh = oh->first; ohh; ohh = ohh->next) {
  179. if (is_ref_thing_header((*((Eterm *) ohh)))) {
  180. ErtsMRefThing *mrtp = (ErtsMRefThing *) ohh;
  181. Eterm val = erts_bld_uword(hpp, szp, (UWord) mrtp->mb);
  182. Eterm orig_size = erts_bld_uint(hpp, szp, mrtp->mb->orig_size);
  183. if (szp)
  184. *szp += 4+2;
  185. if (hpp) {
  186. Uint refc = (Uint) erts_refc_read(&mrtp->mb->intern.refc, 1);
  187. tuple = TUPLE3(*hpp, val, orig_size, make_small(refc));
  188. res = CONS(*hpp + 4, tuple, res);
  189. *hpp += 4+2;
  190. }
  191. }
  192. }
  193. return res;
  194. }
  195. /*
  196. make_monitor_list:
  197. returns a list of records..
  198. -record(erl_monitor, {
  199. type, % process | port | time_offset | dist_process | resource
  200. % | node | nodes | suspend
  201. dir, % origin | target
  202. ref, % reference or []
  203. pid, % Process or nodename
  204. extra % registered name, integer or []
  205. }).
  206. */
  207. static int do_calc_mon_size(ErtsMonitor *mon, void *vpsz, Sint reds)
  208. {
  209. ErtsMonitorData *mdp = erts_monitor_to_data(mon);
  210. Uint *psz = vpsz;
  211. *psz += is_immed(mdp->ref) ? 0 : NC_HEAP_SIZE(mdp->ref);
  212. if (mon->type == ERTS_MON_TYPE_RESOURCE && erts_monitor_is_target(mon))
  213. *psz += erts_resource_ref_size(mon->other.ptr);
  214. else
  215. *psz += is_immed(mon->other.item) ? 0 : NC_HEAP_SIZE(mon->other.item);
  216. *psz += 9; /* CONS + 6-tuple */
  217. return 1;
  218. }
  219. typedef struct {
  220. Process *p;
  221. Eterm *hp;
  222. Eterm res;
  223. Eterm tag;
  224. } MonListContext;
  225. static int do_make_one_mon_element(ErtsMonitor *mon, void * vpmlc, Sint reds)
  226. {
  227. ErtsMonitorData *mdp = erts_monitor_to_data(mon);
  228. MonListContext *pmlc = vpmlc;
  229. Eterm tup, t, d, r, p, x;
  230. r = is_immed(mdp->ref) ? mdp->ref : STORE_NC(&(pmlc->hp), &MSO(pmlc->p), mdp->ref);
  231. if (mon->type == ERTS_MON_TYPE_RESOURCE && erts_monitor_is_target(mon))
  232. p = erts_bld_resource_ref(&(pmlc->hp), &MSO(pmlc->p), mon->other.ptr);
  233. else
  234. p = (is_immed(mon->other.item)
  235. ? mon->other.item
  236. : STORE_NC(&(pmlc->hp), &MSO(pmlc->p), mon->other.item));
  237. if (mon->flags & ERTS_ML_FLG_NAME)
  238. x = ((ErtsMonitorDataExtended *) mdp)->u.name;
  239. else if (erts_monitor_is_target(mon))
  240. x = NIL;
  241. else if (mon->type == ERTS_MON_TYPE_NODE || mon->type == ERTS_MON_TYPE_NODES)
  242. x = make_small(((ErtsMonitorDataExtended *) mdp)->u.refc);
  243. else
  244. x = NIL;
  245. switch (mon->type) {
  246. case ERTS_MON_TYPE_PROC:
  247. t = am_process;
  248. break;
  249. case ERTS_MON_TYPE_PORT:
  250. t = am_port;
  251. break;
  252. case ERTS_MON_TYPE_TIME_OFFSET:
  253. t = am_time_offset;
  254. break;
  255. case ERTS_MON_TYPE_DIST_PROC: {
  256. ERTS_DECL_AM(dist_process);
  257. t = AM_dist_process;
  258. break;
  259. }
  260. case ERTS_MON_TYPE_RESOURCE: {
  261. ERTS_DECL_AM(resource);
  262. t = AM_resource;
  263. break;
  264. }
  265. case ERTS_MON_TYPE_NODE:
  266. t = am_node;
  267. break;
  268. case ERTS_MON_TYPE_NODES: {
  269. ERTS_DECL_AM(nodes);
  270. t = AM_nodes;
  271. break;
  272. }
  273. case ERTS_MON_TYPE_SUSPEND:
  274. t = am_suspend;
  275. break;
  276. default:
  277. ERTS_INTERNAL_ERROR("Unknown monitor type");
  278. t = am_error;
  279. break;
  280. }
  281. if (erts_monitor_is_target(mon)) {
  282. ERTS_DECL_AM(target);
  283. d = AM_target;
  284. }
  285. else {
  286. ERTS_DECL_AM(origin);
  287. d = AM_origin;
  288. }
  289. tup = TUPLE6(pmlc->hp, pmlc->tag, t, d, r, p, x);
  290. pmlc->hp += 7;
  291. pmlc->res = CONS(pmlc->hp, tup, pmlc->res);
  292. pmlc->hp += 2;
  293. return 1;
  294. }
  295. static Eterm
  296. make_monitor_list(Process *p, int tree, ErtsMonitor *root, Eterm tail)
  297. {
  298. DECL_AM(erl_monitor);
  299. Uint sz = 0;
  300. MonListContext mlc;
  301. void (*foreach)(ErtsMonitor *,
  302. ErtsMonitorFunc,
  303. void *);
  304. foreach = tree ? erts_monitor_tree_foreach : erts_monitor_list_foreach;
  305. (*foreach)(root, do_calc_mon_size, &sz);
  306. if (sz == 0)
  307. return tail;
  308. mlc.p = p;
  309. mlc.hp = HAlloc(p,sz);
  310. mlc.res = tail;
  311. mlc.tag = AM_erl_monitor;
  312. (*foreach)(root, do_make_one_mon_element, &mlc);
  313. return mlc.res;
  314. }
  315. /*
  316. make_link_list:
  317. returns a list of records..
  318. -record(erl_link, {
  319. type, % process | port | dist_process
  320. pid, % Process or port
  321. id % (address)
  322. }).
  323. */
  324. static int calc_lnk_size(ErtsLink *lnk, void *vpsz, Sint reds)
  325. {
  326. Uint *psz = vpsz;
  327. Uint sz = 0;
  328. ErtsLinkData *ldp = erts_link_to_data(lnk);
  329. (void) erts_bld_uword(NULL, &sz, (UWord) ldp);
  330. *psz += sz;
  331. *psz += is_immed(lnk->other.item) ? 0 : size_object(lnk->other.item);
  332. *psz += 7; /* CONS + 4-tuple */
  333. return 1;
  334. }
  335. typedef struct {
  336. Process *p;
  337. Eterm *hp;
  338. Eterm res;
  339. Eterm tag;
  340. } LnkListContext;
  341. static int make_one_lnk_element(ErtsLink *lnk, void * vpllc, Sint reds)
  342. {
  343. LnkListContext *pllc = vpllc;
  344. Eterm tup, t, pid, id;
  345. ErtsLinkData *ldp = erts_link_to_data(lnk);
  346. id = erts_bld_uword(&pllc->hp, NULL, (UWord) ldp);
  347. if (is_immed(lnk->other.item))
  348. pid = lnk->other.item;
  349. else {
  350. Uint sz = size_object(lnk->other.item);
  351. pid = copy_struct(lnk->other.item, sz, &(pllc->hp), &MSO(pllc->p));
  352. }
  353. switch (lnk->type) {
  354. case ERTS_LNK_TYPE_PROC:
  355. t = am_process;
  356. break;
  357. case ERTS_LNK_TYPE_PORT:
  358. t = am_port;
  359. break;
  360. case ERTS_LNK_TYPE_DIST_PROC: {
  361. ERTS_DECL_AM(dist_process);
  362. t = AM_dist_process;
  363. break;
  364. }
  365. default:
  366. ERTS_INTERNAL_ERROR("Unkown link type");
  367. t = am_undefined;
  368. break;
  369. }
  370. tup = TUPLE4(pllc->hp, pllc->tag, t, pid, id);
  371. pllc->hp += 5;
  372. pllc->res = CONS(pllc->hp, tup, pllc->res);
  373. pllc->hp += 2;
  374. return 1;
  375. }
  376. static Eterm
  377. make_link_list(Process *p, int tree, ErtsLink *root, Eterm tail)
  378. {
  379. DECL_AM(erl_link);
  380. Uint sz = 0;
  381. LnkListContext llc;
  382. void (*foreach)(ErtsLink *,
  383. ErtsLinkFunc,
  384. void *);
  385. foreach = tree ? erts_link_tree_foreach : erts_link_list_foreach;
  386. (*foreach)(root, calc_lnk_size, (void *) &sz);
  387. if (sz == 0) {
  388. return tail;
  389. }
  390. llc.p = p;
  391. llc.hp = HAlloc(p,sz);
  392. llc.res = tail;
  393. llc.tag = AM_erl_link;
  394. (*foreach)(root, make_one_lnk_element, (void *) &llc);
  395. return llc.res;
  396. }
  397. int
  398. erts_print_system_version(fmtfn_t to, void *arg, Process *c_p)
  399. {
  400. int i, rc = -1;
  401. char *rc_str = "";
  402. char rc_buf[100];
  403. char *ov = otp_version;
  404. Uint total, online, active;
  405. Uint dirty_cpu, dirty_cpu_onln, dirty_io;
  406. erts_schedulers_state(&total, &online, &active,
  407. &dirty_cpu, &dirty_cpu_onln, NULL,
  408. &dirty_io, NULL);
  409. for (i = 0; i < sizeof(otp_version)-4; i++) {
  410. if (ov[i] == '-' && ov[i+1] == 'r' && ov[i+2] == 'c')
  411. rc = atoi(&ov[i+3]);
  412. }
  413. if (rc >= 0) {
  414. if (rc == 0)
  415. rc_str = " [DEVELOPMENT]";
  416. else {
  417. erts_snprintf(rc_buf, sizeof(rc_buf), " [RELEASE CANDIDATE %d]", rc);
  418. rc_str = rc_buf;
  419. }
  420. }
  421. return erts_print(to, arg, erts_system_version,
  422. rc_str
  423. , total, online
  424. , dirty_cpu, dirty_cpu_onln, dirty_io
  425. , erts_async_max_threads
  426. );
  427. }
  428. typedef struct {
  429. /* {Entity,Node} = {monitor.Name,monitor.Pid} for external by name
  430. * {Entity,Node} = {monitor.Pid,NIL} for external/external by pid
  431. * {Entity,Node} = {monitor.Name,erlang:node()} for internal by name
  432. * {Entity,Node} = {monitor.resource,MON_NIF_TARGET}*/
  433. union {
  434. Eterm term;
  435. ErtsResource* resource;
  436. }entity;
  437. int named;
  438. Uint16 type;
  439. Eterm node;
  440. /* pid is actual target being monitored, no matter pid/port or name */
  441. Eterm pid;
  442. } MonitorInfo;
  443. typedef struct {
  444. MonitorInfo *mi;
  445. Uint mi_i;
  446. Uint mi_max;
  447. int sz;
  448. } MonitorInfoCollection;
  449. #define INIT_MONITOR_INFOS(MIC) do { \
  450. (MIC).mi = NULL; \
  451. (MIC).mi_i = (MIC).mi_max = 0; \
  452. (MIC).sz = 0; \
  453. } while(0)
  454. #define MI_INC 50
  455. #define EXTEND_MONITOR_INFOS(MICP) \
  456. do { \
  457. if ((MICP)->mi_i >= (MICP)->mi_max) { \
  458. (MICP)->mi = ((MICP)->mi ? erts_realloc(ERTS_ALC_T_TMP, \
  459. (MICP)->mi, \
  460. ((MICP)->mi_max+MI_INC) \
  461. * sizeof(MonitorInfo)) \
  462. : erts_alloc(ERTS_ALC_T_TMP, \
  463. MI_INC*sizeof(MonitorInfo))); \
  464. (MICP)->mi_max += MI_INC; \
  465. } \
  466. } while (0)
  467. #define DESTROY_MONITOR_INFOS(MIC) \
  468. do { \
  469. if ((MIC).mi != NULL) { \
  470. erts_free(ERTS_ALC_T_TMP, (void *) (MIC).mi); \
  471. } \
  472. } while (0)
  473. static int collect_one_link(ErtsLink *lnk, void *vmicp, Sint reds)
  474. {
  475. MonitorInfoCollection *micp = vmicp;
  476. EXTEND_MONITOR_INFOS(micp);
  477. micp->mi[micp->mi_i].entity.term = lnk->other.item;
  478. micp->sz += 2 + NC_HEAP_SIZE(lnk->other.item);
  479. micp->mi_i++;
  480. return 1;
  481. }
  482. static int collect_one_origin_monitor(ErtsMonitor *mon, void *vmicp, Sint reds)
  483. {
  484. if (erts_monitor_is_origin(mon)) {
  485. MonitorInfoCollection *micp = vmicp;
  486. EXTEND_MONITOR_INFOS(micp);
  487. micp->mi[micp->mi_i].type = mon->type;
  488. switch (mon->type) {
  489. case ERTS_MON_TYPE_PROC:
  490. case ERTS_MON_TYPE_PORT:
  491. case ERTS_MON_TYPE_DIST_PROC:
  492. case ERTS_MON_TYPE_TIME_OFFSET:
  493. if (!(mon->flags & ERTS_ML_FLG_NAME)) {
  494. micp->mi[micp->mi_i].named = 0;
  495. micp->mi[micp->mi_i].entity.term = mon->other.item;
  496. micp->mi[micp->mi_i].node = NIL;
  497. if (is_not_atom(mon->other.item))
  498. micp->sz += NC_HEAP_SIZE(mon->other.item);
  499. }
  500. else {
  501. ErtsMonitorDataExtended *mdep;
  502. micp->mi[micp->mi_i].named = !0;
  503. mdep = (ErtsMonitorDataExtended *) erts_monitor_to_data(mon);
  504. micp->mi[micp->mi_i].entity.term = mdep->u.name;
  505. if (mdep->dist)
  506. micp->mi[micp->mi_i].node = mdep->dist->nodename;
  507. else
  508. micp->mi[micp->mi_i].node = erts_this_dist_entry->sysname;
  509. micp->sz += 3; /* need one 2-tuple */
  510. }
  511. /* have always pid at hand, to assist with figuring out if its a port or
  512. * a process, when we monitored by name and process_info is requested.
  513. * See: erl_bif_info.c:process_info_aux section for am_monitors */
  514. micp->mi[micp->mi_i].pid = mon->other.item;
  515. micp->mi_i++;
  516. micp->sz += 2 + 3; /* For a cons cell and a 2-tuple */
  517. break;
  518. default:
  519. break;
  520. }
  521. }
  522. return 1;
  523. }
  524. static int collect_one_target_monitor(ErtsMonitor *mon, void *vmicp, Sint reds)
  525. {
  526. MonitorInfoCollection *micp = vmicp;
  527. if (erts_monitor_is_target(mon)) {
  528. EXTEND_MONITOR_INFOS(micp);
  529. micp->mi[micp->mi_i].type = mon->type;
  530. micp->mi[micp->mi_i].named = !!(mon->flags & ERTS_ML_FLG_NAME);
  531. switch (mon->type) {
  532. case ERTS_MON_TYPE_PROC:
  533. case ERTS_MON_TYPE_PORT:
  534. case ERTS_MON_TYPE_DIST_PROC:
  535. micp->mi[micp->mi_i].entity.term = mon->other.item;
  536. micp->mi[micp->mi_i].node = NIL;
  537. micp->sz += NC_HEAP_SIZE(mon->other.item);
  538. micp->sz += 2; /* cons */;
  539. micp->mi_i++;
  540. break;
  541. case ERTS_MON_TYPE_RESOURCE:
  542. micp->mi[micp->mi_i].entity.resource = mon->other.ptr;
  543. micp->mi[micp->mi_i].node = NIL;
  544. micp->sz += erts_resource_ref_size(mon->other.ptr);
  545. micp->sz += 2; /* cons */;
  546. micp->mi_i++;
  547. break;
  548. default:
  549. break;
  550. }
  551. }
  552. return 1;
  553. }
  554. typedef struct {
  555. ErtsMonitorSuspend **smi;
  556. Uint smi_i;
  557. Uint smi_max;
  558. Uint sz;
  559. } ErtsSuspendMonitorInfoCollection;
  560. #define ERTS_INIT_SUSPEND_MONITOR_INFOS(SMIC) do { \
  561. (SMIC).smi = NULL; \
  562. (SMIC).smi_i = (SMIC).smi_max = 0; \
  563. (SMIC).sz = 0; \
  564. } while(0)
  565. #define ERTS_SMI_INC 50
  566. #define ERTS_EXTEND_SUSPEND_MONITOR_INFOS(SMICP) \
  567. do { \
  568. if ((SMICP)->smi_i >= (SMICP)->smi_max) { \
  569. (SMICP)->smi = ((SMICP)->smi \
  570. ? erts_realloc(ERTS_ALC_T_TMP, \
  571. (SMICP)->smi, \
  572. ((SMICP)->smi_max \
  573. + ERTS_SMI_INC) \
  574. * sizeof(ErtsMonitorSuspend *)) \
  575. : erts_alloc(ERTS_ALC_T_TMP, \
  576. ERTS_SMI_INC \
  577. * sizeof(ErtsMonitorSuspend *))); \
  578. (SMICP)->smi_max += ERTS_SMI_INC; \
  579. } \
  580. } while (0)
  581. #define ERTS_DESTROY_SUSPEND_MONITOR_INFOS(SMIC) \
  582. do { \
  583. if ((SMIC).smi != NULL) { \
  584. erts_free(ERTS_ALC_T_TMP, (void *) (SMIC).smi); \
  585. } \
  586. } while (0)
  587. static int
  588. collect_one_suspend_monitor(ErtsMonitor *mon, void *vsmicp, Sint reds)
  589. {
  590. if (mon->type == ERTS_MON_TYPE_SUSPEND) {
  591. Sint count;
  592. erts_aint_t mstate;
  593. ErtsMonitorSuspend *msp;
  594. ErtsSuspendMonitorInfoCollection *smicp;
  595. msp = (ErtsMonitorSuspend *) erts_monitor_to_data(mon);
  596. smicp = vsmicp;
  597. ERTS_EXTEND_SUSPEND_MONITOR_INFOS(smicp);
  598. smicp->smi[smicp->smi_i] = msp;
  599. smicp->sz += 2 /* cons */ + 4 /* 3-tuple */;
  600. mstate = erts_atomic_read_nob(&msp->state);
  601. count = (Sint) (mstate & ERTS_MSUSPEND_STATE_COUNTER_MASK);
  602. if (!IS_SSMALL(count))
  603. smicp->sz += BIG_UINT_HEAP_SIZE;
  604. smicp->smi_i++;
  605. }
  606. return 1;
  607. }
  608. /*
  609. * process_info/[1,2]
  610. */
  611. /*
  612. * All valid process_info arguments.
  613. */
  614. #define ERTS_PI_IX_REGISTERED_NAME 0
  615. #define ERTS_PI_IX_CURRENT_FUNCTION 1
  616. #define ERTS_PI_IX_INITIAL_CALL 2
  617. #define ERTS_PI_IX_STATUS 3
  618. #define ERTS_PI_IX_MESSAGES 4
  619. #define ERTS_PI_IX_MESSAGE_QUEUE_LEN 5
  620. #define ERTS_PI_IX_LINKS 6
  621. #define ERTS_PI_IX_MONITORS 7
  622. #define ERTS_PI_IX_MONITORED_BY 8
  623. #define ERTS_PI_IX_DICTIONARY 9
  624. #define ERTS_PI_IX_TRAP_EXIT 10
  625. #define ERTS_PI_IX_ERROR_HANDLER 11
  626. #define ERTS_PI_IX_HEAP_SIZE 12
  627. #define ERTS_PI_IX_STACK_SIZE 13
  628. #define ERTS_PI_IX_MEMORY 14
  629. #define ERTS_PI_IX_GARBAGE_COLLECTION 15
  630. #define ERTS_PI_IX_GROUP_LEADER 16
  631. #define ERTS_PI_IX_REDUCTIONS 17
  632. #define ERTS_PI_IX_PRIORITY 18
  633. #define ERTS_PI_IX_TRACE 19
  634. #define ERTS_PI_IX_BINARY 20
  635. #define ERTS_PI_IX_SEQUENTIAL_TRACE_TOKEN 21
  636. #define ERTS_PI_IX_CATCHLEVEL 22
  637. #define ERTS_PI_IX_BACKTRACE 23
  638. #define ERTS_PI_IX_LAST_CALLS 24
  639. #define ERTS_PI_IX_TOTAL_HEAP_SIZE 25
  640. #define ERTS_PI_IX_SUSPENDING 26
  641. #define ERTS_PI_IX_MIN_HEAP_SIZE 27
  642. #define ERTS_PI_IX_MIN_BIN_VHEAP_SIZE 28
  643. #define ERTS_PI_IX_MAX_HEAP_SIZE 29
  644. #define ERTS_PI_IX_CURRENT_LOCATION 30
  645. #define ERTS_PI_IX_CURRENT_STACKTRACE 31
  646. #define ERTS_PI_IX_MESSAGE_QUEUE_DATA 32
  647. #define ERTS_PI_IX_GARBAGE_COLLECTION_INFO 33
  648. #define ERTS_PI_IX_MAGIC_REF 34
  649. #define ERTS_PI_IX_FULLSWEEP_AFTER 35
  650. #define ERTS_PI_FLAG_SINGELTON (1 << 0)
  651. #define ERTS_PI_FLAG_ALWAYS_WRAP (1 << 1)
  652. #define ERTS_PI_FLAG_WANT_MSGS (1 << 2)
  653. #define ERTS_PI_FLAG_NEED_MSGQ_LEN (1 << 3)
  654. #define ERTS_PI_FLAG_FORCE_SIG_SEND (1 << 4)
  655. #define ERTS_PI_FLAG_REQUEST_FOR_OTHER (1 << 5)
  656. #define ERTS_PI_UNRESERVE(RS, SZ) \
  657. (ASSERT((RS) >= (SZ)), (RS) -= (SZ))
  658. typedef struct {
  659. Eterm name;
  660. Uint reserve_size;
  661. int flags;
  662. ErtsProcLocks locks;
  663. } ErtsProcessInfoArgs;
  664. static ErtsProcessInfoArgs pi_args[] = {
  665. {am_registered_name, 0, 0, ERTS_PROC_LOCK_MAIN},
  666. {am_current_function, 4, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  667. {am_initial_call, 4, 0, ERTS_PROC_LOCK_MAIN},
  668. {am_status, 0, 0, 0},
  669. {am_messages, 0, ERTS_PI_FLAG_WANT_MSGS|ERTS_PI_FLAG_NEED_MSGQ_LEN|ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  670. {am_message_queue_len, 0, ERTS_PI_FLAG_NEED_MSGQ_LEN, ERTS_PROC_LOCK_MAIN},
  671. {am_links, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  672. {am_monitors, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  673. {am_monitored_by, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  674. {am_dictionary, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  675. {am_trap_exit, 0, 0, ERTS_PROC_LOCK_MAIN},
  676. {am_error_handler, 0, 0, ERTS_PROC_LOCK_MAIN},
  677. {am_heap_size, 0, 0, ERTS_PROC_LOCK_MAIN},
  678. {am_stack_size, 0, 0, ERTS_PROC_LOCK_MAIN},
  679. {am_memory, 0, ERTS_PI_FLAG_NEED_MSGQ_LEN|ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  680. {am_garbage_collection, 3+2 + 3+2 + 3+2 + 3+2 + 3+2 + ERTS_MAX_HEAP_SIZE_MAP_SZ, 0, ERTS_PROC_LOCK_MAIN},
  681. {am_group_leader, 0, 0, ERTS_PROC_LOCK_MAIN},
  682. {am_reductions, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  683. {am_priority, 0, 0, 0},
  684. {am_trace, 0, 0, ERTS_PROC_LOCK_MAIN},
  685. {am_binary, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  686. {am_sequential_trace_token, 0, 0, ERTS_PROC_LOCK_MAIN},
  687. {am_catchlevel, 0, 0, ERTS_PROC_LOCK_MAIN},
  688. {am_backtrace, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  689. {am_last_calls, 0, 0, ERTS_PROC_LOCK_MAIN},
  690. {am_total_heap_size, 0, ERTS_PI_FLAG_NEED_MSGQ_LEN|ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  691. {am_suspending, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, 0},
  692. {am_min_heap_size, 0, 0, ERTS_PROC_LOCK_MAIN},
  693. {am_min_bin_vheap_size, 0, 0, ERTS_PROC_LOCK_MAIN},
  694. {am_max_heap_size, 0, 0, ERTS_PROC_LOCK_MAIN},
  695. {am_current_location, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  696. {am_current_stacktrace, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  697. {am_message_queue_data, 0, 0, ERTS_PROC_LOCK_MAIN},
  698. {am_garbage_collection_info, ERTS_PROCESS_GC_INFO_MAX_SIZE, 0, ERTS_PROC_LOCK_MAIN},
  699. {am_magic_ref, 0, ERTS_PI_FLAG_FORCE_SIG_SEND, ERTS_PROC_LOCK_MAIN},
  700. {am_fullsweep_after, 0, 0, ERTS_PROC_LOCK_MAIN}
  701. };
  702. #define ERTS_PI_ARGS ((int) (sizeof(pi_args)/sizeof(pi_args[0])))
  703. #ifdef DEBUG
  704. # define ERTS_PI_DEF_ARR_SZ 2
  705. #else
  706. # define ERTS_PI_DEF_ARR_SZ ERTS_PI_ARGS
  707. #endif
  708. static ERTS_INLINE Eterm
  709. pi_ix2arg(int ix)
  710. {
  711. if (ix < 0 || ERTS_PI_ARGS <= ix)
  712. return am_undefined;
  713. return pi_args[ix].name;
  714. }
  715. static ERTS_INLINE int
  716. pi_ix2flags(int ix)
  717. {
  718. if (ix < 0 || ERTS_PI_ARGS <= ix)
  719. return 0;
  720. return pi_args[ix].flags;
  721. }
  722. static ERTS_INLINE Uint
  723. pi_ix2rsz(int ix)
  724. {
  725. if (ix < 0 || ERTS_PI_ARGS <= ix)
  726. return 0;
  727. return pi_args[ix].reserve_size;
  728. }
  729. static ERTS_INLINE ErtsProcLocks
  730. pi_ix2locks(int ix)
  731. {
  732. if (ix < 0 || ERTS_PI_ARGS <= ix)
  733. return 0;
  734. return pi_args[ix].locks;
  735. }
  736. static ERTS_INLINE int
  737. pi_arg2ix(Eterm arg)
  738. {
  739. switch (arg) {
  740. case am_registered_name:
  741. return ERTS_PI_IX_REGISTERED_NAME;
  742. case am_current_function:
  743. return ERTS_PI_IX_CURRENT_FUNCTION;
  744. case am_initial_call:
  745. return ERTS_PI_IX_INITIAL_CALL;
  746. case am_status:
  747. return ERTS_PI_IX_STATUS;
  748. case am_messages:
  749. return ERTS_PI_IX_MESSAGES;
  750. case am_message_queue_len:
  751. return ERTS_PI_IX_MESSAGE_QUEUE_LEN;
  752. case am_links:
  753. return ERTS_PI_IX_LINKS;
  754. case am_monitors:
  755. return ERTS_PI_IX_MONITORS;
  756. case am_monitored_by:
  757. return ERTS_PI_IX_MONITORED_BY;
  758. case am_dictionary:
  759. return ERTS_PI_IX_DICTIONARY;
  760. case am_trap_exit:
  761. return ERTS_PI_IX_TRAP_EXIT;
  762. case am_error_handler:
  763. return ERTS_PI_IX_ERROR_HANDLER;
  764. case am_heap_size:
  765. return ERTS_PI_IX_HEAP_SIZE;
  766. case am_stack_size:
  767. return ERTS_PI_IX_STACK_SIZE;
  768. case am_memory:
  769. return ERTS_PI_IX_MEMORY;
  770. case am_garbage_collection:
  771. return ERTS_PI_IX_GARBAGE_COLLECTION;
  772. case am_group_leader:
  773. return ERTS_PI_IX_GROUP_LEADER;
  774. case am_reductions:
  775. return ERTS_PI_IX_REDUCTIONS;
  776. case am_priority:
  777. return ERTS_PI_IX_PRIORITY;
  778. case am_trace:
  779. return ERTS_PI_IX_TRACE;
  780. case am_binary:
  781. return ERTS_PI_IX_BINARY;
  782. case am_sequential_trace_token:
  783. return ERTS_PI_IX_SEQUENTIAL_TRACE_TOKEN;
  784. case am_catchlevel:
  785. return ERTS_PI_IX_CATCHLEVEL;
  786. case am_backtrace:
  787. return ERTS_PI_IX_BACKTRACE;
  788. case am_last_calls:
  789. return ERTS_PI_IX_LAST_CALLS;
  790. case am_total_heap_size:
  791. return ERTS_PI_IX_TOTAL_HEAP_SIZE;
  792. case am_suspending:
  793. return ERTS_PI_IX_SUSPENDING;
  794. case am_min_heap_size:
  795. return ERTS_PI_IX_MIN_HEAP_SIZE;
  796. case am_min_bin_vheap_size:
  797. return ERTS_PI_IX_MIN_BIN_VHEAP_SIZE;
  798. case am_max_heap_size:
  799. return ERTS_PI_IX_MAX_HEAP_SIZE;
  800. case am_current_location:
  801. return ERTS_PI_IX_CURRENT_LOCATION;
  802. case am_current_stacktrace:
  803. return ERTS_PI_IX_CURRENT_STACKTRACE;
  804. case am_message_queue_data:
  805. return ERTS_PI_IX_MESSAGE_QUEUE_DATA;
  806. case am_garbage_collection_info:
  807. return ERTS_PI_IX_GARBAGE_COLLECTION_INFO;
  808. case am_magic_ref:
  809. return ERTS_PI_IX_MAGIC_REF;
  810. case am_fullsweep_after:
  811. return ERTS_PI_IX_FULLSWEEP_AFTER;
  812. default:
  813. return -1;
  814. }
  815. }
  816. static Eterm pi_1_keys[] = {
  817. am_registered_name,
  818. am_current_function,
  819. am_initial_call,
  820. am_status,
  821. am_message_queue_len,
  822. am_links,
  823. am_dictionary,
  824. am_trap_exit,
  825. am_error_handler,
  826. am_priority,
  827. am_group_leader,
  828. am_total_heap_size,
  829. am_heap_size,
  830. am_stack_size,
  831. am_reductions,
  832. am_garbage_collection,
  833. am_suspending
  834. };
  835. #define ERTS_PI_1_NO_OF_KEYS (sizeof(pi_1_keys)/sizeof(Eterm))
  836. static Eterm pi_1_keys_list;
  837. static Eterm pi_1_keys_list_heap[2*ERTS_PI_1_NO_OF_KEYS];
  838. static void
  839. process_info_init(void)
  840. {
  841. Eterm *hp = &pi_1_keys_list_heap[0];
  842. int i;
  843. pi_1_keys_list = NIL;
  844. for (i = ERTS_PI_1_NO_OF_KEYS-1; i >= 0; i--) {
  845. pi_1_keys_list = CONS(hp, pi_1_keys[i], pi_1_keys_list);
  846. hp += 2;
  847. }
  848. #ifdef DEBUG
  849. { /* Make sure the process_info argument mappings are consistent */
  850. int ix;
  851. for (ix = 0; ix < ERTS_PI_ARGS; ix++) {
  852. ASSERT(pi_arg2ix(pi_ix2arg(ix)) == ix);
  853. }
  854. }
  855. #endif
  856. }
  857. static BIF_RETTYPE
  858. process_info_aux(Process *c_p,
  859. ErtsHeapFactory *hfact,
  860. Process *rp,
  861. ErtsProcLocks rp_locks,
  862. int item_ix,
  863. int flags,
  864. Uint *reserve_sizep,
  865. Uint *reds);
  866. Eterm
  867. erts_process_info(Process *c_p,
  868. ErtsHeapFactory *hfact,
  869. Process *rp,
  870. ErtsProcLocks rp_locks,
  871. int *item_ix,
  872. int item_ix_len,
  873. int flags,
  874. Uint reserve_size,
  875. Uint *reds)
  876. {
  877. Eterm res;
  878. Eterm part_res[ERTS_PI_ARGS];
  879. int item_ix_ix, ix;
  880. if (ERTS_PI_FLAG_SINGELTON & flags) {
  881. ASSERT(item_ix_len == 1);
  882. res = process_info_aux(c_p, hfact, rp, rp_locks, item_ix[0],
  883. flags, &reserve_size, reds);
  884. return res;
  885. }
  886. for (ix = 0; ix < ERTS_PI_ARGS; ix++)
  887. part_res[ix] = THE_NON_VALUE;
  888. /*
  889. * We always handle 'messages' first if it should be part
  890. * of the result. This since if both 'messages' and
  891. * 'message_queue_len' are wanted, 'messages' may
  892. * change the result of 'message_queue_len' (in case
  893. * the queue contain bad distribution messages).
  894. */
  895. if (flags & ERTS_PI_FLAG_WANT_MSGS) {
  896. ix = pi_arg2ix(am_messages);
  897. ASSERT(part_res[ix] == THE_NON_VALUE);
  898. res = process_info_aux(c_p, hfact, rp, rp_locks, ix,
  899. flags, &reserve_size, reds);
  900. ASSERT(res != am_undefined);
  901. ASSERT(res != THE_NON_VALUE);
  902. part_res[ix] = res;
  903. }
  904. for (item_ix_ix = item_ix_len - 1; item_ix_ix >= 0; item_ix_ix--) {
  905. ix = item_ix[item_ix_ix];
  906. if (part_res[ix] == THE_NON_VALUE) {
  907. res = process_info_aux(c_p, hfact, rp, rp_locks, ix,
  908. flags, &reserve_size, reds);
  909. ASSERT(res != am_undefined);
  910. ASSERT(res != THE_NON_VALUE);
  911. part_res[ix] = res;
  912. }
  913. }
  914. res = NIL;
  915. for (item_ix_ix = item_ix_len - 1; item_ix_ix >= 0; item_ix_ix--) {
  916. ix = item_ix[item_ix_ix];
  917. ASSERT(part_res[ix] != THE_NON_VALUE);
  918. /*
  919. * If we should ignore the value of registered_name,
  920. * its value is nil. For more info, see comment in the
  921. * beginning of process_info_aux().
  922. */
  923. if (is_nil(part_res[ix])) {
  924. ASSERT(!(flags & ERTS_PI_FLAG_ALWAYS_WRAP));
  925. ASSERT(pi_ix2arg(ix) == am_registered_name);
  926. }
  927. else {
  928. Eterm *hp;
  929. ERTS_PI_UNRESERVE(reserve_size, 2);
  930. hp = erts_produce_heap(hfact, 2, reserve_size);
  931. res = CONS(hp, part_res[ix], res);
  932. }
  933. }
  934. return res;
  935. }
  936. static void
  937. pi_setup_grow(int **arr, int *def_arr, Uint *sz, int ix);
  938. static BIF_RETTYPE
  939. process_info_bif(Process *c_p, Eterm pid, Eterm opt, int always_wrap, int pi2)
  940. {
  941. ErtsHeapFactory hfact;
  942. int def_arr[ERTS_PI_DEF_ARR_SZ];
  943. int *item_ix = &def_arr[0];
  944. Process *rp = NULL;
  945. erts_aint32_t state;
  946. BIF_RETTYPE ret;
  947. Uint reds = 0;
  948. ErtsProcLocks locks = 0;
  949. int flags;
  950. Uint reserve_size;
  951. int len;
  952. Eterm res;
  953. ERTS_CT_ASSERT(ERTS_PI_DEF_ARR_SZ > 0);
  954. if (c_p->common.id == pid) {
  955. int local_only = c_p->flags & F_LOCAL_SIGS_ONLY;
  956. int sres, sreds, reds_left;
  957. reds_left = ERTS_BIF_REDS_LEFT(c_p);
  958. sreds = reds_left;
  959. if (!local_only) {
  960. erts_proc_lock(c_p, ERTS_PROC_LOCK_MSGQ);
  961. erts_proc_sig_fetch(c_p);
  962. erts_proc_unlock(c_p, ERTS_PROC_LOCK_MSGQ);
  963. }
  964. sres = erts_proc_sig_handle_incoming(c_p, &state, &sreds, sreds, !0);
  965. BUMP_REDS(c_p, (int) sreds);
  966. reds_left -= sreds;
  967. if (state & ERTS_PSFLG_EXITING) {
  968. c_p->flags &= ~F_LOCAL_SIGS_ONLY;
  969. goto exited;
  970. }
  971. if (!sres | (reds_left <= 0)) {
  972. /*
  973. * More signals to handle or out of reds; need
  974. * to yield and continue. Prevent fetching of
  975. * more signals by setting local-sigs-only flag.
  976. */
  977. c_p->flags |= F_LOCAL_SIGS_ONLY;
  978. goto yield;
  979. }
  980. c_p->flags &= ~F_LOCAL_SIGS_ONLY;
  981. }
  982. if (is_atom(opt)) {
  983. int ix = pi_arg2ix(opt);
  984. item_ix[0] = ix;
  985. len = 1;
  986. locks = pi_ix2locks(ix);
  987. reserve_size = 3 + pi_ix2rsz(ix);
  988. flags = ERTS_PI_FLAG_SINGELTON;
  989. flags |= pi_ix2flags(ix);
  990. if (ix < 0)
  991. goto badarg;
  992. }
  993. else {
  994. Eterm list = opt;
  995. Uint size = ERTS_PI_DEF_ARR_SZ;
  996. len = 0;
  997. reserve_size = 0;
  998. locks = 0;
  999. flags = 0;
  1000. while (is_list(list)) {
  1001. Eterm *consp = list_val(list);
  1002. Eterm arg = CAR(consp);
  1003. int ix = pi_arg2ix(arg);
  1004. if (ix < 0)
  1005. goto badarg;
  1006. if (len >= size)
  1007. pi_setup_grow(&item_ix, def_arr, &size, len);
  1008. item_ix[len++] = ix;
  1009. locks |= pi_ix2locks(ix);
  1010. flags |= pi_ix2flags(ix);
  1011. reserve_size += pi_ix2rsz(ix);
  1012. reserve_size += 3; /* 2-tuple */
  1013. reserve_size += 2; /* cons */
  1014. list = CDR(consp);
  1015. }
  1016. if (is_not_nil(list))
  1017. goto badarg;
  1018. }
  1019. if (is_not_internal_pid(pid)) {
  1020. if (is_external_pid(pid)
  1021. && external_pid_dist_entry(pid) == erts_this_dist_entry)
  1022. goto undefined;
  1023. goto badarg;
  1024. }
  1025. if (always_wrap)
  1026. flags |= ERTS_PI_FLAG_ALWAYS_WRAP;
  1027. if (c_p->common.id == pid) {
  1028. rp = c_p;
  1029. if (locks & ~ERTS_PROC_LOCK_MAIN)
  1030. erts_proc_lock(c_p, locks & ~ERTS_PROC_LOCK_MAIN);
  1031. locks |= ERTS_PROC_LOCK_MAIN;
  1032. }
  1033. else {
  1034. if (flags & ERTS_PI_FLAG_FORCE_SIG_SEND)
  1035. goto send_signal;
  1036. state = ERTS_PSFLG_RUNNING; /* fail state... */
  1037. rp = erts_try_lock_sig_free_proc(pid, locks, &state);
  1038. if (!rp)
  1039. goto undefined;
  1040. if (rp == ERTS_PROC_LOCK_BUSY) {
  1041. rp = NULL;
  1042. goto send_signal;
  1043. }
  1044. if (state & ERTS_PSFLG_EXITING) {
  1045. if (locks)
  1046. erts_proc_unlock(rp, locks);
  1047. locks = 0;
  1048. /* wait for it to terminate properly... */
  1049. goto send_signal;
  1050. }
  1051. if (flags & ERTS_PI_FLAG_NEED_MSGQ_LEN) {
  1052. ASSERT(locks & ERTS_PROC_LOCK_MAIN);
  1053. erts_proc_lock(rp, ERTS_PROC_LOCK_MSGQ);
  1054. erts_proc_sig_fetch(rp);
  1055. if (c_p->sig_qs.cont) {
  1056. erts_proc_unlock(rp, locks|ERTS_PROC_LOCK_MSGQ);
  1057. locks = 0;
  1058. goto send_signal;
  1059. }
  1060. erts_proc_unlock(rp, ERTS_PROC_LOCK_MSGQ);
  1061. }
  1062. }
  1063. erts_factory_proc_init(&hfact, c_p);
  1064. res = erts_process_info(c_p, &hfact, rp, locks, item_ix, len,
  1065. flags, reserve_size, &reds);
  1066. erts_factory_close(&hfact);
  1067. if (reds > INT_MAX/2)
  1068. reds = INT_MAX/2;
  1069. BUMP_REDS(c_p, (int) reds);
  1070. state = erts_atomic32_read_acqb(&rp->state);
  1071. if (state & (ERTS_PSFLG_EXITING|ERTS_PSFLG_FREE)) {
  1072. if (state & ERTS_PSFLG_FREE) {
  1073. ASSERT(!locks);
  1074. goto undefined;
  1075. }
  1076. if (locks)
  1077. erts_proc_unlock(rp, locks);
  1078. locks = 0;
  1079. /* wait for it to terminate properly... */
  1080. goto send_signal;
  1081. }
  1082. ERTS_BIF_PREP_RET(ret, res);
  1083. done:
  1084. if (c_p == rp)
  1085. locks &= ~ERTS_PROC_LOCK_MAIN;
  1086. if (locks && rp)
  1087. erts_proc_unlock(rp, locks);
  1088. if (item_ix != def_arr)
  1089. erts_free(ERTS_ALC_T_TMP, item_ix);
  1090. return ret;
  1091. badarg:
  1092. ERTS_BIF_PREP_ERROR(ret, c_p, BADARG);
  1093. goto done;
  1094. undefined:
  1095. ERTS_BIF_PREP_RET(ret, am_undefined);
  1096. goto done;
  1097. exited:
  1098. ERTS_BIF_PREP_EXITED(ret, c_p);
  1099. goto done;
  1100. yield:
  1101. if (pi2)
  1102. ERTS_BIF_PREP_YIELD2(ret, bif_export[BIF_process_info_2], c_p, pid, opt);
  1103. else
  1104. ERTS_BIF_PREP_YIELD1(ret, bif_export[BIF_process_info_1], c_p, pid);
  1105. goto done;
  1106. send_signal: {
  1107. Eterm ref = erts_make_ref(c_p);
  1108. int enqueued, need_msgq_len;
  1109. flags |= ERTS_PI_FLAG_REQUEST_FOR_OTHER;
  1110. need_msgq_len = (flags & ERTS_PI_FLAG_NEED_MSGQ_LEN);
  1111. /*
  1112. * Set receive mark so we wont have to scan the whole
  1113. * message queue for the result. Note caller unconditionally
  1114. * has to enter a receive only matching messages containing
  1115. * 'ref', or restore save pointer.
  1116. */
  1117. ERTS_RECV_MARK_SAVE(c_p);
  1118. ERTS_RECV_MARK_SET(c_p);
  1119. enqueued = erts_proc_sig_send_process_info_request(c_p, pid, item_ix,
  1120. len, need_msgq_len,
  1121. flags, reserve_size,
  1122. ref);
  1123. if (!enqueued) {
  1124. /* Restore save pointer... */
  1125. JOIN_MESSAGE(c_p);
  1126. goto undefined;
  1127. }
  1128. ERTS_BIF_PREP_TRAP1(ret, erts_await_result, c_p, ref);
  1129. goto done;
  1130. }
  1131. }
  1132. static void
  1133. pi_setup_grow(int **arr, int *def_arr, Uint *sz, int ix)
  1134. {
  1135. *sz = (ix+1) + ERTS_PI_DEF_ARR_SZ;
  1136. if (*arr != def_arr)
  1137. *arr = erts_realloc(ERTS_ALC_T_TMP, *arr, (*sz)*sizeof(int));
  1138. else {
  1139. int *new_arr = erts_alloc(ERTS_ALC_T_TMP, (*sz)*sizeof(int));
  1140. sys_memcpy((void *) new_arr, (void *) def_arr,
  1141. sizeof(int)*ERTS_PI_DEF_ARR_SZ);
  1142. *arr = new_arr;
  1143. }
  1144. }
  1145. BIF_RETTYPE process_info_2(BIF_ALIST_2)
  1146. {
  1147. return process_info_bif(BIF_P, BIF_ARG_1, BIF_ARG_2, !is_atom(BIF_ARG_2), !0);
  1148. }
  1149. BIF_RETTYPE process_info_1(BIF_ALIST_1)
  1150. {
  1151. return process_info_bif(BIF_P, BIF_ARG_1, pi_1_keys_list, 0, 0);
  1152. }
  1153. Eterm
  1154. process_info_aux(Process *c_p,
  1155. ErtsHeapFactory *hfact,
  1156. Process *rp,
  1157. ErtsProcLocks rp_locks,
  1158. int item_ix,
  1159. int flags,
  1160. Uint *reserve_sizep,
  1161. Uint *reds)
  1162. {
  1163. Eterm *hp;
  1164. Eterm res = NIL;
  1165. Uint reserved;
  1166. Uint reserve_size = *reserve_sizep;
  1167. #ifdef ERTS_ENABLE_LOCK_CHECK
  1168. ErtsProcLocks locks = erts_proc_lc_my_proc_locks(rp);
  1169. switch (item_ix) {
  1170. case ERTS_PI_IX_STATUS:
  1171. case ERTS_PI_IX_PRIORITY:
  1172. case ERTS_PI_IX_SUSPENDING:
  1173. ERTS_LC_ASSERT((locks & ~ERTS_PROC_LOCK_MAIN) == 0);
  1174. break;
  1175. default:
  1176. ERTS_LC_ASSERT(locks == ERTS_PROC_LOCK_MAIN);
  1177. break;
  1178. }
  1179. #endif
  1180. reserved = pi_ix2rsz(item_ix);
  1181. ERTS_PI_UNRESERVE(reserve_size, reserved);
  1182. (*reds)++;
  1183. ASSERT(rp);
  1184. /*
  1185. * Q: Why this ERTS_PI_FLAG_ALWAYS_WRAP flag?
  1186. *
  1187. * A: registered_name is strange. If process has no registered name,
  1188. * process_info(Pid, registered_name) returns [], and
  1189. * the result of process_info(Pid) has no {registered_name, Name}
  1190. * tuple in the resulting list. This is inconsistent with all other
  1191. * options, but we do not dare to change it.
  1192. *
  1193. * When process_info/2 is called with a list as second argument,
  1194. * registered_name behaves as it should, i.e. a
  1195. * {registered_name, []} will appear in the resulting list.
  1196. *
  1197. * If ERTS_PI_FLAG_ALWAYS_WRAP is set, process_info_aux() always
  1198. * wrap the result in a key two tuple.
  1199. */
  1200. switch (item_ix) {
  1201. case ERTS_PI_IX_REGISTERED_NAME:
  1202. if (rp->common.u.alive.reg)
  1203. res = rp->common.u.alive.reg->name;
  1204. else {
  1205. if (flags & ERTS_PI_FLAG_ALWAYS_WRAP)
  1206. res = NIL;
  1207. else
  1208. return NIL;
  1209. }
  1210. break;
  1211. case ERTS_PI_IX_CURRENT_FUNCTION:
  1212. res = current_function(c_p, hfact, rp, 0,
  1213. reserve_size, flags);
  1214. break;
  1215. case ERTS_PI_IX_CURRENT_LOCATION:
  1216. res = current_function(c_p, hfact, rp, 1,
  1217. reserve_size, flags);
  1218. break;
  1219. case ERTS_PI_IX_CURRENT_STACKTRACE:
  1220. res = current_stacktrace(hfact, rp, reserve_size);
  1221. break;
  1222. case ERTS_PI_IX_INITIAL_CALL:
  1223. hp = erts_produce_heap(hfact, 4, reserve_size);
  1224. res = TUPLE3(hp,
  1225. rp->u.initial.module,
  1226. rp->u.initial.function,
  1227. make_small(rp->u.initial.arity));
  1228. hp += 4;
  1229. break;
  1230. case ERTS_PI_IX_STATUS: {
  1231. erts_aint32_t state = erts_atomic32_read_nob(&rp->state);
  1232. res = erts_process_state2status(state);
  1233. if (res == am_running && (state & ERTS_PSFLG_RUNNING_SYS)) {
  1234. ASSERT(c_p == rp);
  1235. ASSERT(flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER);
  1236. if (!(state & (ERTS_PSFLG_SYS_TASKS
  1237. | ERTS_PSFLG_ACTIVE
  1238. | ERTS_PSFLG_SIG_Q
  1239. | ERTS_PSFLG_SIG_IN_Q))) {
  1240. /*
  1241. * We are servicing a process-info request from
  1242. * another process. If that other process could
  1243. * have inspected our state itself, we would have
  1244. * been in the 'waiting' state.
  1245. */
  1246. res = am_waiting;
  1247. }
  1248. }
  1249. break;
  1250. }
  1251. case ERTS_PI_IX_MESSAGES: {
  1252. ASSERT(flags & ERTS_PI_FLAG_NEED_MSGQ_LEN);
  1253. if (rp->sig_qs.len == 0 || (ERTS_TRACE_FLAGS(rp) & F_SENSITIVE))
  1254. res = NIL;
  1255. else {
  1256. int info_on_self = !(flags & ERTS_PI_FLAG_REQUEST_FOR_OTHER);
  1257. ErtsMessageInfo *mip;
  1258. Sint i, len;
  1259. Uint heap_need;
  1260. mip = erts_alloc(ERTS_ALC_T_TMP,
  1261. rp->sig_qs.len*sizeof(ErtsMessageInfo));
  1262. /*
  1263. * Note that message queue may shrink when calling
  1264. * erts_proc_sig_prep_msgq_for_inspection() since it removes
  1265. * corrupt distribution messages.
  1266. */
  1267. heap_need = erts_proc_sig_prep_msgq_for_inspection(c_p, rp,
  1268. rp_locks,
  1269. info_on_self,
  1270. mip);
  1271. len = rp->sig_qs.len;
  1272. heap_need += len*2; /* Cons cells */
  1273. reserve_size += heap_need;
  1274. /* Build list of messages... */
  1275. for (i = len - 1, res = NIL; i >= 0; i--) {
  1276. Eterm msg = ERL_MESSAGE_TERM(mip[i].msgp);
  1277. Uint sz = mip[i].size;
  1278. ERTS_PI_UNRESERVE(reserve_size, sz+2);
  1279. hp = erts_produce_heap(hfact, sz+2, reserve_size);
  1280. if (sz != 0)
  1281. msg = copy_struct(msg, sz, &hp, hfact->off_heap);
  1282. res = CONS(hp, msg, res);
  1283. hp += 2;
  1284. }
  1285. *reds += (Uint) len / 4;
  1286. erts_free(ERTS_ALC_T_TMP, mip);
  1287. }
  1288. break;
  1289. }
  1290. case ERTS_PI_IX_MESSAGE_QUEUE_LEN: {
  1291. Sint len = rp->sig_qs.len;
  1292. ASSERT(flags & ERTS_PI_FLAG_NEED_MSGQ_LEN);
  1293. ASSERT(len >= 0);
  1294. if (len <= MAX_SMALL)
  1295. res = make_small(len);
  1296. else {
  1297. hp = erts_produce_heap(hfact, BIG_UINT_HEAP_SIZE, reserve_size);
  1298. res = uint_to_big((Uint) len, hp);
  1299. }
  1300. break;
  1301. }
  1302. case ERTS_PI_IX_LINKS: {
  1303. MonitorInfoCollection mic;
  1304. int i;
  1305. Eterm item;
  1306. INIT_MONITOR_INFOS(mic);
  1307. erts_link_tree_foreach(ERTS_P_LINKS(rp), collect_one_link, (void *) &mic);
  1308. reserve_size += mic.sz;
  1309. res = NIL;
  1310. for (i = 0; i < mic.mi_i; i++) {
  1311. Eterm item_src = mic.mi[i].entity.term;
  1312. Uint sz = NC_HEAP_SIZE(item_src) + 2;
  1313. ERTS_PI_UNRESERVE(reserve_size, sz);
  1314. hp = erts_produce_heap(hfact, sz, reserve_size);
  1315. item = STORE_NC(&hp, hfact->off_heap, item_src);
  1316. res = CONS(hp, item, res);
  1317. }
  1318. *reds += (Uint) mic.mi_i / 4;
  1319. DESTROY_MONITOR_INFOS(mic);
  1320. break;
  1321. }
  1322. case ERTS_PI_IX_MONITORS: {
  1323. MonitorInfoCollection mic;
  1324. int i;
  1325. INIT_MONITOR_INFOS(mic);
  1326. erts_monitor_tree_foreach(ERTS_P_MONITORS(rp),
  1327. collect_one_origin_monitor,
  1328. (void *) &mic);
  1329. reserve_size += mic.sz;
  1330. res = NIL;
  1331. for (i = 0; i < mic.mi_i; i++) {
  1332. if (mic.mi[i].named) {
  1333. /* Monitor by name.
  1334. * Build {process|port, {Name, Node}} and cons it.
  1335. */
  1336. Eterm t1, t2;
  1337. /* If pid is an atom, then it is a remote named monitor, which
  1338. has to be a process */
  1339. Eterm m_type = is_port(mic.mi[i].pid) ? am_port : am_process;
  1340. ASSERT(is_pid(mic.mi[i].pid)
  1341. || is_port(mic.mi[i].pid)
  1342. || is_atom(mic.mi[i].pid));
  1343. ERTS_PI_UNRESERVE(reserve_size, 3+3+2);
  1344. hp = erts_produce_heap(hfact, 3+3+2, reserve_size);
  1345. t1 = TUPLE2(hp, mic.mi[i].entity.term, mic.mi[i].node);
  1346. hp += 3;
  1347. t2 = TUPLE2(hp, m_type, t1);
  1348. hp += 3;
  1349. res = CONS(hp, t2, res);
  1350. }
  1351. else {
  1352. /* Build {process|port|time_offset, Pid|clock_service} and cons it. */
  1353. Eterm t;
  1354. Eterm pid;
  1355. Eterm m_type;
  1356. Eterm pid_src = mic.mi[i].entity.term;
  1357. Uint sz = is_atom(pid_src) ? 0 : NC_HEAP_SIZE(pid_src);
  1358. sz += 3 + 2;
  1359. ERTS_PI_UNRESERVE(reserve_size, sz);
  1360. hp = erts_produce_heap(hfact, sz, reserve_size);
  1361. pid = (is_atom(pid_src)
  1362. ? pid_src
  1363. : STORE_NC(&hp, hfact->off_heap, pid_src));
  1364. switch (mic.mi[i].type) {
  1365. case ERTS_MON_TYPE_PORT:
  1366. m_type = am_port;
  1367. break;
  1368. case ERTS_MON_TYPE_TIME_OFFSET:
  1369. m_type = am_time_offset;
  1370. break;
  1371. default:
  1372. m_type = am_process;
  1373. break;
  1374. }
  1375. ASSERT(is_pid(mic.mi[i].pid)
  1376. || is_port(mic.mi[i].pid));
  1377. t = TUPLE2(hp, m_type, pid);
  1378. hp += 3;
  1379. res = CONS(hp, t, res);
  1380. }
  1381. }
  1382. *reds += (Uint) mic.mi_i / 4;
  1383. DESTROY_MONITOR_INFOS(mic);
  1384. break;
  1385. }
  1386. case ERTS_PI_IX_MONITORED_BY: {
  1387. MonitorInfoCollection mic;
  1388. int i;
  1389. Eterm item;
  1390. INIT_MONITOR_INFOS(mic);
  1391. erts_monitor_list_foreach(ERTS_P_LT_MONITORS(rp),
  1392. collect_one_target_monitor,
  1393. (void *) &mic);
  1394. erts_monitor_tree_foreach(ERTS_P_MONITORS(rp),
  1395. collect_one_target_monitor,
  1396. (void *) &mic);
  1397. reserve_size += mic.sz;
  1398. res = NIL;
  1399. for (i = 0; i < mic.mi_i; ++i) {
  1400. Uint sz = 2;
  1401. if (mic.mi[i].type == ERTS_MON_TYPE_RESOURCE)
  1402. sz += erts_resource_ref_size(mic.mi[i].entity.resource);
  1403. else
  1404. sz += NC_HEAP_SIZE(mic.mi[i].entity.term);
  1405. ERTS_PI_UNRESERVE(reserve_size, sz);
  1406. hp = erts_produce_heap(hfact, sz, reserve_size);
  1407. if (mic.mi[i].type == ERTS_MON_TYPE_RESOURCE)
  1408. item = erts_bld_resource_ref(&hp,
  1409. hfact->off_heap,
  1410. mic.mi[i].entity.resource);
  1411. else
  1412. item = STORE_NC(&hp,
  1413. hfact->off_heap,
  1414. mic.mi[i].entity.term);
  1415. res = CONS(hp, item, res);
  1416. }
  1417. *reds += (Uint) mic.mi_i / 4;
  1418. DESTROY_MONITOR_INFOS(mic);
  1419. break;
  1420. }
  1421. case ERTS_PI_IX_SUSPENDING: {
  1422. ErtsSuspendMonitorInfoCollection smic;
  1423. int i;
  1424. ERTS_INIT_SUSPEND_MONITOR_INFOS(smic);
  1425. erts_monitor_tree_foreach(ERTS_P_MONITORS(rp),
  1426. collect_one_suspend_monitor,
  1427. (void *) &smic);
  1428. reserve_size += smic.sz;
  1429. res = NIL;
  1430. for (i = 0; i < smic.smi_i; i++) {
  1431. ErtsMonitorSuspend *msp;
  1432. erts_aint_t mstate;
  1433. Sint ci;
  1434. Eterm ct, active, pending, item;
  1435. Uint sz = 4 + 2;
  1436. msp = smic.smi[i];
  1437. mstate = erts_atomic_read_nob(&msp->state);
  1438. ci = (Sint) (mstate & ERTS_MSUSPEND_STATE_COUNTER_MASK);
  1439. if (!IS_SSMALL(ci))
  1440. sz += BIG_UINT_HEAP_SIZE;
  1441. ERTS_PI_UNRESERVE(reserve_size, sz);
  1442. hp = erts_produce_heap(hfact, sz, reserve_size);
  1443. if (IS_SSMALL(ci))
  1444. ct = make_small(ci);
  1445. else {
  1446. ct = small_to_big(ci, hp);
  1447. hp += BIG_UINT_HEAP_SIZE;
  1448. }
  1449. if (mstate & ERTS_MSUSPEND_STATE_FLG_ACTIVE) {
  1450. active = ct;
  1451. pending = make_small(0);
  1452. }
  1453. else {
  1454. active = make_small(0);
  1455. pending = ct;
  1456. }
  1457. ASSERT(is_internal_pid(msp->md.origin.other.item));
  1458. item = TUPLE3(hp, msp->md.origin.other.item, active, pending);
  1459. hp += 4;
  1460. res = CONS(hp, item, res);
  1461. }
  1462. *reds += (Uint) smic.smi_i / 4;
  1463. ERTS_DESTROY_SUSPEND_MONITOR_INFOS(smic);
  1464. break;
  1465. }
  1466. case ERTS_PI_IX_DICTIONARY:
  1467. if (!rp->dictionary || (ERTS_TRACE_FLAGS(rp) & F_SENSITIVE)) {
  1468. res = NIL;
  1469. } else {
  1470. Uint num = rp->dictionary->numElements;
  1471. res = erts_dictionary_copy(hfact, rp->dictionary, reserve_size);
  1472. *reds += (Uint) num / 4;
  1473. }
  1474. break;
  1475. case ERTS_PI_IX_TRAP_EXIT:
  1476. res = (rp->flags & F_TRAP_EXIT) ? am_true : am_false;
  1477. break;
  1478. case ERTS_PI_IX_ERROR_HANDLER:
  1479. res = erts_proc_get_error_handler(rp);
  1480. break;
  1481. case ERTS_PI_IX_HEAP_SIZE: {
  1482. Uint hsz = 0;
  1483. (void) erts_bld_uint(NULL, &hsz, HEAP_SIZE(rp));
  1484. hp = erts_produce_heap(hfact, hsz, reserve_size);
  1485. res = erts_bld_uint(&hp, NULL, HEAP_SIZE(rp));
  1486. break;
  1487. }
  1488. case ERTS_PI_IX_FULLSWEEP_AFTER: {
  1489. Uint hsz = 0;
  1490. (void) erts_bld_uint(NULL, &hsz, MAX_GEN_GCS(rp));
  1491. hp = erts_produce_heap(hfact, hsz, reserve_size);
  1492. res = erts_bld_uint(&hp, NULL, MAX_GEN_GCS(rp));
  1493. break;
  1494. }
  1495. case ERTS_PI_IX_MIN_HEAP_SIZE: {
  1496. Uint hsz = 0;
  1497. (void) erts_bld_uint(NULL, &hsz, MIN_HEAP_SIZE(rp));
  1498. hp = erts_produce_heap(hfact, hsz, reserve_size);
  1499. res = erts_bld_uint(&hp, NULL, MIN_HEAP_SIZE(rp));
  1500. break;
  1501. }
  1502. case ERTS_PI_IX_MIN_BIN_VHEAP_SIZE: {
  1503. Uint hsz = 0;
  1504. (void) erts_bld_uint(NULL, &hsz, MIN_VHEAP_SIZE(rp));
  1505. hp = erts_produce_heap(hfact, hsz, reserve_size);
  1506. res = erts_bld_uint(&hp, NULL, MIN_VHEAP_SIZE(rp));
  1507. break;
  1508. }
  1509. case ERTS_PI_IX_MAX_HEAP_SIZE: {
  1510. Uint hsz = 0;
  1511. (void) erts_max_heap_size_map(MAX_HEAP_SIZE_GET(rp),
  1512. MAX_HEAP_SIZE_FLAGS_GET(rp),
  1513. NULL, &hsz);
  1514. hp = er

Large files files are truncated, but you can click here to view the full file