PageRenderTime 49ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 2ms

/erts/emulator/beam/erl_process.c

https://github.com/Bwooce/otp
C | 8823 lines | 6988 code | 1195 blank | 640 comment | 1474 complexity | 13f9e0f35e94464e4926f975dc2a129f MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-2-Clause
  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 1996-2010. All Rights Reserved.
  5. *
  6. * The contents of this file are subject to the Erlang Public License,
  7. * Version 1.1, (the "License"); you may not use this file except in
  8. * compliance with the License. You should have received a copy of the
  9. * Erlang Public License along with this software. If not, it can be
  10. * retrieved online at http://www.erlang.org/.
  11. *
  12. * Software distributed under the License is distributed on an "AS IS"
  13. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  14. * the License for the specific language governing rights and limitations
  15. * under the License.
  16. *
  17. * %CopyrightEnd%
  18. */
  19. #define ERL_PROCESS_C__
  20. #ifdef HAVE_CONFIG_H
  21. # include "config.h"
  22. #endif
  23. #include <stddef.h> /* offsetof() */
  24. #include "sys.h"
  25. #include "erl_vm.h"
  26. #include "global.h"
  27. #include "erl_process.h"
  28. #include "erl_nmgc.h"
  29. #include "error.h"
  30. #include "bif.h"
  31. #include "erl_db.h"
  32. #include "dist.h"
  33. #include "beam_catches.h"
  34. #include "erl_instrument.h"
  35. #include "erl_threads.h"
  36. #include "erl_binary.h"
  37. #include "beam_bp.h"
  38. #include "erl_cpu_topology.h"
  39. #define ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED (2000*CONTEXT_REDS)
  40. #define ERTS_RUNQ_CALL_CHECK_BALANCE_REDS \
  41. (ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED/2)
  42. #define ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST (CONTEXT_REDS/10)
  43. #define ERTS_SCHED_SPIN_UNTIL_YIELD 100
  44. #define ERTS_SCHED_SYS_SLEEP_SPINCOUNT 10
  45. #define ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT 1000
  46. #define ERTS_SCHED_TSE_SLEEP_SPINCOUNT \
  47. (ERTS_SCHED_SYS_SLEEP_SPINCOUNT*ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT)
  48. #define ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT 0
  49. #define ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH (200*CONTEXT_REDS)
  50. #define ERTS_WAKEUP_OTHER_LIMIT_HIGH (50*CONTEXT_REDS)
  51. #define ERTS_WAKEUP_OTHER_LIMIT_MEDIUM (10*CONTEXT_REDS)
  52. #define ERTS_WAKEUP_OTHER_LIMIT_LOW (CONTEXT_REDS)
  53. #define ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW (CONTEXT_REDS/10)
  54. #define ERTS_WAKEUP_OTHER_DEC 10
  55. #define ERTS_WAKEUP_OTHER_FIXED_INC (CONTEXT_REDS/10)
  56. #if 0 || defined(DEBUG)
  57. #define ERTS_FAKE_SCHED_BIND_PRINT_SORTED_CPU_DATA
  58. #endif
  59. #if defined(DEBUG) && 0
  60. #define HARDDEBUG
  61. #else
  62. #undef HARDDEBUG
  63. #endif
  64. #ifdef HARDDEBUG
  65. #define HARDDEBUG_RUNQS
  66. #endif
  67. #ifdef HIPE
  68. #include "hipe_mode_switch.h" /* for hipe_init_process() */
  69. #include "hipe_signal.h" /* for hipe_thread_signal_init() */
  70. #endif
  71. #ifdef ERTS_ENABLE_LOCK_COUNT
  72. #include "erl_lock_count.h"
  73. #endif
  74. #define MAX_BIT (1 << PRIORITY_MAX)
  75. #define HIGH_BIT (1 << PRIORITY_HIGH)
  76. #define NORMAL_BIT (1 << PRIORITY_NORMAL)
  77. #define LOW_BIT (1 << PRIORITY_LOW)
  78. #define ERTS_MAYBE_SAVE_TERMINATING_PROCESS(P) \
  79. do { \
  80. ERTS_SMP_LC_ASSERT(erts_lc_mtx_is_locked(&proc_tab_mtx)); \
  81. if (saved_term_procs.end) \
  82. save_terminating_process((P)); \
  83. } while (0)
  84. #define ERTS_EMPTY_RUNQ(RQ) \
  85. ((RQ)->len == 0 && (RQ)->misc.start == NULL)
  86. extern BeamInstr beam_apply[];
  87. extern BeamInstr beam_exit[];
  88. extern BeamInstr beam_continue_exit[];
  89. static Sint p_last;
  90. static Sint p_next;
  91. static Sint p_serial;
  92. static Uint p_serial_mask;
  93. static Uint p_serial_shift;
  94. Uint erts_no_schedulers;
  95. Uint erts_max_processes = ERTS_DEFAULT_MAX_PROCESSES;
  96. Uint erts_process_tab_index_mask;
  97. static int wakeup_other_limit;
  98. int erts_sched_thread_suggested_stack_size = -1;
  99. #ifdef ERTS_ENABLE_LOCK_CHECK
  100. ErtsLcPSDLocks erts_psd_required_locks[ERTS_PSD_SIZE];
  101. #endif
  102. #ifdef ERTS_SMP
  103. int erts_disable_proc_not_running_opt;
  104. #define ERTS_SCHDLR_SSPND_CHNG_WAITER (((erts_aint32_t) 1) << 0)
  105. #define ERTS_SCHDLR_SSPND_CHNG_MSB (((erts_aint32_t) 1) << 1)
  106. #define ERTS_SCHDLR_SSPND_CHNG_ONLN (((erts_aint32_t) 1) << 2)
  107. #ifndef DEBUG
  108. #define ERTS_SCHDLR_SSPND_CHNG_SET(VAL, OLD_VAL) \
  109. erts_smp_atomic32_set(&schdlr_sspnd.changing, (VAL))
  110. #else
  111. #define ERTS_SCHDLR_SSPND_CHNG_SET(VAL, OLD_VAL) \
  112. do { \
  113. erts_aint32_t old_val__; \
  114. old_val__ = erts_smp_atomic32_xchg(&schdlr_sspnd.changing, \
  115. (VAL)); \
  116. ASSERT(old_val__ == (OLD_VAL)); \
  117. } while (0)
  118. #endif
  119. static struct {
  120. erts_smp_mtx_t mtx;
  121. erts_smp_cnd_t cnd;
  122. int online;
  123. int curr_online;
  124. int wait_curr_online;
  125. erts_smp_atomic32_t changing;
  126. erts_smp_atomic32_t active;
  127. struct {
  128. erts_smp_atomic32_t ongoing;
  129. long wait_active;
  130. ErtsProcList *procs;
  131. } msb; /* Multi Scheduling Block */
  132. } schdlr_sspnd;
  133. static struct {
  134. erts_smp_mtx_t update_mtx;
  135. erts_smp_atomic32_t active_runqs;
  136. int last_active_runqs;
  137. erts_smp_atomic32_t used_runqs;
  138. int forced_check_balance;
  139. erts_smp_atomic32_t checking_balance;
  140. int halftime;
  141. int full_reds_history_index;
  142. struct {
  143. int active_runqs;
  144. int reds;
  145. int max_len;
  146. } prev_rise;
  147. Uint n;
  148. } balance_info;
  149. #define ERTS_BLNCE_SAVE_RISE(ACTIVE, MAX_LEN, REDS) \
  150. do { \
  151. balance_info.prev_rise.active_runqs = (ACTIVE); \
  152. balance_info.prev_rise.max_len = (MAX_LEN); \
  153. balance_info.prev_rise.reds = (REDS); \
  154. } while (0)
  155. #endif
  156. erts_sched_stat_t erts_sched_stat;
  157. ErtsRunQueue *erts_common_run_queue;
  158. #ifdef USE_THREADS
  159. static erts_tsd_key_t sched_data_key;
  160. #endif
  161. static erts_smp_mtx_t proc_tab_mtx;
  162. static erts_smp_atomic32_t function_calls;
  163. #ifdef ERTS_SMP
  164. static erts_smp_atomic32_t doing_sys_schedule;
  165. static erts_smp_atomic32_t no_empty_run_queues;
  166. #else /* !ERTS_SMP */
  167. ErtsSchedulerData *erts_scheduler_data;
  168. #endif
  169. ErtsAlignedRunQueue *erts_aligned_run_queues;
  170. Uint erts_no_run_queues;
  171. ErtsAlignedSchedulerData *erts_aligned_scheduler_data;
  172. #ifdef ERTS_SMP
  173. typedef union {
  174. ErtsSchedulerSleepInfo ssi;
  175. char align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsSchedulerSleepInfo))];
  176. } ErtsAlignedSchedulerSleepInfo;
  177. static ErtsAlignedSchedulerSleepInfo *aligned_sched_sleep_info;
  178. #endif
  179. #ifndef BM_COUNTERS
  180. static int processes_busy;
  181. #endif
  182. Process** process_tab;
  183. static Uint last_reductions;
  184. static Uint last_exact_reductions;
  185. Uint erts_default_process_flags;
  186. Eterm erts_system_monitor;
  187. Eterm erts_system_monitor_msg_queue_len;
  188. Eterm erts_system_monitor_long_gc;
  189. Eterm erts_system_monitor_large_heap;
  190. struct erts_system_monitor_flags_t erts_system_monitor_flags;
  191. /* system performance monitor */
  192. Eterm erts_system_profile;
  193. struct erts_system_profile_flags_t erts_system_profile_flags;
  194. #ifdef HYBRID
  195. Uint erts_num_active_procs;
  196. Process** erts_active_procs;
  197. #endif
  198. #if ERTS_MAX_PROCESSES > 0x7fffffff
  199. #error "Need to store process_count in another type"
  200. #endif
  201. static erts_smp_atomic32_t process_count;
  202. typedef struct ErtsTermProcElement_ ErtsTermProcElement;
  203. struct ErtsTermProcElement_ {
  204. ErtsTermProcElement *next;
  205. ErtsTermProcElement *prev;
  206. int ix;
  207. union {
  208. struct {
  209. Eterm pid;
  210. SysTimeval spawned;
  211. SysTimeval exited;
  212. } process;
  213. struct {
  214. SysTimeval time;
  215. } bif_invocation;
  216. } u;
  217. };
  218. static struct {
  219. ErtsTermProcElement *start;
  220. ErtsTermProcElement *end;
  221. } saved_term_procs;
  222. ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(misc_op_list,
  223. ErtsMiscOpList,
  224. 10,
  225. ERTS_ALC_T_MISC_OP_LIST)
  226. ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(proclist,
  227. ErtsProcList,
  228. 200,
  229. ERTS_ALC_T_PROC_LIST)
  230. #define ERTS_SCHED_SLEEP_INFO_IX(IX) \
  231. (ASSERT_EXPR(0 <= (IX) && (IX) < erts_no_schedulers), \
  232. &aligned_sched_sleep_info[(IX)].ssi)
  233. #define ERTS_FOREACH_RUNQ(RQVAR, DO) \
  234. do { \
  235. ErtsRunQueue *RQVAR; \
  236. int ix__; \
  237. for (ix__ = 0; ix__ < erts_no_run_queues; ix__++) { \
  238. RQVAR = ERTS_RUNQ_IX(ix__); \
  239. erts_smp_runq_lock(RQVAR); \
  240. { DO; } \
  241. erts_smp_runq_unlock(RQVAR); \
  242. } \
  243. } while (0)
  244. #define ERTS_FOREACH_OP_RUNQ(RQVAR, DO) \
  245. do { \
  246. ErtsRunQueue *RQVAR; \
  247. int ix__; \
  248. ERTS_SMP_LC_ASSERT(erts_smp_lc_mtx_is_locked(&schdlr_sspnd.mtx)); \
  249. for (ix__ = 0; ix__ < schdlr_sspnd.online; ix__++) { \
  250. RQVAR = ERTS_RUNQ_IX(ix__); \
  251. erts_smp_runq_lock(RQVAR); \
  252. { DO; } \
  253. erts_smp_runq_unlock(RQVAR); \
  254. } \
  255. } while (0)
  256. #define ERTS_ATOMIC_FOREACH_RUNQ_X(RQVAR, DO, DOX) \
  257. do { \
  258. ErtsRunQueue *RQVAR; \
  259. int ix__; \
  260. for (ix__ = 0; ix__ < erts_no_run_queues; ix__++) { \
  261. RQVAR = ERTS_RUNQ_IX(ix__); \
  262. erts_smp_runq_lock(RQVAR); \
  263. { DO; } \
  264. } \
  265. { DOX; } \
  266. for (ix__ = 0; ix__ < erts_no_run_queues; ix__++) \
  267. erts_smp_runq_unlock(ERTS_RUNQ_IX(ix__)); \
  268. } while (0)
  269. #define ERTS_ATOMIC_FOREACH_RUNQ(RQVAR, DO) \
  270. ERTS_ATOMIC_FOREACH_RUNQ_X(RQVAR, DO, )
  271. /*
  272. * Local functions.
  273. */
  274. static void init_processes_bif(void);
  275. static void save_terminating_process(Process *p);
  276. static void exec_misc_ops(ErtsRunQueue *);
  277. static void print_function_from_pc(int to, void *to_arg, BeamInstr* x);
  278. static int stack_element_dump(int to, void *to_arg, Process* p, Eterm* sp,
  279. int yreg);
  280. #ifdef ERTS_SMP
  281. static void handle_pending_exiters(ErtsProcList *);
  282. #endif
  283. #if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
  284. int
  285. erts_smp_lc_runq_is_locked(ErtsRunQueue *runq)
  286. {
  287. return erts_smp_lc_mtx_is_locked(&runq->mtx);
  288. }
  289. #endif
  290. void
  291. erts_pre_init_process(void)
  292. {
  293. #ifdef USE_THREADS
  294. erts_tsd_key_create(&sched_data_key);
  295. #endif
  296. #ifdef ERTS_ENABLE_LOCK_CHECK
  297. {
  298. int ix;
  299. erts_psd_required_locks[ERTS_PSD_ERROR_HANDLER].get_locks
  300. = ERTS_PSD_ERROR_HANDLER_BUF_GET_LOCKS;
  301. erts_psd_required_locks[ERTS_PSD_ERROR_HANDLER].set_locks
  302. = ERTS_PSD_ERROR_HANDLER_BUF_SET_LOCKS;
  303. erts_psd_required_locks[ERTS_PSD_SAVED_CALLS_BUF].get_locks
  304. = ERTS_PSD_SAVED_CALLS_BUF_GET_LOCKS;
  305. erts_psd_required_locks[ERTS_PSD_SAVED_CALLS_BUF].set_locks
  306. = ERTS_PSD_SAVED_CALLS_BUF_SET_LOCKS;
  307. erts_psd_required_locks[ERTS_PSD_SCHED_ID].get_locks
  308. = ERTS_PSD_SCHED_ID_GET_LOCKS;
  309. erts_psd_required_locks[ERTS_PSD_SCHED_ID].set_locks
  310. = ERTS_PSD_SCHED_ID_SET_LOCKS;
  311. erts_psd_required_locks[ERTS_PSD_DIST_ENTRY].get_locks
  312. = ERTS_PSD_DIST_ENTRY_GET_LOCKS;
  313. erts_psd_required_locks[ERTS_PSD_DIST_ENTRY].set_locks
  314. = ERTS_PSD_DIST_ENTRY_SET_LOCKS;
  315. erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].get_locks
  316. = ERTS_PSD_CALL_TIME_BP_GET_LOCKS;
  317. erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].set_locks
  318. = ERTS_PSD_CALL_TIME_BP_SET_LOCKS;
  319. /* Check that we have locks for all entries */
  320. for (ix = 0; ix < ERTS_PSD_SIZE; ix++) {
  321. ERTS_SMP_LC_ASSERT(erts_psd_required_locks[ix].get_locks);
  322. ERTS_SMP_LC_ASSERT(erts_psd_required_locks[ix].set_locks);
  323. }
  324. }
  325. #endif
  326. }
  327. /* initialize the scheduler */
  328. void
  329. erts_init_process(int ncpu)
  330. {
  331. Uint proc_bits = ERTS_PROC_BITS;
  332. #ifdef ERTS_SMP
  333. erts_disable_proc_not_running_opt = 0;
  334. erts_init_proc_lock(ncpu);
  335. #endif
  336. init_proclist_alloc();
  337. erts_smp_atomic32_init(&process_count, 0);
  338. if (erts_use_r9_pids_ports) {
  339. proc_bits = ERTS_R9_PROC_BITS;
  340. ASSERT(erts_max_processes <= (1 << ERTS_R9_PROC_BITS));
  341. }
  342. process_tab = (Process**) erts_alloc(ERTS_ALC_T_PROC_TABLE,
  343. erts_max_processes*sizeof(Process*));
  344. sys_memzero(process_tab, erts_max_processes * sizeof(Process*));
  345. #ifdef HYBRID
  346. erts_active_procs = (Process**)
  347. erts_alloc(ERTS_ALC_T_ACTIVE_PROCS,
  348. erts_max_processes * sizeof(Process*));
  349. erts_num_active_procs = 0;
  350. #endif
  351. erts_smp_mtx_init(&proc_tab_mtx, "proc_tab");
  352. p_last = -1;
  353. p_next = 0;
  354. p_serial = 0;
  355. p_serial_shift = erts_fit_in_bits(erts_max_processes - 1);
  356. p_serial_mask = ((~(~((Uint) 0) << proc_bits)) >> p_serial_shift);
  357. erts_process_tab_index_mask = ~(~((Uint) 0) << p_serial_shift);
  358. #ifndef BM_COUNTERS
  359. processes_busy = 0;
  360. #endif
  361. last_reductions = 0;
  362. last_exact_reductions = 0;
  363. erts_default_process_flags = 0;
  364. }
  365. void
  366. erts_late_init_process(void)
  367. {
  368. int ix;
  369. init_processes_bif();
  370. erts_smp_spinlock_init(&erts_sched_stat.lock, "sched_stat");
  371. for (ix = 0; ix < ERTS_NO_PRIO_LEVELS; ix++) {
  372. Eterm atom;
  373. char *atom_str;
  374. switch (ix) {
  375. case PRIORITY_MAX:
  376. atom_str = "process_max";
  377. break;
  378. case PRIORITY_HIGH:
  379. atom_str = "process_high";
  380. break;
  381. case PRIORITY_NORMAL:
  382. atom_str = "process_normal";
  383. break;
  384. case PRIORITY_LOW:
  385. atom_str = "process_low";
  386. break;
  387. case ERTS_PORT_PRIO_LEVEL:
  388. atom_str = "port";
  389. break;
  390. default:
  391. atom_str = "bad_prio";
  392. ASSERT(!"bad prio");
  393. break;
  394. }
  395. atom = am_atom_put(atom_str, sys_strlen(atom_str));
  396. erts_sched_stat.prio[ix].name = atom;
  397. erts_sched_stat.prio[ix].total_executed = 0;
  398. erts_sched_stat.prio[ix].executed = 0;
  399. erts_sched_stat.prio[ix].total_migrated = 0;
  400. erts_sched_stat.prio[ix].migrated = 0;
  401. }
  402. }
  403. static ERTS_INLINE ErtsProcList *
  404. proclist_create(Process *p)
  405. {
  406. ErtsProcList *plp = proclist_alloc();
  407. plp->pid = p->id;
  408. plp->started = p->started;
  409. return plp;
  410. }
  411. static ERTS_INLINE void
  412. proclist_destroy(ErtsProcList *plp)
  413. {
  414. proclist_free(plp);
  415. }
  416. static ERTS_INLINE int
  417. proclist_same(ErtsProcList *plp, Process *p)
  418. {
  419. return (plp->pid == p->id
  420. && erts_cmp_timeval(&plp->started, &p->started) == 0);
  421. }
  422. ErtsProcList *
  423. erts_proclist_create(Process *p)
  424. {
  425. return proclist_create(p);
  426. }
  427. void
  428. erts_proclist_destroy(ErtsProcList *plp)
  429. {
  430. proclist_destroy(plp);
  431. }
  432. int
  433. erts_proclist_same(ErtsProcList *plp, Process *p)
  434. {
  435. return proclist_same(plp, p);
  436. }
  437. void *
  438. erts_psd_set_init(Process *p, ErtsProcLocks plocks, int ix, void *data)
  439. {
  440. void *old;
  441. ErtsProcLocks xplocks;
  442. int refc = 0;
  443. ErtsPSD *psd = erts_alloc(ERTS_ALC_T_PSD, sizeof(ErtsPSD));
  444. int i;
  445. for (i = 0; i < ERTS_PSD_SIZE; i++)
  446. psd->data[i] = NULL;
  447. ERTS_SMP_LC_ASSERT(plocks);
  448. ERTS_SMP_LC_ASSERT(plocks == erts_proc_lc_my_proc_locks(p));
  449. xplocks = ERTS_PROC_LOCKS_ALL;
  450. xplocks &= ~plocks;
  451. if (xplocks && erts_smp_proc_trylock(p, xplocks) == EBUSY) {
  452. if (xplocks & ERTS_PROC_LOCK_MAIN) {
  453. erts_smp_proc_inc_refc(p);
  454. erts_smp_proc_unlock(p, plocks);
  455. erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL);
  456. refc = 1;
  457. }
  458. else {
  459. if (plocks & ERTS_PROC_LOCKS_ALL_MINOR)
  460. erts_smp_proc_unlock(p, plocks & ERTS_PROC_LOCKS_ALL_MINOR);
  461. erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
  462. }
  463. }
  464. if (!p->psd)
  465. p->psd = psd;
  466. if (xplocks)
  467. erts_smp_proc_unlock(p, xplocks);
  468. if (refc)
  469. erts_smp_proc_dec_refc(p);
  470. ASSERT(p->psd);
  471. if (p->psd != psd)
  472. erts_free(ERTS_ALC_T_PSD, psd);
  473. old = p->psd->data[ix];
  474. p->psd->data[ix] = data;
  475. ERTS_SMP_LC_ASSERT(plocks == erts_proc_lc_my_proc_locks(p));
  476. return old;
  477. }
  478. #ifdef ERTS_SMP
  479. void
  480. erts_sched_finish_poke(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flags)
  481. {
  482. switch (flags & ERTS_SSI_FLGS_SLEEP_TYPE) {
  483. case ERTS_SSI_FLG_POLL_SLEEPING:
  484. erts_sys_schedule_interrupt(1);
  485. break;
  486. case ERTS_SSI_FLG_TSE_SLEEPING:
  487. erts_tse_set(ssi->event);
  488. break;
  489. case 0:
  490. break;
  491. default:
  492. erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n",
  493. __FILE__, __LINE__);
  494. break;
  495. }
  496. }
  497. typedef struct erts_misc_aux_work_t_ erts_misc_aux_work_t;
  498. struct erts_misc_aux_work_t_ {
  499. erts_misc_aux_work_t *next;
  500. void (*func)(void *);
  501. void *arg;
  502. };
  503. typedef struct {
  504. erts_smp_mtx_t mtx;
  505. erts_misc_aux_work_t *first;
  506. erts_misc_aux_work_t *last;
  507. } erts_misc_aux_work_q_t;
  508. typedef union {
  509. erts_misc_aux_work_q_t data;
  510. char align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_misc_aux_work_q_t))];
  511. } erts_algnd_misc_aux_work_q_t;
  512. static erts_algnd_misc_aux_work_q_t *misc_aux_work_queues;
  513. ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(misc_aux_work,
  514. erts_misc_aux_work_t,
  515. 200,
  516. ERTS_ALC_T_MISC_AUX_WORK)
  517. static void
  518. init_misc_aux_work(void)
  519. {
  520. int ix;
  521. init_misc_aux_work_alloc();
  522. misc_aux_work_queues = erts_alloc(ERTS_ALC_T_MISC_AUX_WORK_Q,
  523. (sizeof(erts_algnd_misc_aux_work_q_t)
  524. *(erts_no_schedulers+1)));
  525. if ((((UWord) misc_aux_work_queues) & ERTS_CACHE_LINE_MASK) != 0)
  526. misc_aux_work_queues = ((erts_algnd_misc_aux_work_q_t *)
  527. ((((UWord) misc_aux_work_queues)
  528. & ~ERTS_CACHE_LINE_MASK)
  529. + ERTS_CACHE_LINE_SIZE));
  530. for (ix = 0; ix < erts_no_schedulers; ix++) {
  531. erts_smp_mtx_init_x(&misc_aux_work_queues[ix].data.mtx,
  532. "misc_aux_work_queue",
  533. make_small(ix + 1));
  534. misc_aux_work_queues[ix].data.first = NULL;
  535. misc_aux_work_queues[ix].data.last = NULL;
  536. }
  537. }
  538. static void
  539. handle_misc_aux_work(ErtsSchedulerData *esdp)
  540. {
  541. int ix = (int) esdp->no - 1;
  542. erts_misc_aux_work_t *mawp;
  543. erts_smp_mtx_lock(&misc_aux_work_queues[ix].data.mtx);
  544. mawp = misc_aux_work_queues[ix].data.first;
  545. misc_aux_work_queues[ix].data.first = NULL;
  546. misc_aux_work_queues[ix].data.last = NULL;
  547. erts_smp_mtx_unlock(&misc_aux_work_queues[ix].data.mtx);
  548. while (mawp) {
  549. erts_misc_aux_work_t *free_mawp;
  550. mawp->func(mawp->arg);
  551. free_mawp = mawp;
  552. mawp = mawp->next;
  553. misc_aux_work_free(free_mawp);
  554. }
  555. }
  556. void
  557. erts_smp_schedule_misc_aux_work(int ignore_self,
  558. int max_sched,
  559. void (*func)(void *),
  560. void *arg)
  561. {
  562. int ix, ignore_ix = -1;
  563. if (ignore_self) {
  564. ErtsSchedulerData *esdp = erts_get_scheduler_data();
  565. if (esdp)
  566. ignore_ix = (int) esdp->no - 1;
  567. }
  568. ASSERT(0 <= max_sched && max_sched <= erts_no_schedulers);
  569. for (ix = 0; ix < max_sched; ix++) {
  570. erts_aint32_t aux_work;
  571. erts_misc_aux_work_t *mawp;
  572. ErtsSchedulerSleepInfo *ssi;
  573. if (ix == ignore_ix)
  574. continue;
  575. mawp = misc_aux_work_alloc();
  576. mawp->func = func;
  577. mawp->arg = arg;
  578. mawp->next = NULL;
  579. erts_smp_mtx_lock(&misc_aux_work_queues[ix].data.mtx);
  580. if (!misc_aux_work_queues[ix].data.last)
  581. misc_aux_work_queues[ix].data.first = mawp;
  582. else
  583. misc_aux_work_queues[ix].data.last->next = mawp;
  584. misc_aux_work_queues[ix].data.last = mawp;
  585. erts_smp_mtx_unlock(&misc_aux_work_queues[ix].data.mtx);
  586. ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
  587. aux_work = erts_smp_atomic32_bor(&ssi->aux_work,
  588. ERTS_SSI_AUX_WORK_MISC);
  589. if ((aux_work & ERTS_SSI_AUX_WORK_MISC) == 0)
  590. erts_sched_poke(ssi);
  591. }
  592. }
  593. #ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
  594. void
  595. erts_smp_notify_check_children_needed(void)
  596. {
  597. int i;
  598. for (i = 0; i < erts_no_schedulers; i++) {
  599. erts_aint32_t aux_work;
  600. ErtsSchedulerSleepInfo *ssi;
  601. ssi = ERTS_SCHED_SLEEP_INFO_IX(i);
  602. aux_work = erts_smp_atomic32_bor(&ssi->aux_work,
  603. ERTS_SSI_AUX_WORK_CHECK_CHILDREN);
  604. if (!(aux_work & ERTS_SSI_AUX_WORK_CHECK_CHILDREN))
  605. erts_sched_poke(ssi);
  606. }
  607. }
  608. #endif
  609. #ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  610. static ERTS_INLINE erts_aint32_t
  611. blockable_aux_work(ErtsSchedulerData *esdp,
  612. ErtsSchedulerSleepInfo *ssi,
  613. erts_aint32_t aux_work)
  614. {
  615. if (aux_work & ERTS_SSI_BLOCKABLE_AUX_WORK_MASK) {
  616. if (aux_work & ERTS_SSI_AUX_WORK_MISC) {
  617. aux_work = erts_smp_atomic32_band(&ssi->aux_work,
  618. ~ERTS_SSI_AUX_WORK_MISC);
  619. aux_work &= ~ERTS_SSI_AUX_WORK_MISC;
  620. handle_misc_aux_work(esdp);
  621. }
  622. #ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
  623. if (aux_work & ERTS_SSI_AUX_WORK_CHECK_CHILDREN) {
  624. aux_work = erts_smp_atomic32_band(&ssi->aux_work,
  625. ~ERTS_SSI_AUX_WORK_CHECK_CHILDREN);
  626. aux_work &= ~ERTS_SSI_AUX_WORK_CHECK_CHILDREN;
  627. erts_check_children();
  628. }
  629. #endif
  630. }
  631. return aux_work;
  632. }
  633. #endif
  634. #ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
  635. static ERTS_INLINE erts_aint32_t
  636. nonblockable_aux_work(ErtsSchedulerData *esdp,
  637. ErtsSchedulerSleepInfo *ssi,
  638. erts_aint32_t aux_work)
  639. {
  640. if (aux_work & ERTS_SSI_NONBLOCKABLE_AUX_WORK_MASK) {
  641. }
  642. }
  643. #endif
  644. static void
  645. prepare_for_block(void *vrq)
  646. {
  647. erts_smp_runq_unlock((ErtsRunQueue *) vrq);
  648. }
  649. static void
  650. resume_after_block(void *vrq)
  651. {
  652. erts_smp_runq_lock((ErtsRunQueue *) vrq);
  653. }
  654. #endif
  655. static ERTS_INLINE void
  656. sched_waiting_sys(Uint no, ErtsRunQueue *rq)
  657. {
  658. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  659. ASSERT(rq->waiting >= 0);
  660. rq->flags |= (ERTS_RUNQ_FLG_OUT_OF_WORK
  661. | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK);
  662. rq->waiting++;
  663. rq->waiting *= -1;
  664. rq->woken = 0;
  665. if (erts_system_profile_flags.scheduler)
  666. profile_scheduler(make_small(no), am_inactive);
  667. }
  668. static ERTS_INLINE void
  669. sched_active_sys(Uint no, ErtsRunQueue *rq)
  670. {
  671. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  672. ASSERT(rq->waiting < 0);
  673. rq->waiting *= -1;
  674. rq->waiting--;
  675. if (erts_system_profile_flags.scheduler)
  676. profile_scheduler(make_small(no), am_active);
  677. }
  678. Uint
  679. erts_active_schedulers(void)
  680. {
  681. /* RRRRRRRRR */
  682. Uint as = erts_no_schedulers;
  683. ERTS_ATOMIC_FOREACH_RUNQ(rq, as -= abs(rq->waiting));
  684. ASSERT(as >= 0);
  685. return as;
  686. }
  687. static ERTS_INLINE int
  688. prepare_for_sys_schedule(void)
  689. {
  690. #ifdef ERTS_SMP
  691. while (!erts_port_task_have_outstanding_io_tasks()
  692. && !erts_smp_atomic32_xchg(&doing_sys_schedule, 1)) {
  693. if (!erts_port_task_have_outstanding_io_tasks())
  694. return 1;
  695. erts_smp_atomic32_set(&doing_sys_schedule, 0);
  696. }
  697. return 0;
  698. #else
  699. return !erts_port_task_have_outstanding_io_tasks();
  700. #endif
  701. }
  702. #ifdef ERTS_SMP
  703. static ERTS_INLINE void
  704. sched_change_waiting_sys_to_waiting(Uint no, ErtsRunQueue *rq)
  705. {
  706. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  707. ASSERT(rq->waiting < 0);
  708. rq->waiting *= -1;
  709. }
  710. static ERTS_INLINE void
  711. sched_waiting(Uint no, ErtsRunQueue *rq)
  712. {
  713. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  714. rq->flags |= (ERTS_RUNQ_FLG_OUT_OF_WORK
  715. | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK);
  716. if (rq->waiting < 0)
  717. rq->waiting--;
  718. else
  719. rq->waiting++;
  720. rq->woken = 0;
  721. if (erts_system_profile_flags.scheduler)
  722. profile_scheduler(make_small(no), am_inactive);
  723. }
  724. static ERTS_INLINE void
  725. sched_active(Uint no, ErtsRunQueue *rq)
  726. {
  727. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  728. if (rq->waiting < 0)
  729. rq->waiting++;
  730. else
  731. rq->waiting--;
  732. if (erts_system_profile_flags.scheduler)
  733. profile_scheduler(make_small(no), am_active);
  734. }
  735. static int ERTS_INLINE
  736. ongoing_multi_scheduling_block(void)
  737. {
  738. return erts_smp_atomic32_read(&schdlr_sspnd.msb.ongoing) != 0;
  739. }
  740. static ERTS_INLINE void
  741. empty_runq(ErtsRunQueue *rq)
  742. {
  743. erts_aint32_t oifls = erts_smp_atomic32_band(&rq->info_flags,
  744. ~ERTS_RUNQ_IFLG_NONEMPTY);
  745. if (oifls & ERTS_RUNQ_IFLG_NONEMPTY) {
  746. #ifdef DEBUG
  747. erts_aint32_t empty = erts_smp_atomic32_read(&no_empty_run_queues);
  748. /*
  749. * For a short period of time no_empty_run_queues may have
  750. * been increased twice for a specific run queue.
  751. */
  752. ASSERT(0 <= empty && empty < 2*erts_no_run_queues);
  753. #endif
  754. erts_smp_atomic32_inc(&no_empty_run_queues);
  755. }
  756. }
  757. static ERTS_INLINE void
  758. non_empty_runq(ErtsRunQueue *rq)
  759. {
  760. erts_aint32_t oifls = erts_smp_atomic32_bor(&rq->info_flags,
  761. ERTS_RUNQ_IFLG_NONEMPTY);
  762. if (!(oifls & ERTS_RUNQ_IFLG_NONEMPTY)) {
  763. #ifdef DEBUG
  764. erts_aint32_t empty = erts_smp_atomic32_read(&no_empty_run_queues);
  765. /*
  766. * For a short period of time no_empty_run_queues may have
  767. * been increased twice for a specific run queue.
  768. */
  769. ASSERT(0 < empty && empty <= 2*erts_no_run_queues);
  770. #endif
  771. erts_smp_atomic32_dec(&no_empty_run_queues);
  772. }
  773. }
  774. static erts_aint32_t
  775. sched_prep_spin_wait(ErtsSchedulerSleepInfo *ssi)
  776. {
  777. erts_aint32_t oflgs;
  778. erts_aint32_t nflgs = (ERTS_SSI_FLG_SLEEPING
  779. | ERTS_SSI_FLG_WAITING);
  780. erts_aint32_t xflgs = 0;
  781. do {
  782. oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
  783. if (oflgs == xflgs)
  784. return nflgs;
  785. xflgs = oflgs;
  786. } while (!(oflgs & ERTS_SSI_FLG_SUSPENDED));
  787. return oflgs;
  788. }
  789. static erts_aint32_t
  790. sched_prep_cont_spin_wait(ErtsSchedulerSleepInfo *ssi)
  791. {
  792. erts_aint32_t oflgs;
  793. erts_aint32_t nflgs = (ERTS_SSI_FLG_SLEEPING
  794. | ERTS_SSI_FLG_WAITING);
  795. erts_aint32_t xflgs = ERTS_SSI_FLG_WAITING;
  796. do {
  797. oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
  798. if (oflgs == xflgs)
  799. return nflgs;
  800. xflgs = oflgs;
  801. nflgs |= oflgs & ERTS_SSI_FLG_SUSPENDED;
  802. } while (oflgs & ERTS_SSI_FLG_WAITING);
  803. return oflgs;
  804. }
  805. static erts_aint32_t
  806. sched_spin_wait(ErtsSchedulerSleepInfo *ssi, int spincount)
  807. {
  808. int until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
  809. int sc = spincount;
  810. erts_aint32_t flgs;
  811. do {
  812. flgs = erts_smp_atomic32_read(&ssi->flags);
  813. if ((flgs & (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING))
  814. != (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING)) {
  815. break;
  816. }
  817. ERTS_SPIN_BODY;
  818. if (--until_yield == 0) {
  819. until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
  820. erts_thr_yield();
  821. }
  822. } while (--sc > 0);
  823. return flgs;
  824. }
  825. static erts_aint32_t
  826. sched_set_sleeptype(ErtsSchedulerSleepInfo *ssi, erts_aint32_t sleep_type)
  827. {
  828. erts_aint32_t oflgs;
  829. erts_aint32_t nflgs = ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING|sleep_type;
  830. erts_aint32_t xflgs = ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING;
  831. if (sleep_type == ERTS_SSI_FLG_TSE_SLEEPING)
  832. erts_tse_reset(ssi->event);
  833. while (1) {
  834. oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
  835. if (oflgs == xflgs)
  836. return nflgs;
  837. if ((oflgs & (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING))
  838. != (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING)) {
  839. return oflgs;
  840. }
  841. xflgs = oflgs;
  842. nflgs |= oflgs & ERTS_SSI_FLG_SUSPENDED;
  843. }
  844. }
  845. #define ERTS_SCHED_WAIT_WOKEN(FLGS) \
  846. (((FLGS) & (ERTS_SSI_FLG_WAITING|ERTS_SSI_FLG_SUSPENDED)) \
  847. != ERTS_SSI_FLG_WAITING)
  848. static void
  849. scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
  850. {
  851. ErtsSchedulerSleepInfo *ssi = esdp->ssi;
  852. int spincount;
  853. erts_aint32_t flgs;
  854. #if defined(ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK) \
  855. || defined(ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK)
  856. erts_aint32_t aux_work;
  857. #endif
  858. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  859. erts_smp_spin_lock(&rq->sleepers.lock);
  860. flgs = sched_prep_spin_wait(ssi);
  861. if (flgs & ERTS_SSI_FLG_SUSPENDED) {
  862. /* Go suspend instead... */
  863. erts_smp_spin_unlock(&rq->sleepers.lock);
  864. return;
  865. }
  866. ssi->prev = NULL;
  867. ssi->next = rq->sleepers.list;
  868. if (rq->sleepers.list)
  869. rq->sleepers.list->prev = ssi;
  870. rq->sleepers.list = ssi;
  871. erts_smp_spin_unlock(&rq->sleepers.lock);
  872. /*
  873. * If all schedulers are waiting, one of them *should*
  874. * be waiting in erl_sys_schedule()
  875. */
  876. if (!prepare_for_sys_schedule()) {
  877. sched_waiting(esdp->no, rq);
  878. erts_smp_runq_unlock(rq);
  879. spincount = ERTS_SCHED_TSE_SLEEP_SPINCOUNT;
  880. tse_wait:
  881. #ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  882. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  883. tse_blockable_aux_work:
  884. aux_work = blockable_aux_work(esdp, ssi, aux_work);
  885. #endif
  886. erts_smp_activity_begin(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
  887. while (1) {
  888. #ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
  889. #ifndef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  890. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  891. #endif
  892. nonblockable_aux_work(esdp, ssi, aux_work);
  893. #endif
  894. flgs = sched_spin_wait(ssi, spincount);
  895. if (flgs & ERTS_SSI_FLG_SLEEPING) {
  896. ASSERT(flgs & ERTS_SSI_FLG_WAITING);
  897. flgs = sched_set_sleeptype(ssi, ERTS_SSI_FLG_TSE_SLEEPING);
  898. if (flgs & ERTS_SSI_FLG_SLEEPING) {
  899. int res;
  900. ASSERT(flgs & ERTS_SSI_FLG_TSE_SLEEPING);
  901. ASSERT(flgs & ERTS_SSI_FLG_WAITING);
  902. do {
  903. res = erts_tse_wait(ssi->event);
  904. } while (res == EINTR);
  905. }
  906. }
  907. if (!(flgs & ERTS_SSI_FLG_WAITING)) {
  908. ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
  909. break;
  910. }
  911. flgs = sched_prep_cont_spin_wait(ssi);
  912. spincount = ERTS_SCHED_TSE_SLEEP_SPINCOUNT;
  913. if (!(flgs & ERTS_SSI_FLG_WAITING)) {
  914. ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
  915. break;
  916. }
  917. #ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  918. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  919. if (aux_work & ERTS_SSI_BLOCKABLE_AUX_WORK_MASK) {
  920. erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
  921. goto tse_blockable_aux_work;
  922. }
  923. #endif
  924. }
  925. erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
  926. if (flgs & ~ERTS_SSI_FLG_SUSPENDED)
  927. erts_smp_atomic32_band(&ssi->flags, ERTS_SSI_FLG_SUSPENDED);
  928. erts_smp_runq_lock(rq);
  929. sched_active(esdp->no, rq);
  930. }
  931. else {
  932. erts_aint_t dt;
  933. erts_smp_atomic32_set(&function_calls, 0);
  934. *fcalls = 0;
  935. sched_waiting_sys(esdp->no, rq);
  936. erts_smp_runq_unlock(rq);
  937. spincount = ERTS_SCHED_SYS_SLEEP_SPINCOUNT;
  938. while (spincount-- > 0) {
  939. sys_poll_aux_work:
  940. ASSERT(!erts_port_task_have_outstanding_io_tasks());
  941. erl_sys_schedule(1); /* Might give us something to do */
  942. dt = erts_do_time_read_and_reset();
  943. if (dt) erts_bump_timer(dt);
  944. sys_aux_work:
  945. #ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  946. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  947. aux_work = blockable_aux_work(esdp, ssi, aux_work);
  948. #endif
  949. #ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
  950. #ifndef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  951. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  952. #endif
  953. nonblockable_aux_work(esdp, ssi, aux_work);
  954. #endif
  955. flgs = erts_smp_atomic32_read(&ssi->flags);
  956. if (!(flgs & ERTS_SSI_FLG_WAITING)) {
  957. ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
  958. goto sys_woken;
  959. }
  960. if (!(flgs & ERTS_SSI_FLG_SLEEPING)) {
  961. flgs = sched_prep_cont_spin_wait(ssi);
  962. if (!(flgs & ERTS_SSI_FLG_WAITING)) {
  963. ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
  964. goto sys_woken;
  965. }
  966. }
  967. /*
  968. * If we got new I/O tasks we aren't allowed to
  969. * call erl_sys_schedule() until it is handled.
  970. */
  971. if (erts_port_task_have_outstanding_io_tasks()) {
  972. erts_smp_atomic32_set(&doing_sys_schedule, 0);
  973. /*
  974. * Got to check that we still got I/O tasks; otherwise
  975. * we have to continue checking for I/O...
  976. */
  977. if (!prepare_for_sys_schedule()) {
  978. spincount *= ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT;
  979. goto tse_wait;
  980. }
  981. }
  982. }
  983. erts_smp_runq_lock(rq);
  984. /*
  985. * If we got new I/O tasks we aren't allowed to
  986. * sleep in erl_sys_schedule().
  987. */
  988. if (erts_port_task_have_outstanding_io_tasks()) {
  989. erts_smp_atomic32_set(&doing_sys_schedule, 0);
  990. /*
  991. * Got to check that we still got I/O tasks; otherwise
  992. * we have to wait in erl_sys_schedule() after all...
  993. */
  994. if (prepare_for_sys_schedule())
  995. goto do_sys_schedule;
  996. /*
  997. * Not allowed to wait in erl_sys_schedule;
  998. * do tse wait instead...
  999. */
  1000. sched_change_waiting_sys_to_waiting(esdp->no, rq);
  1001. erts_smp_runq_unlock(rq);
  1002. spincount = 0;
  1003. goto tse_wait;
  1004. }
  1005. else {
  1006. do_sys_schedule:
  1007. erts_sys_schedule_interrupt(0);
  1008. flgs = sched_set_sleeptype(ssi, ERTS_SSI_FLG_POLL_SLEEPING);
  1009. if (!(flgs & ERTS_SSI_FLG_SLEEPING)) {
  1010. if (!(flgs & ERTS_SSI_FLG_WAITING))
  1011. goto sys_locked_woken;
  1012. erts_smp_runq_unlock(rq);
  1013. flgs = sched_prep_cont_spin_wait(ssi);
  1014. if (!(flgs & ERTS_SSI_FLG_WAITING)) {
  1015. ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
  1016. goto sys_woken;
  1017. }
  1018. ASSERT(!erts_port_task_have_outstanding_io_tasks());
  1019. goto sys_poll_aux_work;
  1020. }
  1021. ASSERT(flgs & ERTS_SSI_FLG_POLL_SLEEPING);
  1022. ASSERT(flgs & ERTS_SSI_FLG_WAITING);
  1023. erts_smp_runq_unlock(rq);
  1024. ASSERT(!erts_port_task_have_outstanding_io_tasks());
  1025. erl_sys_schedule(0);
  1026. dt = erts_do_time_read_and_reset();
  1027. if (dt) erts_bump_timer(dt);
  1028. flgs = sched_prep_cont_spin_wait(ssi);
  1029. if (flgs & ERTS_SSI_FLG_WAITING)
  1030. goto sys_aux_work;
  1031. sys_woken:
  1032. erts_smp_runq_lock(rq);
  1033. sys_locked_woken:
  1034. erts_smp_atomic32_set(&doing_sys_schedule, 0);
  1035. if (flgs & ~ERTS_SSI_FLG_SUSPENDED)
  1036. erts_smp_atomic32_band(&ssi->flags, ERTS_SSI_FLG_SUSPENDED);
  1037. sched_active_sys(esdp->no, rq);
  1038. }
  1039. }
  1040. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  1041. }
  1042. static ERTS_INLINE erts_aint32_t
  1043. ssi_flags_set_wake(ErtsSchedulerSleepInfo *ssi)
  1044. {
  1045. /* reset all flags but suspended */
  1046. erts_aint32_t oflgs;
  1047. erts_aint32_t nflgs = 0;
  1048. erts_aint32_t xflgs = ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING;
  1049. while (1) {
  1050. oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
  1051. if (oflgs == xflgs)
  1052. return oflgs;
  1053. nflgs = oflgs & ERTS_SSI_FLG_SUSPENDED;
  1054. xflgs = oflgs;
  1055. }
  1056. }
  1057. static void
  1058. wake_scheduler(ErtsRunQueue *rq, int incq, int one)
  1059. {
  1060. int res;
  1061. ErtsSchedulerSleepInfo *ssi;
  1062. ErtsSchedulerSleepList *sl;
  1063. /*
  1064. * The unlocked run queue is not strictly necessary
  1065. * from a thread safety or deadlock prevention
  1066. * perspective. It will, however, cost us performance
  1067. * if it is locked during wakup of another scheduler,
  1068. * so all code *should* handle this without having
  1069. * the lock on the run queue.
  1070. */
  1071. ERTS_SMP_LC_ASSERT(!erts_smp_lc_runq_is_locked(rq));
  1072. sl = &rq->sleepers;
  1073. erts_smp_spin_lock(&sl->lock);
  1074. ssi = sl->list;
  1075. if (!ssi)
  1076. erts_smp_spin_unlock(&sl->lock);
  1077. else if (one) {
  1078. erts_aint32_t flgs;
  1079. if (ssi->prev)
  1080. ssi->prev->next = ssi->next;
  1081. else {
  1082. ASSERT(sl->list == ssi);
  1083. sl->list = ssi->next;
  1084. }
  1085. if (ssi->next)
  1086. ssi->next->prev = ssi->prev;
  1087. res = sl->list != NULL;
  1088. erts_smp_spin_unlock(&sl->lock);
  1089. flgs = ssi_flags_set_wake(ssi);
  1090. erts_sched_finish_poke(ssi, flgs);
  1091. if (incq && !erts_common_run_queue && (flgs & ERTS_SSI_FLG_WAITING))
  1092. non_empty_runq(rq);
  1093. }
  1094. else {
  1095. sl->list = NULL;
  1096. erts_smp_spin_unlock(&sl->lock);
  1097. do {
  1098. ErtsSchedulerSleepInfo *wake_ssi = ssi;
  1099. ssi = ssi->next;
  1100. erts_sched_finish_poke(wake_ssi, ssi_flags_set_wake(wake_ssi));
  1101. } while (ssi);
  1102. }
  1103. }
  1104. static void
  1105. wake_all_schedulers(void)
  1106. {
  1107. if (erts_common_run_queue)
  1108. wake_scheduler(erts_common_run_queue, 0, 0);
  1109. else {
  1110. int ix;
  1111. for (ix = 0; ix < erts_no_run_queues; ix++) {
  1112. ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
  1113. wake_scheduler(rq, 0, 1);
  1114. }
  1115. }
  1116. }
  1117. static ERTS_INLINE int
  1118. chk_wake_sched(ErtsRunQueue *crq, int ix, int activate)
  1119. {
  1120. erts_aint32_t iflgs;
  1121. ErtsRunQueue *wrq;
  1122. if (crq->ix == ix)
  1123. return 0;
  1124. wrq = ERTS_RUNQ_IX(ix);
  1125. iflgs = erts_smp_atomic32_read(&wrq->info_flags);
  1126. if (!(iflgs & (ERTS_RUNQ_IFLG_SUSPENDED|ERTS_RUNQ_IFLG_NONEMPTY))) {
  1127. if (activate) {
  1128. if (ix == erts_smp_atomic32_cmpxchg(&balance_info.active_runqs,
  1129. ix+1,
  1130. ix)) {
  1131. erts_smp_xrunq_lock(crq, wrq);
  1132. wrq->flags &= ~ERTS_RUNQ_FLG_INACTIVE;
  1133. erts_smp_xrunq_unlock(crq, wrq);
  1134. }
  1135. }
  1136. wake_scheduler(wrq, 0, 1);
  1137. return 1;
  1138. }
  1139. return 0;
  1140. }
  1141. static void
  1142. wake_scheduler_on_empty_runq(ErtsRunQueue *crq)
  1143. {
  1144. int ix = crq->ix;
  1145. int stop_ix = ix;
  1146. int active_ix = erts_smp_atomic32_read(&balance_info.active_runqs);
  1147. int balance_ix = erts_smp_atomic32_read(&balance_info.used_runqs);
  1148. if (active_ix > balance_ix)
  1149. active_ix = balance_ix;
  1150. if (ix >= active_ix)
  1151. stop_ix = ix = active_ix;
  1152. /* Try to wake a scheduler on an active run queue */
  1153. while (1) {
  1154. ix--;
  1155. if (ix < 0) {
  1156. if (active_ix == stop_ix)
  1157. break;
  1158. ix = active_ix - 1;
  1159. }
  1160. if (ix == stop_ix)
  1161. break;
  1162. if (chk_wake_sched(crq, ix, 0))
  1163. return;
  1164. }
  1165. if (active_ix < balance_ix) {
  1166. /* Try to activate a new run queue and wake its scheduler */
  1167. (void) chk_wake_sched(crq, active_ix, 1);
  1168. }
  1169. }
  1170. #endif /* ERTS_SMP */
  1171. static ERTS_INLINE void
  1172. smp_notify_inc_runq(ErtsRunQueue *runq)
  1173. {
  1174. #ifdef ERTS_SMP
  1175. if (runq)
  1176. wake_scheduler(runq, 1, 1);
  1177. #endif
  1178. }
  1179. void
  1180. erts_smp_notify_inc_runq(ErtsRunQueue *runq)
  1181. {
  1182. smp_notify_inc_runq(runq);
  1183. }
  1184. void
  1185. erts_sched_notify_check_cpu_bind(void)
  1186. {
  1187. #ifdef ERTS_SMP
  1188. int ix;
  1189. if (erts_common_run_queue) {
  1190. for (ix = 0; ix < erts_no_schedulers; ix++)
  1191. erts_smp_atomic32_set(&ERTS_SCHEDULER_IX(ix)->chk_cpu_bind, 1);
  1192. wake_all_schedulers();
  1193. }
  1194. else {
  1195. for (ix = 0; ix < erts_no_run_queues; ix++) {
  1196. ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
  1197. erts_smp_runq_lock(rq);
  1198. rq->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND;
  1199. erts_smp_runq_unlock(rq);
  1200. wake_scheduler(rq, 0, 1);
  1201. };
  1202. }
  1203. #else
  1204. erts_sched_check_cpu_bind(erts_get_scheduler_data());
  1205. #endif
  1206. }
  1207. #ifdef ERTS_SMP
  1208. ErtsRunQueue *
  1209. erts_prepare_emigrate(ErtsRunQueue *c_rq, ErtsRunQueueInfo *c_rqi, int prio)
  1210. {
  1211. ASSERT(ERTS_CHK_RUNQ_FLG_EMIGRATE(c_rq->flags, prio));
  1212. ASSERT(ERTS_CHK_RUNQ_FLG_EVACUATE(c_rq->flags, prio)
  1213. || c_rqi->len >= c_rqi->migrate.limit.this);
  1214. while (1) {
  1215. ErtsRunQueue *n_rq = c_rqi->migrate.runq;
  1216. ERTS_DBG_VERIFY_VALID_RUNQP(n_rq);
  1217. erts_smp_xrunq_lock(c_rq, n_rq);
  1218. /*
  1219. * erts_smp_xrunq_lock() may release lock on c_rq! We have
  1220. * to check that we still want to emigrate and emigrate
  1221. * to the same run queue as before.
  1222. */
  1223. if (ERTS_CHK_RUNQ_FLG_EMIGRATE(c_rq->flags, prio)) {
  1224. Uint32 force = (ERTS_CHK_RUNQ_FLG_EVACUATE(c_rq->flags, prio)
  1225. | (c_rq->flags & ERTS_RUNQ_FLG_INACTIVE));
  1226. if (force || c_rqi->len > c_rqi->migrate.limit.this) {
  1227. ErtsRunQueueInfo *n_rqi;
  1228. /* We still want to emigrate */
  1229. if (n_rq != c_rqi->migrate.runq) {
  1230. /* Ahh... run queue changed; need to do it all over again... */
  1231. erts_smp_runq_unlock(n_rq);
  1232. continue;
  1233. }
  1234. else {
  1235. if (prio == ERTS_PORT_PRIO_LEVEL)
  1236. n_rqi = &n_rq->ports.info;
  1237. else
  1238. n_rqi = &n_rq->procs.prio_info[prio];
  1239. if (force || (n_rqi->len < c_rqi->migrate.limit.other)) {
  1240. /* emigrate ... */
  1241. return n_rq;
  1242. }
  1243. }
  1244. }
  1245. }
  1246. ASSERT(n_rq != c_rq);
  1247. erts_smp_runq_unlock(n_rq);
  1248. if (!(c_rq->flags & ERTS_RUNQ_FLG_INACTIVE)) {
  1249. /* No more emigrations to this runq */
  1250. ERTS_UNSET_RUNQ_FLG_EMIGRATE(c_rq->flags, prio);
  1251. ERTS_DBG_SET_INVALID_RUNQP(c_rqi->migrate.runq, 0x3);
  1252. }
  1253. return NULL;
  1254. }
  1255. }
  1256. static void
  1257. immigrate(ErtsRunQueue *rq)
  1258. {
  1259. int prio;
  1260. ASSERT(rq->flags & ERTS_RUNQ_FLGS_IMMIGRATE_QMASK);
  1261. for (prio = 0; prio < ERTS_NO_PRIO_LEVELS; prio++) {
  1262. if (ERTS_CHK_RUNQ_FLG_IMMIGRATE(rq->flags, prio)) {
  1263. ErtsRunQueueInfo *rqi = (prio == ERTS_PORT_PRIO_LEVEL
  1264. ? &rq->ports.info
  1265. : &rq->procs.prio_info[prio]);
  1266. ErtsRunQueue *from_rq = rqi->migrate.runq;
  1267. int rq_locked, from_rq_locked;
  1268. ERTS_DBG_VERIFY_VALID_RUNQP(from_rq);
  1269. rq_locked = 1;
  1270. from_rq_locked = 1;
  1271. erts_smp_xrunq_lock(rq, from_rq);
  1272. /*
  1273. * erts_smp_xrunq_lock() may release lock on rq! We have
  1274. * to check that we still want to immigrate from the same
  1275. * run queue as before.
  1276. */
  1277. if (ERTS_CHK_RUNQ_FLG_IMMIGRATE(rq->flags, prio)
  1278. && from_rq == rqi->migrate.runq) {
  1279. ErtsRunQueueInfo *from_rqi = (prio == ERTS_PORT_PRIO_LEVEL
  1280. ? &from_rq->ports.info
  1281. : &from_rq->procs.prio_info[prio]);
  1282. if ((ERTS_CHK_RUNQ_FLG_EVACUATE(rq->flags, prio)
  1283. && ERTS_CHK_RUNQ_FLG_EVACUATE(from_rq->flags, prio)
  1284. && from_rqi->len)
  1285. || (from_rqi->len > rqi->migrate.limit.other
  1286. && rqi->len < rqi->migrate.limit.this)) {
  1287. if (prio == ERTS_PORT_PRIO_LEVEL) {
  1288. Port *prt = from_rq->ports.start;
  1289. if (prt) {
  1290. int prt_locked = 0;
  1291. (void) erts_port_migrate(prt, &prt_locked,
  1292. from_rq, &from_rq_locked,
  1293. rq, &rq_locked);
  1294. if (prt_locked)
  1295. erts_smp_port_unlock(prt);
  1296. }
  1297. }
  1298. else {
  1299. Process *proc;
  1300. ErtsRunPrioQueue *from_rpq;
  1301. from_rpq = (prio == PRIORITY_LOW
  1302. ? &from_rq->procs.prio[PRIORITY_NORMAL]
  1303. : &from_rq->procs.prio[prio]);
  1304. for (proc = from_rpq->first; proc; proc = proc->next)
  1305. if (proc->prio == prio && !proc->bound_runq)
  1306. break;
  1307. if (proc) {
  1308. ErtsProcLocks proc_locks = 0;
  1309. (void) erts_proc_migrate(proc, &proc_locks,
  1310. from_rq, &from_rq_locked,
  1311. rq, &rq_locked);
  1312. if (proc_locks)
  1313. erts_smp_proc_unlock(proc, proc_locks);
  1314. }
  1315. }
  1316. }
  1317. else {
  1318. ERTS_UNSET_RUNQ_FLG_IMMIGRATE(rq->flags, prio);
  1319. ERTS_DBG_SET_INVALID_RUNQP(rqi->migrate.runq, 0x1);
  1320. }
  1321. }
  1322. if (from_rq_locked)
  1323. erts_smp_runq_unlock(from_rq);
  1324. if (!rq_locked)
  1325. erts_smp_runq_lock(rq);
  1326. }
  1327. }
  1328. }
  1329. static void
  1330. evacuate_run_queue(ErtsRunQueue *evac_rq, ErtsRunQueue *rq)
  1331. {
  1332. Port *prt;
  1333. int notify_to_rq = 0;
  1334. int prio;
  1335. int prt_locked = 0;
  1336. int rq_locked = 0;
  1337. int evac_rq_locked = 1;
  1338. ErtsMigrateResult mres;
  1339. erts_smp_runq_lock(evac_rq);
  1340. erts_smp_atomic32_bor(&evac_rq->scheduler->ssi->flags,
  1341. ERTS_SSI_FLG_SUSPENDED);
  1342. evac_rq->flags &= ~ERTS_RUNQ_FLGS_IMMIGRATE_QMASK;
  1343. evac_rq->flags |= (ERTS_RUNQ_FLGS_EMIGRATE_QMASK
  1344. | ERTS_RUNQ_FLGS_EVACUATE_QMASK
  1345. | ERTS_RUNQ_FLG_SUSPENDED);
  1346. erts_smp_atomic32_bor(&evac_rq->info_flags, ERTS_RUNQ_IFLG_SUSPENDED);
  1347. /*
  1348. * Need to set up evacuation paths first since we
  1349. * may release the run queue lock on evac_rq
  1350. * when evacuating.
  1351. */
  1352. evac_rq->misc.evac_runq = rq;
  1353. evac_rq->ports.info.migrate.runq = rq;
  1354. for (prio = 0; prio < ERTS_NO_PROC_PRIO_LEVELS; prio++)
  1355. evac_rq->procs.prio_info[prio].migrate.runq = rq;
  1356. /* Evacuate scheduled misc ops */
  1357. if (evac_rq->misc.start) {
  1358. rq_locked = 1;
  1359. erts_smp_xrunq_lock(evac_rq, rq);
  1360. if (rq->misc.end)
  1361. rq->misc.end->next = evac_rq->misc.start;
  1362. else
  1363. rq->misc.start = evac_rq->misc.start;
  1364. rq->misc.end = evac_rq->misc.end;
  1365. evac_rq->misc.start = NULL;
  1366. evac_rq->misc.end = NULL;
  1367. }
  1368. /* Evacuate scheduled ports */
  1369. prt = evac_rq->ports.start;
  1370. while (prt) {
  1371. mres = erts_port_migrate(prt, &prt_locked,
  1372. evac_rq, &evac_rq_locked,
  1373. rq, &rq_locked);
  1374. if (mres == ERTS_MIGRATE_SUCCESS)
  1375. notify_to_rq = 1;
  1376. if (prt_locked)
  1377. erts_smp_port_unlock(prt);
  1378. if (!evac_rq_locked) {
  1379. evac_rq_locked = 1;
  1380. erts_smp_runq_lock(evac_rq);
  1381. }
  1382. prt = evac_rq->ports.start;
  1383. }
  1384. /* Evacuate scheduled processes */
  1385. for (prio = 0; prio < ERTS_NO_PROC_PRIO_LEVELS; prio++) {
  1386. Process *proc;
  1387. switch (prio) {
  1388. case PRIORITY_MAX:
  1389. case PRIORITY_HIGH:
  1390. case PRIORITY_NORMAL:
  1391. proc = evac_rq->procs.prio[prio].first;
  1392. while (proc) {
  1393. ErtsProcLocks proc_locks = 0;
  1394. /* Bound processes are stuck... */
  1395. while (proc->bound_runq) {
  1396. proc = proc->next;
  1397. if (!proc)
  1398. goto end_of_proc;
  1399. }
  1400. mres = erts_proc_migrate(proc, &proc_locks,
  1401. evac_rq, &evac_rq_locked,
  1402. rq, &rq_locked);
  1403. if (mres == ERTS_MIGRATE_SUCCESS)
  1404. notify_to_rq = 1;
  1405. if (proc_locks)
  1406. erts_smp_proc_unlock(proc, proc_locks);
  1407. if (!evac_rq_locked) {
  1408. erts_smp_runq_lock(evac_rq);
  1409. evac_rq_locked = 1;
  1410. }
  1411. proc = evac_rq->procs.prio[prio].first;
  1412. }
  1413. end_of_proc:
  1414. #ifdef DEBUG
  1415. for (proc = evac_rq->procs.prio[prio].first;
  1416. proc;
  1417. proc = proc->next) {
  1418. ASSERT(proc->bound_runq);
  1419. }
  1420. #endif
  1421. break;
  1422. case PRIORITY_LOW:
  1423. break;
  1424. default:
  1425. ASSERT(!"Invalid process priority");
  1426. break;
  1427. }
  1428. }
  1429. if (rq_locked)
  1430. erts_smp_runq_unlock(rq);
  1431. if (evac_rq_locked)
  1432. erts_smp_runq_unlock(evac_rq);
  1433. if (notify_to_rq)
  1434. smp_notify_inc_runq(rq);
  1435. wake_scheduler(evac_rq, 0, 1);
  1436. }
  1437. static int
  1438. try_steal_task_from_victim(ErtsRunQueue *rq, int *rq_lockedp, ErtsRunQueue *vrq)
  1439. {
  1440. Process *proc;
  1441. int vrq_locked;
  1442. if (*rq_lockedp)
  1443. erts_smp_xrunq_lock(rq, vrq);
  1444. else
  1445. erts_smp_runq_lock(vrq);
  1446. vrq_locked = 1;
  1447. ERTS_SMP_LC_CHK_RUNQ_LOCK(rq, *rq_lockedp);
  1448. ERTS_SMP_LC_CHK_RUNQ_LOCK(vrq, vrq_locked);
  1449. /*
  1450. * Check for a runnable process to steal...
  1451. */
  1452. switch (vrq->flags & ERTS_RUNQ_FLGS_PROCS_QMASK) {
  1453. case MAX_BIT:
  1454. case MAX_BIT|HIGH_BIT:
  1455. case MAX_BIT|NORMAL_BIT:
  1456. case MAX_BIT|LOW_BIT:
  1457. case MAX_BIT|HIGH_BIT|NORMAL_BIT:
  1458. case MAX_BIT|HIGH_BIT|LOW_BIT:
  1459. case MAX_BIT|NORMAL_BIT|LOW_BIT:
  1460. case MAX_BIT|HIGH_BIT|NORMAL_BIT|LOW_BIT:
  1461. for (proc = vrq->procs.prio[PRIORITY_MAX].last;
  1462. proc;
  1463. proc = proc->prev) {
  1464. if (!proc->bound_runq)
  1465. break;
  1466. }
  1467. if (proc)
  1468. break;
  1469. case HIGH_BIT:
  1470. case HIGH_BIT|NORMAL_BIT:
  1471. case HIGH_BIT|LOW_BIT:
  1472. case HIGH_BIT|NORMAL_BIT|LOW_BIT:
  1473. for (proc = vrq->procs.prio[PRIORITY_HIGH].last;
  1474. proc;
  1475. proc = proc->prev) {
  1476. if (!proc->bound_runq)
  1477. break;
  1478. }
  1479. if (proc)
  1480. break;
  1481. case NORMAL_BIT:
  1482. case LOW_BIT:
  1483. case NORMAL_BIT|LOW_BIT:
  1484. for (proc = vrq->procs.prio[PRIORITY_NORMAL].last;
  1485. proc;
  1486. proc = proc->prev) {
  1487. if (!proc->bound_runq)
  1488. break;
  1489. }
  1490. if (proc)
  1491. break;
  1492. case 0:
  1493. proc = NULL;
  1494. break;
  1495. default:
  1496. ASSERT(!"Invalid queue mask");
  1497. proc = NULL;
  1498. break;
  1499. }
  1500. if (proc) {
  1501. ErtsProcLocks proc_locks = 0;
  1502. int res;
  1503. ErtsMigrateResult mres;
  1504. mres = erts_proc_migrate(proc, &proc_locks,
  1505. vrq, &vrq_locked,
  1506. rq, rq_lockedp);
  1507. if (proc_locks)
  1508. erts_smp_proc_unlock(proc, proc_locks);
  1509. res = !0;
  1510. switch (mres) {
  1511. case ERTS_MIGRATE_FAILED_RUNQ_SUSPENDED:
  1512. res = 0;
  1513. case ERTS_MIGRATE_SUCCESS:
  1514. if (vrq_locked)
  1515. erts_smp_runq_unlock(vrq);
  1516. return res;
  1517. default: /* Other failures */
  1518. break;
  1519. }
  1520. }
  1521. ERTS_SMP_LC_CHK_RUNQ_LOCK(rq, *rq_lockedp);
  1522. ERTS_SMP_LC_CHK_RUNQ_LOCK(vrq, vrq_locked);
  1523. if (!vrq_locked) {
  1524. if (*rq_lockedp)
  1525. erts_smp_xrunq_lock(rq, vrq);
  1526. else
  1527. erts_smp_runq_lock(vrq);
  1528. vrq_locked = 1;
  1529. }
  1530. ERTS_SMP_LC_CHK_RUNQ_LOCK(rq, *rq_lockedp);
  1531. ERTS_SMP_LC_CHK_RUNQ_LOCK(vrq, vrq_locked);
  1532. /*
  1533. * Check for a runnable port to steal...
  1534. */
  1535. if (vrq->ports.info.len) {
  1536. Port *prt = vrq->ports.end;
  1537. int prt_locked = 0;
  1538. int res;
  1539. ErtsMigrateResult mres;
  1540. mres = erts_port_migrate(prt, &prt_locked,
  1541. vrq, &vrq_locked,
  1542. rq, rq_lockedp);
  1543. if (prt_locked)
  1544. erts_smp_port_unlock(prt);
  1545. res = !0;
  1546. switch (mres) {
  1547. case ERTS_MIGRATE_FAILED_RUNQ_SUSPENDED:
  1548. res = 0;
  1549. case ERTS_MIGRATE_SUCCESS:
  1550. if (vrq_locked)
  1551. erts_smp_runq_unlock(vrq);
  1552. return res;
  1553. default: /* Other failures */
  1554. break;
  1555. }
  1556. }
  1557. if (vrq_locked)
  1558. erts_smp_runq_unlock(vrq);
  1559. return 0;
  1560. }
  1561. static ERTS_INLINE int
  1562. check_possible_steal_victim(ErtsRunQueue *rq, int *rq_lockedp, int vix)
  1563. {
  1564. ErtsRunQueue *vrq = ERTS_RUNQ_IX(vix);
  1565. erts_aint32_t iflgs = erts_smp_atomic32_read(&vrq->info_flags);
  1566. if (iflgs & ERTS_RUNQ_IFLG_NONEMPTY)
  1567. return try_steal_task_from_victim(rq, rq_lockedp, vrq);
  1568. else
  1569. return 0;
  1570. }
  1571. static int
  1572. try_steal_task(ErtsRunQueue *rq)
  1573. {
  1574. int res, rq_locked, vix, active_rqs, blnc_rqs;
  1575. if (erts_common_run_queue)
  1576. return 0;
  1577. /*
  1578. * We are not allowed to steal jobs to this run queue
  1579. * if it is suspended. Note that it might get suspended
  1580. * at any time when we don't have the lock on the run
  1581. * queue.
  1582. */
  1583. if (rq->flags & ERTS_RUNQ_FLG_SUSPENDED)
  1584. return 0;
  1585. res = 0;
  1586. rq_locked = 1;
  1587. ERTS_SMP_LC_CHK_RUNQ_LOCK(rq, rq_locked);
  1588. active_rqs = erts_smp_atomic32_read(&balance_info.active_runqs);
  1589. blnc_rqs = erts_smp_atomic32_read(&balance_info.used_runqs);
  1590. if (active_rqs > blnc_rqs)
  1591. active_rqs = blnc_rqs;
  1592. if (rq->ix < active_rqs) {
  1593. /* First try to steal from an inactive run queue... */
  1594. if (active_rqs < blnc_rqs) {
  1595. int no = blnc_rqs - active_rqs;
  1596. int stop_ix = vix = active_rqs + rq->ix % no;
  1597. while (erts_smp_atomic32_read(&no_empty_run_queues) < blnc_rqs) {
  1598. res = check_possible_steal_victim(rq, &rq_locked, vix);
  1599. if (res)
  1600. goto done;
  1601. vix++;
  1602. if (vix >= blnc_rqs)
  1603. vix = active_rqs;
  1604. if (vix == stop_ix)
  1605. break;
  1606. }
  1607. }
  1608. vix = rq->ix;
  1609. /* ... then try to steal a job from another active queue... */
  1610. while (erts_smp_atomic32_read(&no_empty_run_queues) < blnc_rqs) {
  1611. vix++;
  1612. if (vix >= active_rqs)
  1613. vix = 0;
  1614. if (vix == rq->ix)
  1615. break;
  1616. res = check_possible_steal_victim(rq, &rq_locked, vix);
  1617. if (res)
  1618. goto done;
  1619. }
  1620. }
  1621. done:
  1622. if (!rq_locked)
  1623. erts_smp_runq_lock(rq);
  1624. if (!res)
  1625. res = !ERTS_EMPTY_RUNQ(rq);
  1626. return res;
  1627. }
  1628. /* Run queue balancing */
  1629. typedef struct {
  1630. Uint32 flags;
  1631. struct {
  1632. int max_len;
  1633. int avail;
  1634. int reds;
  1635. int migration_limit;
  1636. int emigrate_to;
  1637. int immigrate_from;
  1638. } prio[ERTS_NO_PRIO_LEVELS];
  1639. int reds;
  1640. int full_reds;
  1641. int full_reds_history_sum;
  1642. int full_reds_history_change;
  1643. int oowc;
  1644. int max_len;
  1645. } ErtsRunQueueBalance;
  1646. static ErtsRunQueueBalance *run_queue_info;
  1647. typedef struct {
  1648. int qix;
  1649. int len;
  1650. } ErtsRunQueueCompare;
  1651. static ErtsRunQueueCompare *run_queue_compare;
  1652. static int
  1653. rqc_len_cmp(const void *x, const void *y)
  1654. {
  1655. return ((ErtsRunQueueCompare *) x)->len - ((ErtsRunQueueCompare *) y)->len;
  1656. }
  1657. #define ERTS_PERCENT(X, Y) \
  1658. ((Y) == 0 \
  1659. ? ((X) == 0 ? 100 : INT_MAX) \
  1660. : ((100*(X))/(Y)))
  1661. #define ERTS_UPDATE_FULL_REDS(QIX, LAST_REDS) \
  1662. do { \
  1663. run_queue_info[(QIX)].full_reds \
  1664. = run_queue_info[(QIX)].full_reds_history_sum; \
  1665. run_queue_info[(QIX)].full_reds += (LAST_REDS); \
  1666. run_queue_info[(QIX)].full_reds \
  1667. >>= ERTS_FULL_REDS_HISTORY_AVG_SHFT; \
  1668. run_queue_info[(QIX)].full_reds_history_sum \
  1669. -= run_queue_info[(QIX)].full_reds_history_change; \
  1670. run_queue_info[(QIX)].full_reds_history_sum += (LAST_REDS); \
  1671. run_queue_info[(QIX)].full_reds_history_change = (LAST_REDS); \
  1672. } while (0)
  1673. #define ERTS_DBG_CHK_FULL_REDS_HISTORY(RQ) \
  1674. do { \
  1675. int sum__ = 0; \
  1676. int rix__; \
  1677. for (rix__ = 0; rix__ < ERTS_FULL_REDS_HISTORY_SIZE; rix__++) \
  1678. sum__ += (RQ)->full_reds_history[rix__]; \
  1679. ASSERT(sum__ == (RQ)->full_reds_history_sum); \
  1680. } while (0);
  1681. static void
  1682. check_balance(ErtsRunQueue *c_rq)
  1683. {
  1684. #if ERTS_MAX_PROCESSES >= (1 << 27)
  1685. # error check_balance() assumes ERTS_MAX_PROCESS < (1 << 27)
  1686. #endif
  1687. ErtsRunQueueBalance avg = {0};
  1688. Sint64 scheds_reds, full_scheds_reds;
  1689. int forced, active, current_active, oowc, half_full_scheds, full_scheds,
  1690. mmax_len, blnc_no_rqs, qix, pix, freds_hist_ix;
  1691. if (erts_smp_atomic32_xchg(&balance_info.checking_balance, 1)) {
  1692. c_rq->check_balance_reds = INT_MAX;
  1693. return;
  1694. }
  1695. blnc_no_rqs = (int) erts_smp_atomic32_read(&balance_info.used_runqs);
  1696. if (blnc_no_rqs == 1) {
  1697. c_rq->check_balance_reds = INT_MAX;
  1698. erts_smp_atomic32_set(&balance_info.checking_balance, 0);
  1699. return;
  1700. }
  1701. erts_smp_runq_unlock(c_rq);
  1702. if (balance_info.halftime) {
  1703. balance_info.halftime = 0;
  1704. erts_smp_atomic32_set(&balance_info.checking_balance, 0);
  1705. ERTS_FOREACH_RUNQ(rq,
  1706. {
  1707. if (rq->waiting)
  1708. rq->flags |= ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK;
  1709. else
  1710. rq->flags &= ~ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK;
  1711. rq->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS;
  1712. });
  1713. erts_smp_runq_lock(c_rq);
  1714. return;
  1715. }
  1716. /*
  1717. * check_balance() is never called in more threads
  1718. * than one at a time, i.e., we will normally never
  1719. * get any conflicts on the balance_info.update_mtx.
  1720. * However, when blocking multi scheduling (which performance
  1721. * critical applications do *not* do) migration information
  1722. * is manipulated. Such updates of the migration information
  1723. * might clash with balancing.
  1724. */
  1725. erts_smp_mtx_lock(&balance_info.update_mtx);
  1726. forced = balance_info.forced_check_balance;
  1727. balance_info.forced_check_balance = 0;
  1728. blnc_no_rqs = (int) erts_smp_atomic32_read(&balance_info.used_runqs);
  1729. if (blnc_no_rqs == 1) {
  1730. erts_smp_mtx_unlock(&balance_info.update_mtx);
  1731. erts_smp_runq_lock(c_rq);
  1732. c_rq->check_balance_reds = INT_MAX;
  1733. erts_smp_atomic32_set(&balance_info.checking_balance, 0);
  1734. return;
  1735. }
  1736. freds_hist_ix = balance_info.full_reds_history_index;
  1737. balance_info.full_reds_history_index++;
  1738. if (balance_info.full_reds_history_index >= ERTS_FULL_REDS_HISTORY_SIZE)
  1739. balance_info.full_reds_history_index = 0;
  1740. current_active = erts_smp_atomic32_read(&balance_info.active_runqs);
  1741. /* Read balance information for all run queues */
  1742. for (qix = 0; qix < blnc_no_rqs; qix++) {
  1743. ErtsRunQueue *rq = ERTS_RUNQ_IX(qix);
  1744. erts_smp_runq_lock(rq);
  1745. run_queue_info[qix].flags = rq->flags;
  1746. for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) {
  1747. run_queue_info[qix].prio[pix].max_len
  1748. = rq->procs.prio_info[pix].max_len;
  1749. run_queue_info[qix].prio[pix].reds
  1750. = rq->procs.prio_info[pix].reds;
  1751. }
  1752. run_queue_info[qix].prio[ERTS_PORT_PRIO_LEVEL].max_len
  1753. = rq->ports.info.max_len;
  1754. run_queue_info[qix].prio[ERTS_PORT_PRIO_LEVEL].reds
  1755. = rq->ports.info.reds;
  1756. run_queue_info[qix].full_reds_history_sum
  1757. = rq->full_reds_history_sum;
  1758. run_queue_info[qix].full_reds_history_change
  1759. = rq->full_reds_history[freds_hist_ix];
  1760. run_queue_info[qix].oowc = rq->out_of_work_count;
  1761. run_queue_info[qix].max_len = rq->max_len;
  1762. rq->check_balance_reds = INT_MAX;
  1763. erts_smp_runq_unlock(rq);
  1764. }
  1765. full_scheds = 0;
  1766. half_full_scheds = 0;
  1767. full_scheds_reds = 0;
  1768. scheds_reds = 0;
  1769. oowc = 0;
  1770. mmax_len = 0;
  1771. /* Calculate availability for each priority in each run queues */
  1772. for (qix = 0; qix < blnc_no_rqs; qix++) {
  1773. int treds = 0;
  1774. if (run_queue_info[qix].flags & ERTS_RUNQ_FLG_OUT_OF_WORK) {
  1775. for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) {
  1776. run_queue_info[qix].prio[pix].avail = 100;
  1777. treds += run_queue_info[qix].prio[pix].reds;
  1778. }
  1779. if (!(run_queue_info[qix].flags & ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK))
  1780. half_full_scheds++;
  1781. ERTS_UPDATE_FULL_REDS(qix, ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED);
  1782. }
  1783. else {
  1784. ASSERT(!(run_queue_info[qix].flags & ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK));
  1785. for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++)
  1786. treds += run_queue_info[qix].prio[pix].reds;
  1787. if (treds == 0) {
  1788. for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++)
  1789. run_queue_info[qix].prio[pix].avail = 0;
  1790. }
  1791. else {
  1792. Sint64 xreds = 0;
  1793. Sint64 procreds = treds;
  1794. procreds -=
  1795. ((Sint64)
  1796. run_queue_info[qix].prio[ERTS_PORT_PRIO_LEVEL].reds);
  1797. for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) {
  1798. Sint64 av;
  1799. if (xreds == 0)
  1800. av = 100;
  1801. else if (procreds == xreds)
  1802. av = 0;
  1803. else {
  1804. av = (100*(procreds - xreds)) / procreds;
  1805. if (av == 0)
  1806. av = 1;
  1807. }
  1808. run_queue_info[qix].prio[pix].avail = (int) av;
  1809. ASSERT(run_queue_info[qix].prio[pix].avail >= 0);
  1810. if (pix < PRIORITY_NORMAL) /* ie., max or high */
  1811. xreds += (Sint64) run_queue_info[qix].prio[pix].reds;
  1812. }
  1813. run_queue_info[qix].prio[ERTS_PORT_PRIO_LEVEL].avail = 100;
  1814. }
  1815. ERTS_UPDATE_FULL_REDS(qix, treds);
  1816. full_scheds_reds += run_queue_info[qix].full_reds;
  1817. full_scheds++;
  1818. half_full_scheds++;
  1819. }
  1820. run_queue_info[qix].reds = treds;
  1821. scheds_reds += treds;
  1822. oowc += run_queue_info[qix].oowc;
  1823. if (mmax_len < run_queue_info[qix].max_len)
  1824. mmax_len = run_queue_info[qix].max_len;
  1825. }
  1826. if (!forced && half_full_scheds != blnc_no_rqs) {
  1827. int min = 1;
  1828. if (min < half_full_scheds)
  1829. min = half_full_scheds;
  1830. if (full_scheds) {
  1831. active = (scheds_reds - 1)/ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED+1;
  1832. }
  1833. else {
  1834. active = balance_info.last_active_runqs - 1;
  1835. }
  1836. if (balance_info.last_active_runqs < current_active) {
  1837. ERTS_BLNCE_SAVE_RISE(current_active, mmax_len, scheds_reds);
  1838. active = current_active;
  1839. }
  1840. else if (active < balance_info.prev_rise.active_runqs) {
  1841. if (ERTS_PERCENT(mmax_len,
  1842. balance_info.prev_rise.max_len) >= 90
  1843. && ERTS_PERCENT(scheds_reds,
  1844. balance_info.prev_rise.reds) >= 90) {
  1845. active = balance_info.prev_rise.active_runqs;
  1846. }
  1847. }
  1848. if (active < min)
  1849. active = min;
  1850. else if (active > blnc_no_rqs)
  1851. active = blnc_no_rqs;
  1852. if (active == blnc_no_rqs)
  1853. goto all_active;
  1854. for (qix = 0; qix < active; qix++) {
  1855. run_queue_info[qix].flags = 0;
  1856. for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) {
  1857. run_queue_info[qix].prio[pix].emigrate_to = -1;
  1858. run_queue_info[qix].prio[pix].immigrate_from = -1;
  1859. run_queue_info[qix].prio[pix].migration_limit = 0;
  1860. }
  1861. }
  1862. for (qix = active; qix < blnc_no_rqs; qix++) {
  1863. run_queue_info[qix].flags = ERTS_RUNQ_FLG_INACTIVE;
  1864. for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) {
  1865. int tix = qix % active;
  1866. ERTS_SET_RUNQ_FLG_EMIGRATE(run_queue_info[qix].flags, pix);
  1867. run_queue_info[qix].prio[pix].emigrate_to = tix;
  1868. run_queue_info[qix].prio[pix].immigrate_from = -1;
  1869. run_queue_info[qix].prio[pix].migration_limit = 0;
  1870. }
  1871. }
  1872. }
  1873. else {
  1874. if (balance_info.last_active_runqs < current_active)
  1875. ERTS_BLNCE_SAVE_RISE(current_active, mmax_len, scheds_reds);
  1876. all_active:
  1877. active = blnc_no_rqs;
  1878. for (qix = 0; qix < blnc_no_rqs; qix++) {
  1879. if (full_scheds_reds > 0) {
  1880. /* Calculate availability compared to other schedulers */
  1881. if (!(run_queue_info[qix].flags & ERTS_RUNQ_FLG_OUT_OF_WORK)) {
  1882. Sint64 tmp = ((Sint64) run_queue_info[qix].full_reds
  1883. * (Sint64) full_scheds);
  1884. for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) {
  1885. Sint64 avail = run_queue_info[qix].prio[pix].avail;
  1886. avail = (avail*tmp)/full_scheds_reds;
  1887. ASSERT(avail >= 0);
  1888. run_queue_info[qix].prio[pix].avail = (int) avail;
  1889. }
  1890. }
  1891. }
  1892. /* Calculate average max length */
  1893. for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) {
  1894. run_queue_info[qix].prio[pix].emigrate_to = -1;
  1895. run_queue_info[qix].prio[pix].immigrate_from = -1;
  1896. avg.prio[pix].max_len += run_queue_info[qix].prio[pix].max_len;
  1897. avg.prio[pix].avail += run_queue_info[qix].prio[pix].avail;
  1898. }
  1899. }
  1900. for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) {
  1901. int max_len = avg.prio[pix].max_len;
  1902. if (max_len != 0) {
  1903. int avail = avg.prio[pix].avail;
  1904. if (avail != 0) {
  1905. max_len = (int) ((100*((Sint64) max_len) - 1)
  1906. / ((Sint64) avail)) + 1;
  1907. avg.prio[pix].max_len = max_len;
  1908. ASSERT(max_len >= 0);
  1909. }
  1910. }
  1911. }
  1912. /* Calculate migration limits for all priority queues in all
  1913. run queues */
  1914. for (qix = 0; qix < blnc_no_rqs; qix++) {
  1915. run_queue_info[qix].flags = 0; /* Reset for later use... */
  1916. for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) {
  1917. int limit;
  1918. if (avg.prio[pix].max_len == 0
  1919. || run_queue_info[qix].prio[pix].avail == 0)
  1920. limit = 0;
  1921. else
  1922. limit = (int) (((((Sint64) avg.prio[pix].max_len)
  1923. * ((Sint64) run_queue_info[qix].prio[pix].avail))
  1924. - 1)
  1925. / 100 + 1);
  1926. run_queue_info[qix].prio[pix].migration_limit = limit;
  1927. }
  1928. }
  1929. /* Setup migration paths for all priorities */
  1930. for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) {
  1931. int low = 0, high = 0;
  1932. for (qix = 0; qix < blnc_no_rqs; qix++) {
  1933. int len_diff = run_queue_info[qix].prio[pix].max_len;
  1934. len_diff -= run_queue_info[qix].prio[pix].migration_limit;
  1935. #ifdef DBG_PRINT
  1936. if (pix == 2) erts_fprintf(stderr, "%d ", len_diff);
  1937. #endif
  1938. run_queue_compare[qix].qix = qix;
  1939. run_queue_compare[qix].len = len_diff;
  1940. if (len_diff != 0) {
  1941. if (len_diff < 0)
  1942. low++;
  1943. else
  1944. high++;
  1945. }
  1946. }
  1947. #ifdef DBG_PRINT
  1948. if (pix == 2) erts_fprintf(stderr, "\n");
  1949. #endif
  1950. if (low && high) {
  1951. int from_qix;
  1952. int to_qix;
  1953. int eof = 0;
  1954. int eot = 0;
  1955. int tix = 0;
  1956. int fix = blnc_no_rqs-1;
  1957. qsort(run_queue_compare,
  1958. blnc_no_rqs,
  1959. sizeof(ErtsRunQueueCompare),
  1960. rqc_len_cmp);
  1961. while (1) {
  1962. if (run_queue_compare[fix].len <= 0)
  1963. eof = 1;
  1964. if (run_queue_compare[tix].len >= 0)
  1965. eot = 1;
  1966. if (eof || eot)
  1967. break;
  1968. from_qix = run_queue_compare[fix].qix;
  1969. to_qix = run_queue_compare[tix].qix;
  1970. if (run_queue_info[from_qix].prio[pix].avail == 0) {
  1971. ERTS_SET_RUNQ_FLG_EVACUATE(run_queue_info[from_qix].flags,
  1972. pix);
  1973. ERTS_SET_RUNQ_FLG_EVACUATE(run_queue_info[to_qix].flags,
  1974. pix);
  1975. }
  1976. ERTS_SET_RUNQ_FLG_EMIGRATE(run_queue_info[from_qix].flags, pix);
  1977. ERTS_SET_RUNQ_FLG_IMMIGRATE(run_queue_info[to_qix].flags, pix);
  1978. run_queue_info[from_qix].prio[pix].emigrate_to = to_qix;
  1979. run_queue_info[to_qix].prio[pix].immigrate_from = from_qix;
  1980. tix++;
  1981. fix--;
  1982. #ifdef DBG_PRINT
  1983. if (pix == 2) erts_fprintf(stderr, "%d >--> %d\n", from_qix, to_qix);
  1984. #endif
  1985. }
  1986. if (!eot && eof) {
  1987. if (fix < blnc_no_rqs-1)
  1988. fix++;
  1989. if (run_queue_compare[fix].len > 0) {
  1990. int fix2 = -1;
  1991. while (tix < fix) {
  1992. if (run_queue_compare[tix].len >= 0)
  1993. break;
  1994. if (fix2 < fix)
  1995. fix2 = blnc_no_rqs-1;
  1996. from_qix = run_queue_compare[fix2].qix;
  1997. to_qix = run_queue_compare[tix].qix;
  1998. ASSERT(to_qix != from_qix);
  1999. if (run_queue_info[from_qix].prio[pix].avail == 0)
  2000. ERTS_SET_RUNQ_FLG_EVACUATE(run_queue_info[to_qix].flags,
  2001. pix);
  2002. ERTS_SET_RUNQ_FLG_IMMIGRATE(run_queue_info[to_qix].flags, pix);
  2003. run_queue_info[to_qix].prio[pix].immigrate_from = from_qix;
  2004. tix++;
  2005. fix2--;
  2006. #ifdef DBG_PRINT
  2007. if (pix == 2) erts_fprintf(stderr, "%d --> %d\n", from_qix, to_qix);
  2008. #endif
  2009. }
  2010. }
  2011. }
  2012. else if (!eof && eot) {
  2013. if (tix > 0)
  2014. tix--;
  2015. if (run_queue_compare[tix].len < 0) {
  2016. int tix2 = 0;
  2017. while (tix < fix) {
  2018. if (run_queue_compare[fix].len <= 0)
  2019. break;
  2020. if (tix2 > tix)
  2021. tix2 = 0;
  2022. from_qix = run_queue_compare[fix].qix;
  2023. to_qix = run_queue_compare[tix2].qix;
  2024. ASSERT(to_qix != from_qix);
  2025. if (run_queue_info[from_qix].prio[pix].avail == 0)
  2026. ERTS_SET_RUNQ_FLG_EVACUATE(run_queue_info[from_qix].flags,
  2027. pix);
  2028. ERTS_SET_RUNQ_FLG_EMIGRATE(run_queue_info[from_qix].flags, pix);
  2029. run_queue_info[from_qix].prio[pix].emigrate_to = to_qix;
  2030. fix--;
  2031. tix2++;
  2032. #ifdef DBG_PRINT
  2033. if (pix == 2) erts_fprintf(stderr, "%d >-- %d\n", from_qix, to_qix);
  2034. #endif
  2035. }
  2036. }
  2037. }
  2038. }
  2039. }
  2040. #ifdef DBG_PRINT
  2041. erts_fprintf(stderr, "--------------------------------\n");
  2042. #endif
  2043. }
  2044. balance_info.last_active_runqs = active;
  2045. erts_smp_atomic32_set(&balance_info.active_runqs, active);
  2046. balance_info.halftime = 1;
  2047. erts_smp_atomic32_set(&balance_info.checking_balance, 0);
  2048. /* Write migration paths and reset balance statistics in all queues */
  2049. for (qix = 0; qix < blnc_no_rqs; qix++) {
  2050. int mqix;
  2051. Uint32 flags;
  2052. ErtsRunQueue *rq = ERTS_RUNQ_IX(qix);
  2053. ErtsRunQueueInfo *rqi;
  2054. flags = run_queue_info[qix].flags;
  2055. erts_smp_runq_lock(rq);
  2056. flags |= (rq->flags & ~ERTS_RUNQ_FLGS_MIGRATION_INFO);
  2057. ASSERT(!(flags & ERTS_RUNQ_FLG_OUT_OF_WORK));
  2058. if (rq->waiting)
  2059. flags |= ERTS_RUNQ_FLG_OUT_OF_WORK;
  2060. rq->full_reds_history_sum
  2061. = run_queue_info[qix].full_reds_history_sum;
  2062. rq->full_reds_history[freds_hist_ix]
  2063. = run_queue_info[qix].full_reds_history_change;
  2064. ERTS_DBG_CHK_FULL_REDS_HISTORY(rq);
  2065. rq->out_of_work_count = 0;
  2066. rq->flags = flags;
  2067. rq->max_len = rq->len;
  2068. for (pix = 0; pix < ERTS_NO_PRIO_LEVELS; pix++) {
  2069. rqi = (pix == ERTS_PORT_PRIO_LEVEL
  2070. ? &rq->ports.info
  2071. : &rq->procs.prio_info[pix]);
  2072. rqi->max_len = rqi->len;
  2073. rqi->reds = 0;
  2074. if (!(ERTS_CHK_RUNQ_FLG_EMIGRATE(flags, pix)
  2075. | ERTS_CHK_RUNQ_FLG_IMMIGRATE(flags, pix))) {
  2076. ASSERT(run_queue_info[qix].prio[pix].immigrate_from < 0);
  2077. ASSERT(run_queue_info[qix].prio[pix].emigrate_to < 0);
  2078. #ifdef DEBUG
  2079. rqi->migrate.limit.this = -1;
  2080. rqi->migrate.limit.other = -1;
  2081. ERTS_DBG_SET_INVALID_RUNQP(rqi->migrate.runq, 0x2);
  2082. #endif
  2083. }
  2084. else if (ERTS_CHK_RUNQ_FLG_EMIGRATE(flags, pix)) {
  2085. ASSERT(!ERTS_CHK_RUNQ_FLG_IMMIGRATE(flags, pix));
  2086. ASSERT(run_queue_info[qix].prio[pix].immigrate_from < 0);
  2087. ASSERT(run_queue_info[qix].prio[pix].emigrate_to >= 0);
  2088. mqix = run_queue_info[qix].prio[pix].emigrate_to;
  2089. rqi->migrate.limit.this
  2090. = run_queue_info[qix].prio[pix].migration_limit;
  2091. rqi->migrate.limit.other
  2092. = run_queue_info[mqix].prio[pix].migration_limit;
  2093. rqi->migrate.runq = ERTS_RUNQ_IX(mqix);
  2094. }
  2095. else {
  2096. ASSERT(ERTS_CHK_RUNQ_FLG_IMMIGRATE(flags, pix));
  2097. ASSERT(run_queue_info[qix].prio[pix].emigrate_to < 0);
  2098. ASSERT(run_queue_info[qix].prio[pix].immigrate_from >= 0);
  2099. mqix = run_queue_info[qix].prio[pix].immigrate_from;
  2100. rqi->migrate.limit.this
  2101. = run_queue_info[qix].prio[pix].migration_limit;
  2102. rqi->migrate.limit.other
  2103. = run_queue_info[mqix].prio[pix].migration_limit;
  2104. rqi->migrate.runq = ERTS_RUNQ_IX(mqix);
  2105. }
  2106. }
  2107. rq->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS;
  2108. erts_smp_runq_unlock(rq);
  2109. }
  2110. balance_info.n++;
  2111. erts_smp_mtx_unlock(&balance_info.update_mtx);
  2112. erts_smp_runq_lock(c_rq);
  2113. }
  2114. #endif /* #ifdef ERTS_SMP */
  2115. Uint
  2116. erts_debug_nbalance(void)
  2117. {
  2118. #ifdef ERTS_SMP
  2119. Uint n;
  2120. erts_smp_mtx_lock(&balance_info.update_mtx);
  2121. n = balance_info.n;
  2122. erts_smp_mtx_unlock(&balance_info.update_mtx);
  2123. return n;
  2124. #else
  2125. return 0;
  2126. #endif
  2127. }
  2128. void
  2129. erts_early_init_scheduling(void)
  2130. {
  2131. wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM;
  2132. }
  2133. int
  2134. erts_sched_set_wakeup_limit(char *str)
  2135. {
  2136. if (sys_strcmp(str, "very_high") == 0)
  2137. wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH;
  2138. else if (sys_strcmp(str, "high") == 0)
  2139. wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_HIGH;
  2140. else if (sys_strcmp(str, "medium") == 0)
  2141. wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_MEDIUM;
  2142. else if (sys_strcmp(str, "low") == 0)
  2143. wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_LOW;
  2144. else if (sys_strcmp(str, "very_low") == 0)
  2145. wakeup_other_limit = ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW;
  2146. else
  2147. return EINVAL;
  2148. return 0;
  2149. }
  2150. void
  2151. erts_init_scheduling(int mrq, int no_schedulers, int no_schedulers_online)
  2152. {
  2153. int ix, n;
  2154. #ifndef ERTS_SMP
  2155. mrq = 0;
  2156. #endif
  2157. init_misc_op_list_alloc();
  2158. ASSERT(no_schedulers_online <= no_schedulers);
  2159. ASSERT(no_schedulers_online >= 1);
  2160. ASSERT(no_schedulers >= 1);
  2161. /* Create and initialize run queues */
  2162. n = (int) (mrq ? no_schedulers : 1);
  2163. erts_aligned_run_queues = erts_alloc(ERTS_ALC_T_RUNQS,
  2164. (sizeof(ErtsAlignedRunQueue)*(n+1)));
  2165. if ((((UWord) erts_aligned_run_queues) & ERTS_CACHE_LINE_MASK) != 0)
  2166. erts_aligned_run_queues = ((ErtsAlignedRunQueue *)
  2167. ((((UWord) erts_aligned_run_queues)
  2168. & ~ERTS_CACHE_LINE_MASK)
  2169. + ERTS_CACHE_LINE_SIZE));
  2170. ASSERT((((UWord) erts_aligned_run_queues) & ERTS_CACHE_LINE_MASK) == 0);
  2171. #ifdef ERTS_SMP
  2172. erts_smp_atomic32_init(&no_empty_run_queues, 0);
  2173. #endif
  2174. erts_no_run_queues = n;
  2175. for (ix = 0; ix < n; ix++) {
  2176. int pix, rix;
  2177. ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
  2178. rq->ix = ix;
  2179. erts_smp_atomic32_init(&rq->info_flags, ERTS_RUNQ_IFLG_NONEMPTY);
  2180. /* make sure that the "extra" id correponds to the schedulers
  2181. * id if the esdp->no <-> ix+1 mapping change.
  2182. */
  2183. erts_smp_mtx_init_x(&rq->mtx, "run_queue", make_small(ix + 1));
  2184. erts_smp_cnd_init(&rq->cnd);
  2185. #ifdef ERTS_SMP
  2186. erts_smp_spinlock_init(&rq->sleepers.lock, "run_queue_sleep_list");
  2187. rq->sleepers.list = NULL;
  2188. #endif
  2189. rq->waiting = 0;
  2190. rq->woken = 0;
  2191. rq->flags = !mrq ? ERTS_RUNQ_FLG_SHARED_RUNQ : 0;
  2192. rq->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS;
  2193. rq->full_reds_history_sum = 0;
  2194. for (rix = 0; rix < ERTS_FULL_REDS_HISTORY_SIZE; rix++) {
  2195. rq->full_reds_history_sum += ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED;
  2196. rq->full_reds_history[rix] = ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED;
  2197. }
  2198. rq->out_of_work_count = 0;
  2199. rq->max_len = 0;
  2200. rq->len = 0;
  2201. rq->wakeup_other = 0;
  2202. rq->wakeup_other_reds = 0;
  2203. rq->procs.len = 0;
  2204. rq->procs.pending_exiters = NULL;
  2205. rq->procs.context_switches = 0;
  2206. rq->procs.reductions = 0;
  2207. for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) {
  2208. rq->procs.prio_info[pix].len = 0;
  2209. rq->procs.prio_info[pix].max_len = 0;
  2210. rq->procs.prio_info[pix].reds = 0;
  2211. rq->procs.prio_info[pix].migrate.limit.this = 0;
  2212. rq->procs.prio_info[pix].migrate.limit.other = 0;
  2213. ERTS_DBG_SET_INVALID_RUNQP(rq->procs.prio_info[pix].migrate.runq,
  2214. 0x0);
  2215. if (pix < ERTS_NO_PROC_PRIO_LEVELS - 1) {
  2216. rq->procs.prio[pix].first = NULL;
  2217. rq->procs.prio[pix].last = NULL;
  2218. }
  2219. }
  2220. rq->misc.start = NULL;
  2221. rq->misc.end = NULL;
  2222. rq->misc.evac_runq = NULL;
  2223. rq->ports.info.len = 0;
  2224. rq->ports.info.max_len = 0;
  2225. rq->ports.info.reds = 0;
  2226. rq->ports.info.migrate.limit.this = 0;
  2227. rq->ports.info.migrate.limit.other = 0;
  2228. rq->ports.info.migrate.runq = NULL;
  2229. rq->ports.start = NULL;
  2230. rq->ports.end = NULL;
  2231. }
  2232. erts_common_run_queue = !mrq ? ERTS_RUNQ_IX(0) : NULL;
  2233. #ifdef ERTS_SMP
  2234. if (erts_no_run_queues != 1) {
  2235. run_queue_info = erts_alloc(ERTS_ALC_T_RUNQ_BLNS,
  2236. (sizeof(ErtsRunQueueBalance)
  2237. * erts_no_run_queues));
  2238. run_queue_compare = erts_alloc(ERTS_ALC_T_RUNQ_BLNS,
  2239. (sizeof(ErtsRunQueueCompare)
  2240. * erts_no_run_queues));
  2241. }
  2242. #endif
  2243. n = (int) no_schedulers;
  2244. erts_no_schedulers = n;
  2245. #ifdef ERTS_SMP
  2246. /* Create and initialize scheduler sleep info */
  2247. aligned_sched_sleep_info = erts_alloc(ERTS_ALC_T_SCHDLR_SLP_INFO,
  2248. (sizeof(ErtsAlignedSchedulerSleepInfo)
  2249. *(n+1)));
  2250. if ((((UWord) aligned_sched_sleep_info) & ERTS_CACHE_LINE_MASK) == 0)
  2251. aligned_sched_sleep_info = ((ErtsAlignedSchedulerSleepInfo *)
  2252. ((((UWord) aligned_sched_sleep_info)
  2253. & ~ERTS_CACHE_LINE_MASK)
  2254. + ERTS_CACHE_LINE_SIZE));
  2255. for (ix = 0; ix < n; ix++) {
  2256. ErtsSchedulerSleepInfo *ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
  2257. #if 0 /* no need to initialize these... */
  2258. ssi->next = NULL;
  2259. ssi->prev = NULL;
  2260. #endif
  2261. erts_smp_atomic32_init(&ssi->flags, 0);
  2262. ssi->event = NULL; /* initialized in sched_thread_func */
  2263. erts_smp_atomic32_init(&ssi->aux_work, 0);
  2264. }
  2265. #endif
  2266. /* Create and initialize scheduler specific data */
  2267. erts_aligned_scheduler_data = erts_alloc(ERTS_ALC_T_SCHDLR_DATA,
  2268. (sizeof(ErtsAlignedSchedulerData)
  2269. *(n+1)));
  2270. if ((((UWord) erts_aligned_scheduler_data) & ERTS_CACHE_LINE_MASK) != 0)
  2271. erts_aligned_scheduler_data = ((ErtsAlignedSchedulerData *)
  2272. ((((UWord) erts_aligned_scheduler_data)
  2273. & ~ERTS_CACHE_LINE_MASK)
  2274. + ERTS_CACHE_LINE_SIZE));
  2275. ASSERT((((UWord) erts_aligned_scheduler_data) & ERTS_CACHE_LINE_MASK) == 0);
  2276. for (ix = 0; ix < n; ix++) {
  2277. ErtsSchedulerData *esdp = ERTS_SCHEDULER_IX(ix);
  2278. #ifdef ERTS_SMP
  2279. erts_bits_init_state(&esdp->erl_bits_state);
  2280. esdp->match_pseudo_process = NULL;
  2281. esdp->ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
  2282. esdp->free_process = NULL;
  2283. #if HALFWORD_HEAP
  2284. /* Registers need to be heap allocated (correct memory range) for tracing to work */
  2285. esdp->save_reg = erts_alloc(ERTS_ALC_T_BEAM_REGISTER, ERTS_X_REGS_ALLOCATED * sizeof(Eterm));
  2286. #endif
  2287. #endif
  2288. #if !HEAP_ON_C_STACK
  2289. esdp->num_tmp_heap_used = 0;
  2290. #endif
  2291. esdp->no = (Uint) ix+1;
  2292. esdp->current_process = NULL;
  2293. esdp->current_port = NULL;
  2294. esdp->virtual_reds = 0;
  2295. esdp->cpu_id = -1;
  2296. erts_init_atom_cache_map(&esdp->atom_cache_map);
  2297. if (erts_common_run_queue) {
  2298. esdp->run_queue = erts_common_run_queue;
  2299. esdp->run_queue->scheduler = NULL;
  2300. }
  2301. else {
  2302. esdp->run_queue = ERTS_RUNQ_IX(ix);
  2303. esdp->run_queue->scheduler = esdp;
  2304. }
  2305. #ifdef ERTS_SMP
  2306. erts_smp_atomic32_init(&esdp->chk_cpu_bind, 0);
  2307. #endif
  2308. }
  2309. #ifdef ERTS_SMP
  2310. erts_smp_mtx_init(&schdlr_sspnd.mtx, "schdlr_sspnd");
  2311. erts_smp_cnd_init(&schdlr_sspnd.cnd);
  2312. erts_smp_atomic32_init(&schdlr_sspnd.changing, 0);
  2313. schdlr_sspnd.online = no_schedulers_online;
  2314. schdlr_sspnd.curr_online = no_schedulers;
  2315. erts_smp_atomic32_init(&schdlr_sspnd.msb.ongoing, 0);
  2316. erts_smp_atomic32_init(&schdlr_sspnd.active, no_schedulers);
  2317. schdlr_sspnd.msb.procs = NULL;
  2318. erts_smp_atomic32_set(&balance_info.used_runqs,
  2319. erts_common_run_queue ? 1 : no_schedulers_online);
  2320. erts_smp_atomic32_init(&balance_info.active_runqs, no_schedulers);
  2321. balance_info.last_active_runqs = no_schedulers;
  2322. erts_smp_mtx_init(&balance_info.update_mtx, "migration_info_update");
  2323. balance_info.forced_check_balance = 0;
  2324. balance_info.halftime = 1;
  2325. balance_info.full_reds_history_index = 0;
  2326. erts_smp_atomic32_init(&balance_info.checking_balance, 0);
  2327. balance_info.prev_rise.active_runqs = 0;
  2328. balance_info.prev_rise.max_len = 0;
  2329. balance_info.prev_rise.reds = 0;
  2330. balance_info.n = 0;
  2331. if (no_schedulers_online < no_schedulers) {
  2332. if (erts_common_run_queue) {
  2333. for (ix = no_schedulers_online; ix < no_schedulers; ix++)
  2334. erts_smp_atomic32_bor(&ERTS_SCHED_SLEEP_INFO_IX(ix)->flags,
  2335. ERTS_SSI_FLG_SUSPENDED);
  2336. }
  2337. else {
  2338. for (ix = no_schedulers_online; ix < erts_no_run_queues; ix++)
  2339. evacuate_run_queue(ERTS_RUNQ_IX(ix),
  2340. ERTS_RUNQ_IX(ix % no_schedulers_online));
  2341. }
  2342. }
  2343. schdlr_sspnd.wait_curr_online = no_schedulers_online;
  2344. schdlr_sspnd.curr_online *= 2; /* Boot strapping... */
  2345. ERTS_SCHDLR_SSPND_CHNG_SET((ERTS_SCHDLR_SSPND_CHNG_ONLN
  2346. | ERTS_SCHDLR_SSPND_CHNG_WAITER), 0);
  2347. erts_smp_atomic32_init(&doing_sys_schedule, 0);
  2348. init_misc_aux_work();
  2349. #else /* !ERTS_SMP */
  2350. {
  2351. ErtsSchedulerData *esdp;
  2352. esdp = ERTS_SCHEDULER_IX(0);
  2353. erts_scheduler_data = esdp;
  2354. #ifdef USE_THREADS
  2355. erts_tsd_set(sched_data_key, (void *) esdp);
  2356. #endif
  2357. }
  2358. erts_no_schedulers = 1;
  2359. #endif
  2360. erts_smp_atomic32_init(&function_calls, 0);
  2361. /* init port tasks */
  2362. erts_port_task_init();
  2363. #ifndef ERTS_SMP
  2364. #ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC
  2365. erts_scheduler_data->verify_unused_temp_alloc
  2366. = erts_alloc_get_verify_unused_temp_alloc(
  2367. &erts_scheduler_data->verify_unused_temp_alloc_data);
  2368. ERTS_VERIFY_UNUSED_TEMP_ALLOC(NULL);
  2369. #endif
  2370. #endif
  2371. }
  2372. ErtsRunQueue *
  2373. erts_schedid2runq(Uint id)
  2374. {
  2375. int ix;
  2376. if (erts_common_run_queue)
  2377. return erts_common_run_queue;
  2378. ix = (int) id - 1;
  2379. ASSERT(0 <= ix && ix < erts_no_run_queues);
  2380. return ERTS_RUNQ_IX(ix);
  2381. }
  2382. #ifdef USE_THREADS
  2383. ErtsSchedulerData *
  2384. erts_get_scheduler_data(void)
  2385. {
  2386. return (ErtsSchedulerData *) erts_tsd_get(sched_data_key);
  2387. }
  2388. #endif
  2389. static int remove_proc_from_runq(ErtsRunQueue *rq, Process *p, int to_inactive);
  2390. static ERTS_INLINE void
  2391. suspend_process(ErtsRunQueue *rq, Process *p)
  2392. {
  2393. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
  2394. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  2395. p->rcount++; /* count number of suspend */
  2396. #ifdef ERTS_SMP
  2397. ASSERT(!(p->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING)
  2398. || p == erts_get_current_process());
  2399. ASSERT(p->status != P_RUNNING
  2400. || p->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING);
  2401. if (p->status_flags & ERTS_PROC_SFLG_PENDADD2SCHEDQ)
  2402. goto runable;
  2403. #endif
  2404. switch(p->status) {
  2405. case P_SUSPENDED:
  2406. break;
  2407. case P_RUNABLE:
  2408. #ifdef ERTS_SMP
  2409. runable:
  2410. if (!ERTS_PROC_PENDING_EXIT(p))
  2411. #endif
  2412. remove_proc_from_runq(rq, p, 1);
  2413. /* else:
  2414. * leave process in schedq so it will discover the pending exit
  2415. */
  2416. p->rstatus = P_RUNABLE; /* wakeup as runnable */
  2417. break;
  2418. case P_RUNNING:
  2419. p->rstatus = P_RUNABLE; /* wakeup as runnable */
  2420. break;
  2421. case P_WAITING:
  2422. p->rstatus = P_WAITING; /* wakeup as waiting */
  2423. break;
  2424. case P_EXITING:
  2425. return; /* ignore this */
  2426. case P_GARBING:
  2427. case P_FREE:
  2428. erl_exit(1, "bad state in suspend_process()\n");
  2429. }
  2430. if ((erts_system_profile_flags.runnable_procs) && (p->rcount == 1) && (p->status != P_WAITING)) {
  2431. profile_runnable_proc(p, am_inactive);
  2432. }
  2433. p->status = P_SUSPENDED;
  2434. }
  2435. static ERTS_INLINE void
  2436. resume_process(Process *p)
  2437. {
  2438. Uint32 *statusp;
  2439. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
  2440. switch (p->status) {
  2441. case P_SUSPENDED:
  2442. statusp = &p->status;
  2443. break;
  2444. case P_GARBING:
  2445. if (p->gcstatus == P_SUSPENDED) {
  2446. statusp = &p->gcstatus;
  2447. break;
  2448. }
  2449. /* Fall through */
  2450. default:
  2451. return;
  2452. }
  2453. ASSERT(p->rcount > 0);
  2454. if (--p->rcount > 0) /* multiple suspend */
  2455. return;
  2456. switch(p->rstatus) {
  2457. case P_RUNABLE:
  2458. *statusp = P_WAITING; /* make erts_add_to_runq work */
  2459. erts_add_to_runq(p);
  2460. break;
  2461. case P_WAITING:
  2462. *statusp = P_WAITING;
  2463. break;
  2464. default:
  2465. erl_exit(1, "bad state in resume_process()\n");
  2466. }
  2467. p->rstatus = P_FREE;
  2468. }
  2469. int
  2470. erts_get_max_no_executing_schedulers(void)
  2471. {
  2472. #ifdef ERTS_SMP
  2473. if (erts_smp_atomic32_read(&schdlr_sspnd.changing))
  2474. return (int) erts_no_schedulers;
  2475. ERTS_THR_MEMORY_BARRIER;
  2476. return (int) erts_smp_atomic32_read(&schdlr_sspnd.active);
  2477. #else
  2478. return 1;
  2479. #endif
  2480. }
  2481. #ifdef ERTS_SMP
  2482. static void
  2483. susp_sched_prep_block(void *unused)
  2484. {
  2485. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  2486. }
  2487. static void
  2488. susp_sched_resume_block(void *unused)
  2489. {
  2490. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  2491. }
  2492. static void
  2493. scheduler_ix_resume_wake(Uint ix)
  2494. {
  2495. ErtsSchedulerSleepInfo *ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
  2496. erts_aint32_t xflgs = (ERTS_SSI_FLG_SLEEPING
  2497. | ERTS_SSI_FLG_TSE_SLEEPING
  2498. | ERTS_SSI_FLG_WAITING
  2499. | ERTS_SSI_FLG_SUSPENDED);
  2500. erts_aint32_t oflgs;
  2501. do {
  2502. oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, 0, xflgs);
  2503. if (oflgs == xflgs) {
  2504. erts_sched_finish_poke(ssi, oflgs);
  2505. break;
  2506. }
  2507. xflgs = oflgs;
  2508. } while (oflgs & ERTS_SSI_FLG_SUSPENDED);
  2509. }
  2510. static erts_aint32_t
  2511. sched_prep_spin_suspended(ErtsSchedulerSleepInfo *ssi, erts_aint32_t xpct)
  2512. {
  2513. erts_aint32_t oflgs;
  2514. erts_aint32_t nflgs = (ERTS_SSI_FLG_SLEEPING
  2515. | ERTS_SSI_FLG_WAITING
  2516. | ERTS_SSI_FLG_SUSPENDED);
  2517. erts_aint32_t xflgs = xpct;
  2518. do {
  2519. oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
  2520. if (oflgs == xflgs)
  2521. return nflgs;
  2522. xflgs = oflgs;
  2523. } while (oflgs & ERTS_SSI_FLG_SUSPENDED);
  2524. return oflgs;
  2525. }
  2526. static erts_aint32_t
  2527. sched_spin_suspended(ErtsSchedulerSleepInfo *ssi, int spincount)
  2528. {
  2529. int until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
  2530. int sc = spincount;
  2531. erts_aint32_t flgs;
  2532. do {
  2533. flgs = erts_smp_atomic32_read(&ssi->flags);
  2534. if ((flgs & (ERTS_SSI_FLG_SLEEPING
  2535. | ERTS_SSI_FLG_WAITING
  2536. | ERTS_SSI_FLG_SUSPENDED))
  2537. != (ERTS_SSI_FLG_SLEEPING
  2538. | ERTS_SSI_FLG_WAITING
  2539. | ERTS_SSI_FLG_SUSPENDED)) {
  2540. break;
  2541. }
  2542. ERTS_SPIN_BODY;
  2543. if (--until_yield == 0) {
  2544. until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
  2545. erts_thr_yield();
  2546. }
  2547. } while (--sc > 0);
  2548. return flgs;
  2549. }
  2550. static erts_aint32_t
  2551. sched_set_suspended_sleeptype(ErtsSchedulerSleepInfo *ssi)
  2552. {
  2553. erts_aint32_t oflgs;
  2554. erts_aint32_t nflgs = (ERTS_SSI_FLG_SLEEPING
  2555. | ERTS_SSI_FLG_TSE_SLEEPING
  2556. | ERTS_SSI_FLG_WAITING
  2557. | ERTS_SSI_FLG_SUSPENDED);
  2558. erts_aint32_t xflgs = (ERTS_SSI_FLG_SLEEPING
  2559. | ERTS_SSI_FLG_WAITING
  2560. | ERTS_SSI_FLG_SUSPENDED);
  2561. erts_tse_reset(ssi->event);
  2562. while (1) {
  2563. oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
  2564. if (oflgs == xflgs)
  2565. return nflgs;
  2566. if ((oflgs & (ERTS_SSI_FLG_SLEEPING
  2567. | ERTS_SSI_FLG_WAITING
  2568. | ERTS_SSI_FLG_SUSPENDED))
  2569. != (ERTS_SSI_FLG_SLEEPING
  2570. | ERTS_SSI_FLG_WAITING
  2571. | ERTS_SSI_FLG_SUSPENDED)) {
  2572. return oflgs;
  2573. }
  2574. xflgs = oflgs;
  2575. }
  2576. }
  2577. static void
  2578. suspend_scheduler(ErtsSchedulerData *esdp)
  2579. {
  2580. erts_aint32_t flgs;
  2581. erts_aint32_t changing;
  2582. long no = (long) esdp->no;
  2583. ErtsSchedulerSleepInfo *ssi = esdp->ssi;
  2584. long active_schedulers;
  2585. int curr_online = 1;
  2586. int wake = 0;
  2587. #if defined(ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK) \
  2588. || defined(ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK)
  2589. erts_aint32_t aux_work;
  2590. #endif
  2591. /*
  2592. * Schedulers may be suspended in two different ways:
  2593. * - A scheduler may be suspended since it is not online.
  2594. * All schedulers with scheduler ids greater than
  2595. * schdlr_sspnd.online are suspended.
  2596. * - Multi scheduling is blocked. All schedulers except the
  2597. * scheduler with scheduler id 1 are suspended.
  2598. *
  2599. * Regardless of why a scheduler is suspended, it ends up here.
  2600. */
  2601. ASSERT(no != 1);
  2602. erts_smp_runq_unlock(esdp->run_queue);
  2603. erts_sched_check_cpu_bind_prep_suspend(esdp);
  2604. if (erts_system_profile_flags.scheduler)
  2605. profile_scheduler(make_small(esdp->no), am_inactive);
  2606. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  2607. flgs = sched_prep_spin_suspended(ssi, ERTS_SSI_FLG_SUSPENDED);
  2608. if (flgs & ERTS_SSI_FLG_SUSPENDED) {
  2609. active_schedulers = erts_smp_atomic32_dectest(&schdlr_sspnd.active);
  2610. ASSERT(active_schedulers >= 1);
  2611. changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
  2612. if (changing & ERTS_SCHDLR_SSPND_CHNG_MSB) {
  2613. if (active_schedulers == schdlr_sspnd.msb.wait_active)
  2614. wake = 1;
  2615. if (active_schedulers == 1) {
  2616. changing = erts_smp_atomic32_band(&schdlr_sspnd.changing,
  2617. ~ERTS_SCHDLR_SSPND_CHNG_MSB);
  2618. changing &= ~ERTS_SCHDLR_SSPND_CHNG_MSB;
  2619. }
  2620. }
  2621. while (1) {
  2622. if (changing & ERTS_SCHDLR_SSPND_CHNG_ONLN) {
  2623. int changed = 0;
  2624. if (no > schdlr_sspnd.online && curr_online) {
  2625. schdlr_sspnd.curr_online--;
  2626. curr_online = 0;
  2627. changed = 1;
  2628. }
  2629. else if (no <= schdlr_sspnd.online && !curr_online) {
  2630. schdlr_sspnd.curr_online++;
  2631. curr_online = 1;
  2632. changed = 1;
  2633. }
  2634. if (changed
  2635. && schdlr_sspnd.curr_online == schdlr_sspnd.wait_curr_online)
  2636. wake = 1;
  2637. if (schdlr_sspnd.online == schdlr_sspnd.curr_online) {
  2638. changing = erts_smp_atomic32_band(&schdlr_sspnd.changing,
  2639. ~ERTS_SCHDLR_SSPND_CHNG_ONLN);
  2640. changing &= ~ERTS_SCHDLR_SSPND_CHNG_ONLN;
  2641. }
  2642. }
  2643. if (wake) {
  2644. erts_smp_cnd_signal(&schdlr_sspnd.cnd);
  2645. wake = 0;
  2646. }
  2647. flgs = erts_smp_atomic32_read(&ssi->flags);
  2648. if (!(flgs & ERTS_SSI_FLG_SUSPENDED))
  2649. break;
  2650. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  2651. #ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  2652. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  2653. blockable_aux_work:
  2654. blockable_aux_work(esdp, ssi, aux_work);
  2655. #endif
  2656. erts_smp_activity_begin(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
  2657. while (1) {
  2658. erts_aint32_t flgs;
  2659. #ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
  2660. #ifndef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  2661. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  2662. #endif
  2663. nonblockable_aux_work(esdp, ssi, aux_work);
  2664. #endif
  2665. flgs = sched_spin_suspended(ssi,
  2666. ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT);
  2667. if (flgs == (ERTS_SSI_FLG_SLEEPING
  2668. | ERTS_SSI_FLG_WAITING
  2669. | ERTS_SSI_FLG_SUSPENDED)) {
  2670. flgs = sched_set_suspended_sleeptype(ssi);
  2671. if (flgs == (ERTS_SSI_FLG_SLEEPING
  2672. | ERTS_SSI_FLG_TSE_SLEEPING
  2673. | ERTS_SSI_FLG_WAITING
  2674. | ERTS_SSI_FLG_SUSPENDED)) {
  2675. int res;
  2676. do {
  2677. res = erts_tse_wait(ssi->event);
  2678. } while (res == EINTR);
  2679. }
  2680. }
  2681. flgs = sched_prep_spin_suspended(ssi, (ERTS_SSI_FLG_WAITING
  2682. | ERTS_SSI_FLG_SUSPENDED));
  2683. if (!(flgs & ERTS_SSI_FLG_SUSPENDED))
  2684. break;
  2685. changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
  2686. if (changing & ~ERTS_SCHDLR_SSPND_CHNG_WAITER)
  2687. break;
  2688. #ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  2689. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  2690. if (aux_work & ERTS_SSI_BLOCKABLE_AUX_WORK_MASK) {
  2691. erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
  2692. goto blockable_aux_work;
  2693. }
  2694. #endif
  2695. }
  2696. erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
  2697. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  2698. changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
  2699. }
  2700. active_schedulers = erts_smp_atomic32_inctest(&schdlr_sspnd.active);
  2701. changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
  2702. if ((changing & ERTS_SCHDLR_SSPND_CHNG_MSB)
  2703. && schdlr_sspnd.online == active_schedulers) {
  2704. erts_smp_atomic32_band(&schdlr_sspnd.changing,
  2705. ~ERTS_SCHDLR_SSPND_CHNG_MSB);
  2706. }
  2707. ASSERT(no <= schdlr_sspnd.online);
  2708. ASSERT(!erts_smp_atomic32_read(&schdlr_sspnd.msb.ongoing));
  2709. }
  2710. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  2711. ASSERT(curr_online);
  2712. if (erts_system_profile_flags.scheduler)
  2713. profile_scheduler(make_small(esdp->no), am_active);
  2714. erts_smp_runq_lock(esdp->run_queue);
  2715. non_empty_runq(esdp->run_queue);
  2716. erts_sched_check_cpu_bind_post_suspend(esdp);
  2717. }
  2718. #define ERTS_RUNQ_RESET_SUSPEND_INFO(RQ, DBG_ID) \
  2719. do { \
  2720. int pix__; \
  2721. (RQ)->misc.evac_runq = NULL; \
  2722. (RQ)->ports.info.migrate.runq = NULL; \
  2723. (RQ)->flags &= ~(ERTS_RUNQ_FLGS_IMMIGRATE_QMASK \
  2724. | ERTS_RUNQ_FLGS_EMIGRATE_QMASK \
  2725. | ERTS_RUNQ_FLGS_EVACUATE_QMASK \
  2726. | ERTS_RUNQ_FLG_SUSPENDED); \
  2727. (RQ)->flags |= (ERTS_RUNQ_FLG_OUT_OF_WORK \
  2728. | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK); \
  2729. (RQ)->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS; \
  2730. erts_smp_atomic32_band(&(RQ)->info_flags, ~ERTS_RUNQ_IFLG_SUSPENDED);\
  2731. for (pix__ = 0; pix__ < ERTS_NO_PROC_PRIO_LEVELS; pix__++) { \
  2732. (RQ)->procs.prio_info[pix__].max_len = 0; \
  2733. (RQ)->procs.prio_info[pix__].reds = 0; \
  2734. ERTS_DBG_SET_INVALID_RUNQP((RQ)->procs.prio_info[pix__].migrate.runq,\
  2735. (DBG_ID)); \
  2736. } \
  2737. (RQ)->ports.info.max_len = 0; \
  2738. (RQ)->ports.info.reds = 0; \
  2739. } while (0)
  2740. #define ERTS_RUNQ_RESET_MIGRATION_PATHS__(RQ) \
  2741. do { \
  2742. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked((RQ))); \
  2743. (RQ)->misc.evac_runq = NULL; \
  2744. (RQ)->ports.info.migrate.runq = NULL; \
  2745. (RQ)->flags &= ~(ERTS_RUNQ_FLGS_IMMIGRATE_QMASK \
  2746. | ERTS_RUNQ_FLGS_EMIGRATE_QMASK \
  2747. | ERTS_RUNQ_FLGS_EVACUATE_QMASK); \
  2748. } while (0)
  2749. #ifdef DEBUG
  2750. #define ERTS_RUNQ_RESET_MIGRATION_PATHS(RQ, DBG_ID) \
  2751. do { \
  2752. int pix__; \
  2753. ERTS_RUNQ_RESET_MIGRATION_PATHS__((RQ)); \
  2754. for (pix__ = 0; pix__ < ERTS_NO_PROC_PRIO_LEVELS; pix__++) \
  2755. ERTS_DBG_SET_INVALID_RUNQP((RQ)->procs.prio_info[pix__].migrate.runq,\
  2756. (DBG_ID)); \
  2757. } while (0)
  2758. #else
  2759. #define ERTS_RUNQ_RESET_MIGRATION_PATHS(RQ, DBG_ID) \
  2760. ERTS_RUNQ_RESET_MIGRATION_PATHS__((RQ))
  2761. #endif
  2762. ErtsSchedSuspendResult
  2763. erts_schedulers_state(Uint *total,
  2764. Uint *online,
  2765. Uint *active,
  2766. int yield_allowed)
  2767. {
  2768. int res;
  2769. erts_aint32_t changing;
  2770. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  2771. changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
  2772. if (yield_allowed && (changing & ~ERTS_SCHDLR_SSPND_CHNG_WAITER))
  2773. res = ERTS_SCHDLR_SSPND_YIELD_RESTART;
  2774. else {
  2775. *active = *online = schdlr_sspnd.online;
  2776. if (ongoing_multi_scheduling_block())
  2777. *active = 1;
  2778. res = ERTS_SCHDLR_SSPND_DONE;
  2779. }
  2780. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  2781. *total = erts_no_schedulers;
  2782. return res;
  2783. }
  2784. ErtsSchedSuspendResult
  2785. erts_set_schedulers_online(Process *p,
  2786. ErtsProcLocks plocks,
  2787. Sint new_no,
  2788. Sint *old_no)
  2789. {
  2790. int ix, res, no, have_unlocked_plocks;
  2791. erts_aint32_t changing;
  2792. if (new_no < 1 || erts_no_schedulers < new_no)
  2793. return ERTS_SCHDLR_SSPND_EINVAL;
  2794. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  2795. have_unlocked_plocks = 0;
  2796. no = (int) new_no;
  2797. changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
  2798. if (changing) {
  2799. res = ERTS_SCHDLR_SSPND_YIELD_RESTART;
  2800. }
  2801. else {
  2802. int online = *old_no = schdlr_sspnd.online;
  2803. if (no == schdlr_sspnd.online) {
  2804. res = ERTS_SCHDLR_SSPND_DONE;
  2805. }
  2806. else {
  2807. ERTS_SCHDLR_SSPND_CHNG_SET((ERTS_SCHDLR_SSPND_CHNG_ONLN
  2808. | ERTS_SCHDLR_SSPND_CHNG_WAITER), 0);
  2809. schdlr_sspnd.online = no;
  2810. if (no > online) {
  2811. int ix;
  2812. schdlr_sspnd.wait_curr_online = no;
  2813. if (ongoing_multi_scheduling_block()) {
  2814. for (ix = online; ix < no; ix++)
  2815. erts_sched_poke(ERTS_SCHED_SLEEP_INFO_IX(ix));
  2816. }
  2817. else if (erts_common_run_queue) {
  2818. for (ix = online; ix < no; ix++)
  2819. scheduler_ix_resume_wake(ix);
  2820. }
  2821. else {
  2822. if (plocks) {
  2823. have_unlocked_plocks = 1;
  2824. erts_smp_proc_unlock(p, plocks);
  2825. }
  2826. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  2827. erts_smp_mtx_lock(&balance_info.update_mtx);
  2828. for (ix = online; ix < no; ix++) {
  2829. ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
  2830. erts_smp_runq_lock(rq);
  2831. ERTS_RUNQ_RESET_SUSPEND_INFO(rq, 0x5);
  2832. erts_smp_runq_unlock(rq);
  2833. scheduler_ix_resume_wake(ix);
  2834. }
  2835. /*
  2836. * Spread evacuation paths among all online
  2837. * run queues.
  2838. */
  2839. for (ix = no; ix < erts_no_run_queues; ix++) {
  2840. ErtsRunQueue *from_rq = ERTS_RUNQ_IX(ix);
  2841. ErtsRunQueue *to_rq = ERTS_RUNQ_IX(ix % no);
  2842. evacuate_run_queue(from_rq, to_rq);
  2843. }
  2844. erts_smp_atomic32_set(&balance_info.used_runqs, no);
  2845. erts_smp_mtx_unlock(&balance_info.update_mtx);
  2846. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  2847. }
  2848. res = ERTS_SCHDLR_SSPND_DONE;
  2849. }
  2850. else /* if (no < online) */ {
  2851. if (p->scheduler_data->no <= no) {
  2852. res = ERTS_SCHDLR_SSPND_DONE;
  2853. schdlr_sspnd.wait_curr_online = no;
  2854. }
  2855. else {
  2856. /*
  2857. * Yield! Current process needs to migrate
  2858. * before bif returns.
  2859. */
  2860. res = ERTS_SCHDLR_SSPND_YIELD_DONE;
  2861. schdlr_sspnd.wait_curr_online = no+1;
  2862. }
  2863. if (ongoing_multi_scheduling_block()) {
  2864. for (ix = no; ix < online; ix++)
  2865. erts_sched_poke(ERTS_SCHED_SLEEP_INFO_IX(ix));
  2866. }
  2867. else if (erts_common_run_queue) {
  2868. for (ix = no; ix < online; ix++) {
  2869. ErtsSchedulerSleepInfo *ssi;
  2870. ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
  2871. erts_smp_atomic32_bor(&ssi->flags,
  2872. ERTS_SSI_FLG_SUSPENDED);
  2873. }
  2874. wake_all_schedulers();
  2875. }
  2876. else {
  2877. if (plocks) {
  2878. have_unlocked_plocks = 1;
  2879. erts_smp_proc_unlock(p, plocks);
  2880. }
  2881. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  2882. erts_smp_mtx_lock(&balance_info.update_mtx);
  2883. for (ix = 0; ix < online; ix++) {
  2884. ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
  2885. erts_smp_runq_lock(rq);
  2886. ERTS_RUNQ_RESET_MIGRATION_PATHS(rq, 0x6);
  2887. erts_smp_runq_unlock(rq);
  2888. }
  2889. /*
  2890. * Evacutation order important! Newly suspended run queues
  2891. * has to be evacuated last.
  2892. */
  2893. for (ix = erts_no_run_queues-1; ix >= no; ix--)
  2894. evacuate_run_queue(ERTS_RUNQ_IX(ix),
  2895. ERTS_RUNQ_IX(ix % no));
  2896. erts_smp_atomic32_set(&balance_info.used_runqs, no);
  2897. erts_smp_mtx_unlock(&balance_info.update_mtx);
  2898. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  2899. for (ix = no; ix < online; ix++) {
  2900. ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
  2901. wake_scheduler(rq, 0, 1);
  2902. }
  2903. }
  2904. }
  2905. erts_smp_activity_begin(ERTS_ACTIVITY_WAIT,
  2906. susp_sched_prep_block,
  2907. susp_sched_resume_block,
  2908. NULL);
  2909. while (schdlr_sspnd.curr_online != schdlr_sspnd.wait_curr_online)
  2910. erts_smp_cnd_wait(&schdlr_sspnd.cnd, &schdlr_sspnd.mtx);
  2911. erts_smp_activity_end(ERTS_ACTIVITY_WAIT,
  2912. susp_sched_prep_block,
  2913. susp_sched_resume_block,
  2914. NULL);
  2915. ASSERT(res != ERTS_SCHDLR_SSPND_DONE
  2916. ? (ERTS_SCHDLR_SSPND_CHNG_WAITER
  2917. & erts_smp_atomic32_read(&schdlr_sspnd.changing))
  2918. : (ERTS_SCHDLR_SSPND_CHNG_WAITER
  2919. == erts_smp_atomic32_read(&schdlr_sspnd.changing)));
  2920. erts_smp_atomic32_band(&schdlr_sspnd.changing,
  2921. ~ERTS_SCHDLR_SSPND_CHNG_WAITER);
  2922. }
  2923. }
  2924. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  2925. if (have_unlocked_plocks)
  2926. erts_smp_proc_lock(p, plocks);
  2927. return res;
  2928. }
  2929. ErtsSchedSuspendResult
  2930. erts_block_multi_scheduling(Process *p, ErtsProcLocks plocks, int on, int all)
  2931. {
  2932. int ix, res, have_unlocked_plocks = 0;
  2933. erts_aint32_t changing;
  2934. ErtsProcList *plp;
  2935. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  2936. changing = erts_smp_atomic32_read(&schdlr_sspnd.changing);
  2937. if (changing) {
  2938. res = ERTS_SCHDLR_SSPND_YIELD_RESTART; /* Yield */
  2939. }
  2940. else if (on) { /* ------ BLOCK ------ */
  2941. if (schdlr_sspnd.msb.procs) {
  2942. plp = proclist_create(p);
  2943. plp->next = schdlr_sspnd.msb.procs;
  2944. schdlr_sspnd.msb.procs = plp;
  2945. p->flags |= F_HAVE_BLCKD_MSCHED;
  2946. ASSERT(erts_smp_atomic32_read(&schdlr_sspnd.active) == 1);
  2947. ASSERT(p->scheduler_data->no == 1);
  2948. res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED;
  2949. }
  2950. else {
  2951. int online = schdlr_sspnd.online;
  2952. p->flags |= F_HAVE_BLCKD_MSCHED;
  2953. if (plocks) {
  2954. have_unlocked_plocks = 1;
  2955. erts_smp_proc_unlock(p, plocks);
  2956. }
  2957. ASSERT(0 == erts_smp_atomic32_read(&schdlr_sspnd.msb.ongoing));
  2958. erts_smp_atomic32_set(&schdlr_sspnd.msb.ongoing, 1);
  2959. if (online == 1) {
  2960. res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED;
  2961. ASSERT(erts_smp_atomic32_read(&schdlr_sspnd.active) == 1);
  2962. ASSERT(p->scheduler_data->no == 1);
  2963. }
  2964. else {
  2965. ERTS_SCHDLR_SSPND_CHNG_SET((ERTS_SCHDLR_SSPND_CHNG_MSB
  2966. | ERTS_SCHDLR_SSPND_CHNG_WAITER), 0);
  2967. if (p->scheduler_data->no == 1) {
  2968. res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED;
  2969. schdlr_sspnd.msb.wait_active = 1;
  2970. }
  2971. else {
  2972. /*
  2973. * Yield! Current process needs to migrate
  2974. * before bif returns.
  2975. */
  2976. res = ERTS_SCHDLR_SSPND_YIELD_DONE_MSCHED_BLOCKED;
  2977. schdlr_sspnd.msb.wait_active = 2;
  2978. }
  2979. if (erts_common_run_queue) {
  2980. for (ix = 1; ix < online; ix++)
  2981. erts_smp_atomic32_bor(&ERTS_SCHED_SLEEP_INFO_IX(ix)->flags,
  2982. ERTS_SSI_FLG_SUSPENDED);
  2983. wake_all_schedulers();
  2984. }
  2985. else {
  2986. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  2987. erts_smp_mtx_lock(&balance_info.update_mtx);
  2988. erts_smp_atomic32_set(&balance_info.used_runqs, 1);
  2989. for (ix = 0; ix < online; ix++) {
  2990. ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
  2991. erts_smp_runq_lock(rq);
  2992. ASSERT(!(rq->flags & ERTS_RUNQ_FLG_SUSPENDED));
  2993. ERTS_RUNQ_RESET_MIGRATION_PATHS(rq, 0x7);
  2994. erts_smp_runq_unlock(rq);
  2995. }
  2996. /*
  2997. * Evacuate all activities in all other run queues
  2998. * into the first run queue. Note order is important,
  2999. * online run queues has to be evacuated last.
  3000. */
  3001. for (ix = erts_no_run_queues-1; ix >= 1; ix--)
  3002. evacuate_run_queue(ERTS_RUNQ_IX(ix), ERTS_RUNQ_IX(0));
  3003. erts_smp_mtx_unlock(&balance_info.update_mtx);
  3004. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  3005. }
  3006. erts_smp_activity_begin(ERTS_ACTIVITY_WAIT,
  3007. susp_sched_prep_block,
  3008. susp_sched_resume_block,
  3009. NULL);
  3010. while (erts_smp_atomic32_read(&schdlr_sspnd.active)
  3011. != schdlr_sspnd.msb.wait_active)
  3012. erts_smp_cnd_wait(&schdlr_sspnd.cnd, &schdlr_sspnd.mtx);
  3013. erts_smp_activity_end(ERTS_ACTIVITY_WAIT,
  3014. susp_sched_prep_block,
  3015. susp_sched_resume_block,
  3016. NULL);
  3017. ASSERT(res != ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED
  3018. ? (ERTS_SCHDLR_SSPND_CHNG_WAITER
  3019. & erts_smp_atomic32_read(&schdlr_sspnd.changing))
  3020. : (ERTS_SCHDLR_SSPND_CHNG_WAITER
  3021. == erts_smp_atomic32_read(&schdlr_sspnd.changing)));
  3022. erts_smp_atomic32_band(&schdlr_sspnd.changing,
  3023. ~ERTS_SCHDLR_SSPND_CHNG_WAITER);
  3024. }
  3025. plp = proclist_create(p);
  3026. plp->next = schdlr_sspnd.msb.procs;
  3027. schdlr_sspnd.msb.procs = plp;
  3028. #ifdef DEBUG
  3029. ERTS_FOREACH_RUNQ(srq,
  3030. {
  3031. if (srq != ERTS_RUNQ_IX(0)) {
  3032. ASSERT(ERTS_EMPTY_RUNQ(srq));
  3033. ASSERT(srq->flags & ERTS_RUNQ_FLG_SUSPENDED);
  3034. }
  3035. });
  3036. #endif
  3037. ASSERT(p->scheduler_data);
  3038. }
  3039. }
  3040. else if (!ongoing_multi_scheduling_block()) {
  3041. /* unblock not ongoing */
  3042. ASSERT(!schdlr_sspnd.msb.procs);
  3043. res = ERTS_SCHDLR_SSPND_DONE;
  3044. }
  3045. else { /* ------ UNBLOCK ------ */
  3046. if (p->flags & F_HAVE_BLCKD_MSCHED) {
  3047. ErtsProcList **plpp = &schdlr_sspnd.msb.procs;
  3048. plp = schdlr_sspnd.msb.procs;
  3049. while (plp) {
  3050. if (!proclist_same(plp, p)){
  3051. plpp = &plp->next;
  3052. plp = plp->next;
  3053. }
  3054. else {
  3055. *plpp = plp->next;
  3056. proclist_destroy(plp);
  3057. if (!all)
  3058. break;
  3059. plp = *plpp;
  3060. }
  3061. }
  3062. }
  3063. if (schdlr_sspnd.msb.procs)
  3064. res = ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED;
  3065. else {
  3066. ERTS_SCHDLR_SSPND_CHNG_SET(ERTS_SCHDLR_SSPND_CHNG_MSB, 0);
  3067. #ifdef DEBUG
  3068. ERTS_FOREACH_RUNQ(rq,
  3069. {
  3070. if (rq != p->scheduler_data->run_queue) {
  3071. if (!ERTS_EMPTY_RUNQ(rq)) {
  3072. Process *rp;
  3073. int pix;
  3074. ASSERT(rq->ports.info.len == 0);
  3075. for (pix = 0; pix < ERTS_NO_PROC_PRIO_LEVELS; pix++) {
  3076. for (rp = rq->procs.prio[pix].first;
  3077. rp;
  3078. rp = rp->next) {
  3079. ASSERT(rp->bound_runq);
  3080. }
  3081. }
  3082. }
  3083. ASSERT(rq->flags & ERTS_RUNQ_FLG_SUSPENDED);
  3084. }
  3085. });
  3086. #endif
  3087. p->flags &= ~F_HAVE_BLCKD_MSCHED;
  3088. erts_smp_atomic32_set(&schdlr_sspnd.msb.ongoing, 0);
  3089. if (schdlr_sspnd.online == 1) {
  3090. /* No schedulers to resume */
  3091. ASSERT(erts_smp_atomic32_read(&schdlr_sspnd.active) == 1);
  3092. ERTS_SCHDLR_SSPND_CHNG_SET(0, ERTS_SCHDLR_SSPND_CHNG_MSB);
  3093. }
  3094. else if (erts_common_run_queue) {
  3095. for (ix = 1; ix < schdlr_sspnd.online; ix++)
  3096. erts_smp_atomic32_band(&ERTS_SCHED_SLEEP_INFO_IX(ix)->flags,
  3097. ~ERTS_SSI_FLG_SUSPENDED);
  3098. wake_all_schedulers();
  3099. }
  3100. else {
  3101. int online = schdlr_sspnd.online;
  3102. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  3103. if (plocks) {
  3104. have_unlocked_plocks = 1;
  3105. erts_smp_proc_unlock(p, plocks);
  3106. }
  3107. erts_smp_mtx_lock(&balance_info.update_mtx);
  3108. /* Resume all online run queues */
  3109. for (ix = 1; ix < online; ix++) {
  3110. ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
  3111. erts_smp_runq_lock(rq);
  3112. ERTS_RUNQ_RESET_SUSPEND_INFO(rq, 0x4);
  3113. erts_smp_runq_unlock(rq);
  3114. scheduler_ix_resume_wake(ix);
  3115. }
  3116. /* Spread evacuation paths among all online run queues */
  3117. for (ix = online; ix < erts_no_run_queues; ix++)
  3118. evacuate_run_queue(ERTS_RUNQ_IX(ix),
  3119. ERTS_RUNQ_IX(ix % online));
  3120. erts_smp_atomic32_set(&balance_info.used_runqs, online);
  3121. /* Make sure that we balance soon... */
  3122. balance_info.forced_check_balance = 1;
  3123. erts_smp_runq_lock(ERTS_RUNQ_IX(0));
  3124. ERTS_RUNQ_IX(0)->check_balance_reds = 0;
  3125. erts_smp_runq_unlock(ERTS_RUNQ_IX(0));
  3126. erts_smp_mtx_unlock(&balance_info.update_mtx);
  3127. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  3128. }
  3129. res = ERTS_SCHDLR_SSPND_DONE;
  3130. }
  3131. }
  3132. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  3133. if (have_unlocked_plocks)
  3134. erts_smp_proc_lock(p, plocks);
  3135. return res;
  3136. }
  3137. #ifdef DEBUG
  3138. void
  3139. erts_dbg_multi_scheduling_return_trap(Process *p, Eterm return_value)
  3140. {
  3141. if (return_value == am_blocked) {
  3142. erts_aint32_t active = erts_smp_atomic32_read(&schdlr_sspnd.active);
  3143. ASSERT(1 <= active && active <= 2);
  3144. ASSERT(ERTS_PROC_GET_SCHDATA(p)->no == 1);
  3145. }
  3146. }
  3147. #endif
  3148. int
  3149. erts_is_multi_scheduling_blocked(void)
  3150. {
  3151. int res;
  3152. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  3153. res = schdlr_sspnd.msb.procs != NULL;
  3154. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  3155. return res;
  3156. }
  3157. Eterm
  3158. erts_multi_scheduling_blockers(Process *p)
  3159. {
  3160. Eterm res = NIL;
  3161. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  3162. if (schdlr_sspnd.msb.procs) {
  3163. Eterm *hp, *hp_end;
  3164. ErtsProcList *plp1, *plp2;
  3165. Uint max_size;
  3166. ASSERT(schdlr_sspnd.msb.procs);
  3167. for (max_size = 0, plp1 = schdlr_sspnd.msb.procs;
  3168. plp1;
  3169. plp1 = plp1->next) {
  3170. max_size += 2;
  3171. }
  3172. ASSERT(max_size);
  3173. hp = HAlloc(p, max_size);
  3174. hp_end = hp + max_size;
  3175. for (plp1 = schdlr_sspnd.msb.procs; plp1; plp1 = plp1->next) {
  3176. for (plp2 = schdlr_sspnd.msb.procs;
  3177. plp2->pid != plp1->pid;
  3178. plp2 = plp2->next);
  3179. if (plp2 == plp1) {
  3180. res = CONS(hp, plp1->pid, res);
  3181. hp += 2;
  3182. }
  3183. /* else: already in result list */
  3184. }
  3185. HRelease(p, hp_end, hp);
  3186. }
  3187. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  3188. return res;
  3189. }
  3190. static void *
  3191. sched_thread_func(void *vesdp)
  3192. {
  3193. #ifdef ERTS_SMP
  3194. Uint no = ((ErtsSchedulerData *) vesdp)->no;
  3195. #endif
  3196. #ifdef ERTS_ENABLE_LOCK_CHECK
  3197. {
  3198. char buf[31];
  3199. erts_snprintf(&buf[0], 31, "scheduler %bpu", no);
  3200. erts_lc_set_thread_name(&buf[0]);
  3201. }
  3202. #endif
  3203. erts_alloc_reg_scheduler_id(no);
  3204. erts_tsd_set(sched_data_key, vesdp);
  3205. #ifdef ERTS_SMP
  3206. erts_sched_init_check_cpu_bind((ErtsSchedulerData *) vesdp);
  3207. erts_proc_lock_prepare_proc_lock_waiter();
  3208. ERTS_SCHED_SLEEP_INFO_IX(no - 1)->event = erts_tse_fetch();
  3209. #endif
  3210. erts_register_blockable_thread();
  3211. #ifdef HIPE
  3212. hipe_thread_signal_init();
  3213. #endif
  3214. erts_thread_init_float();
  3215. erts_smp_mtx_lock(&schdlr_sspnd.mtx);
  3216. ASSERT(erts_smp_atomic32_read(&schdlr_sspnd.changing)
  3217. & ERTS_SCHDLR_SSPND_CHNG_ONLN);
  3218. if (--schdlr_sspnd.curr_online == schdlr_sspnd.wait_curr_online) {
  3219. erts_smp_atomic32_band(&schdlr_sspnd.changing,
  3220. ~ERTS_SCHDLR_SSPND_CHNG_ONLN);
  3221. if (((ErtsSchedulerData *) vesdp)->no != 1)
  3222. erts_smp_cnd_signal(&schdlr_sspnd.cnd);
  3223. }
  3224. if (((ErtsSchedulerData *) vesdp)->no == 1) {
  3225. if (schdlr_sspnd.curr_online != schdlr_sspnd.wait_curr_online) {
  3226. erts_smp_activity_begin(ERTS_ACTIVITY_WAIT,
  3227. susp_sched_prep_block,
  3228. susp_sched_resume_block,
  3229. NULL);
  3230. while (schdlr_sspnd.curr_online != schdlr_sspnd.wait_curr_online)
  3231. erts_smp_cnd_wait(&schdlr_sspnd.cnd, &schdlr_sspnd.mtx);
  3232. erts_smp_activity_end(ERTS_ACTIVITY_WAIT,
  3233. susp_sched_prep_block,
  3234. susp_sched_resume_block,
  3235. NULL);
  3236. }
  3237. ERTS_SCHDLR_SSPND_CHNG_SET(0, ERTS_SCHDLR_SSPND_CHNG_WAITER);
  3238. }
  3239. erts_smp_mtx_unlock(&schdlr_sspnd.mtx);
  3240. #ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC
  3241. ((ErtsSchedulerData *) vesdp)->verify_unused_temp_alloc
  3242. = erts_alloc_get_verify_unused_temp_alloc(
  3243. &((ErtsSchedulerData *) vesdp)->verify_unused_temp_alloc_data);
  3244. ERTS_VERIFY_UNUSED_TEMP_ALLOC(NULL);
  3245. #endif
  3246. process_main();
  3247. /* No schedulers should *ever* terminate */
  3248. erl_exit(ERTS_ABORT_EXIT, "Scheduler thread number %bpu terminated\n",
  3249. ((ErtsSchedulerData *) vesdp)->no);
  3250. return NULL;
  3251. }
  3252. void
  3253. erts_start_schedulers(void)
  3254. {
  3255. int res = 0;
  3256. Uint actual = 0;
  3257. Uint wanted = erts_no_schedulers;
  3258. Uint wanted_no_schedulers = erts_no_schedulers;
  3259. ethr_thr_opts opts = ETHR_THR_OPTS_DEFAULT_INITER;
  3260. opts.detached = 1;
  3261. opts.suggested_stack_size = erts_sched_thread_suggested_stack_size;
  3262. if (wanted < 1)
  3263. wanted = 1;
  3264. if (wanted > ERTS_MAX_NO_OF_SCHEDULERS) {
  3265. wanted = ERTS_MAX_NO_OF_SCHEDULERS;
  3266. res = ENOTSUP;
  3267. }
  3268. erts_block_system(0);
  3269. while (actual < wanted) {
  3270. ErtsSchedulerData *esdp = ERTS_SCHEDULER_IX(actual);
  3271. actual++;
  3272. ASSERT(actual == esdp->no);
  3273. res = ethr_thr_create(&esdp->tid,sched_thread_func,(void*)esdp,&opts);
  3274. if (res != 0) {
  3275. actual--;
  3276. break;
  3277. }
  3278. }
  3279. erts_no_schedulers = actual;
  3280. erts_release_system();
  3281. if (actual < 1)
  3282. erl_exit(1,
  3283. "Failed to create any scheduler-threads: %s (%d)\n",
  3284. erl_errno_id(res),
  3285. res);
  3286. if (res != 0) {
  3287. erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
  3288. ASSERT(actual != wanted_no_schedulers);
  3289. erts_dsprintf(dsbufp,
  3290. "Failed to create %bpu scheduler-threads (%s:%d); "
  3291. "only %bpu scheduler-thread%s created.\n",
  3292. wanted_no_schedulers, erl_errno_id(res), res,
  3293. actual, actual == 1 ? " was" : "s were");
  3294. erts_send_error_to_logger_nogl(dsbufp);
  3295. }
  3296. }
  3297. #endif /* ERTS_SMP */
  3298. #ifdef ERTS_SMP
  3299. static void
  3300. add_pend_suspend(Process *suspendee,
  3301. Eterm originator_pid,
  3302. void (*handle_func)(Process *,
  3303. ErtsProcLocks,
  3304. int,
  3305. Eterm))
  3306. {
  3307. ErtsPendingSuspend *psp = erts_alloc(ERTS_ALC_T_PEND_SUSPEND,
  3308. sizeof(ErtsPendingSuspend));
  3309. psp->next = NULL;
  3310. #ifdef DEBUG
  3311. #if defined(ARCH_64) && !HALFWORD_HEAP
  3312. psp->end = (ErtsPendingSuspend *) 0xdeaddeaddeaddead;
  3313. #else
  3314. psp->end = (ErtsPendingSuspend *) 0xdeaddead;
  3315. #endif
  3316. #endif
  3317. psp->pid = originator_pid;
  3318. psp->handle_func = handle_func;
  3319. if (suspendee->pending_suspenders)
  3320. suspendee->pending_suspenders->end->next = psp;
  3321. else
  3322. suspendee->pending_suspenders = psp;
  3323. suspendee->pending_suspenders->end = psp;
  3324. }
  3325. static void
  3326. handle_pending_suspend(Process *p, ErtsProcLocks p_locks)
  3327. {
  3328. ErtsPendingSuspend *psp;
  3329. int is_alive = !ERTS_PROC_IS_EXITING(p);
  3330. ERTS_SMP_LC_ASSERT(p_locks & ERTS_PROC_LOCK_STATUS);
  3331. /*
  3332. * New pending suspenders might appear while we are processing
  3333. * (since we may release the status lock on p while processing).
  3334. */
  3335. while (p->pending_suspenders) {
  3336. psp = p->pending_suspenders;
  3337. p->pending_suspenders = NULL;
  3338. while (psp) {
  3339. ErtsPendingSuspend *free_psp;
  3340. (*psp->handle_func)(p, p_locks, is_alive, psp->pid);
  3341. free_psp = psp;
  3342. psp = psp->next;
  3343. erts_free(ERTS_ALC_T_PEND_SUSPEND, (void *) free_psp);
  3344. }
  3345. }
  3346. }
  3347. static ERTS_INLINE void
  3348. cancel_suspend_of_suspendee(Process *p, ErtsProcLocks p_locks)
  3349. {
  3350. if (is_not_nil(p->suspendee)) {
  3351. Process *rp;
  3352. if (!(p_locks & ERTS_PROC_LOCK_STATUS))
  3353. erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
  3354. rp = erts_pid2proc(p, p_locks|ERTS_PROC_LOCK_STATUS,
  3355. p->suspendee, ERTS_PROC_LOCK_STATUS);
  3356. if (rp) {
  3357. erts_resume(rp, ERTS_PROC_LOCK_STATUS);
  3358. erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS);
  3359. }
  3360. if (!(p_locks & ERTS_PROC_LOCK_STATUS))
  3361. erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
  3362. p->suspendee = NIL;
  3363. }
  3364. }
  3365. static void
  3366. handle_pend_sync_suspend(Process *suspendee,
  3367. ErtsProcLocks suspendee_locks,
  3368. int suspendee_alive,
  3369. Eterm suspender_pid)
  3370. {
  3371. Process *suspender;
  3372. ERTS_SMP_LC_ASSERT(suspendee_locks & ERTS_PROC_LOCK_STATUS);
  3373. suspender = erts_pid2proc(suspendee,
  3374. suspendee_locks,
  3375. suspender_pid,
  3376. ERTS_PROC_LOCK_STATUS);
  3377. if (suspender) {
  3378. ASSERT(is_nil(suspender->suspendee));
  3379. if (suspendee_alive) {
  3380. ErtsRunQueue *rq = erts_get_runq_proc(suspendee);
  3381. erts_smp_runq_lock(rq);
  3382. suspend_process(rq, suspendee);
  3383. erts_smp_runq_unlock(rq);
  3384. suspender->suspendee = suspendee->id;
  3385. }
  3386. /* suspender is suspended waiting for suspendee to suspend;
  3387. resume suspender */
  3388. resume_process(suspender);
  3389. erts_smp_proc_unlock(suspender, ERTS_PROC_LOCK_STATUS);
  3390. }
  3391. }
  3392. /*
  3393. * Like erts_pid2proc() but:
  3394. *
  3395. * * At least ERTS_PROC_LOCK_MAIN have to be held on c_p.
  3396. * * At least ERTS_PROC_LOCK_MAIN have to be taken on pid.
  3397. * * It also waits for proc to be in a state != running and garbing.
  3398. * * If ERTS_PROC_LOCK_BUSY is returned, the calling process has to
  3399. * yield (ERTS_BIF_YIELD[0-3]()). c_p might in this case have been
  3400. * suspended.
  3401. */
  3402. Process *
  3403. erts_pid2proc_not_running(Process *c_p, ErtsProcLocks c_p_locks,
  3404. Eterm pid, ErtsProcLocks pid_locks)
  3405. {
  3406. Process *rp;
  3407. int unlock_c_p_status;
  3408. ERTS_SMP_LC_ASSERT(c_p_locks == erts_proc_lc_my_proc_locks(c_p));
  3409. ERTS_SMP_LC_ASSERT(c_p_locks & ERTS_PROC_LOCK_MAIN);
  3410. ERTS_SMP_LC_ASSERT(pid_locks & (ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS));
  3411. if (c_p->id == pid)
  3412. return erts_pid2proc(c_p, c_p_locks, pid, pid_locks);
  3413. if (c_p_locks & ERTS_PROC_LOCK_STATUS)
  3414. unlock_c_p_status = 0;
  3415. else {
  3416. unlock_c_p_status = 1;
  3417. erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_STATUS);
  3418. }
  3419. if (c_p->suspendee == pid) {
  3420. /* Process previously suspended by c_p (below)... */
  3421. ErtsProcLocks rp_locks = pid_locks|ERTS_PROC_LOCK_STATUS;
  3422. rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS, pid, rp_locks);
  3423. c_p->suspendee = NIL;
  3424. ASSERT(c_p->flags & F_P2PNR_RESCHED);
  3425. c_p->flags &= ~F_P2PNR_RESCHED;
  3426. if (rp)
  3427. resume_process(rp);
  3428. }
  3429. else {
  3430. ErtsRunQueue *cp_rq, *rp_rq;
  3431. rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS,
  3432. pid, ERTS_PROC_LOCK_STATUS);
  3433. if (!rp) {
  3434. c_p->flags &= ~F_P2PNR_RESCHED;
  3435. goto done;
  3436. }
  3437. ASSERT(!(c_p->flags & F_P2PNR_RESCHED));
  3438. cp_rq = erts_get_runq_proc(c_p);
  3439. rp_rq = erts_get_runq_proc(rp);
  3440. erts_smp_runqs_lock(cp_rq, rp_rq);
  3441. if (rp->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING) {
  3442. running:
  3443. /* Phiu... */
  3444. /*
  3445. * If we got pending suspenders and suspend ourselves waiting
  3446. * to suspend another process we might deadlock.
  3447. * In this case we have to yield, be suspended by
  3448. * someone else and then do it all over again.
  3449. */
  3450. if (!c_p->pending_suspenders) {
  3451. /* Mark rp pending for suspend by c_p */
  3452. add_pend_suspend(rp, c_p->id, handle_pend_sync_suspend);
  3453. ASSERT(is_nil(c_p->suspendee));
  3454. /* Suspend c_p; when rp is suspended c_p will be resumed. */
  3455. suspend_process(cp_rq, c_p);
  3456. c_p->flags |= F_P2PNR_RESCHED;
  3457. }
  3458. /* Yield (caller is assumed to yield immediately in bif). */
  3459. erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS);
  3460. rp = ERTS_PROC_LOCK_BUSY;
  3461. }
  3462. else {
  3463. ErtsProcLocks need_locks = pid_locks & ~ERTS_PROC_LOCK_STATUS;
  3464. if (need_locks && erts_smp_proc_trylock(rp, need_locks) == EBUSY) {
  3465. erts_smp_runqs_unlock(cp_rq, rp_rq);
  3466. erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS);
  3467. rp = erts_pid2proc(c_p, c_p_locks|ERTS_PROC_LOCK_STATUS,
  3468. pid, pid_locks|ERTS_PROC_LOCK_STATUS);
  3469. if (!rp)
  3470. goto done;
  3471. /* run-queues may have changed */
  3472. cp_rq = erts_get_runq_proc(c_p);
  3473. rp_rq = erts_get_runq_proc(rp);
  3474. erts_smp_runqs_lock(cp_rq, rp_rq);
  3475. if (rp->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING) {
  3476. /* Ahh... */
  3477. erts_smp_proc_unlock(rp,
  3478. pid_locks & ~ERTS_PROC_LOCK_STATUS);
  3479. goto running;
  3480. }
  3481. }
  3482. /* rp is not running and we got the locks we want... */
  3483. }
  3484. erts_smp_runqs_unlock(cp_rq, rp_rq);
  3485. }
  3486. done:
  3487. if (rp && rp != ERTS_PROC_LOCK_BUSY && !(pid_locks & ERTS_PROC_LOCK_STATUS))
  3488. erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_STATUS);
  3489. if (unlock_c_p_status)
  3490. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_STATUS);
  3491. return rp;
  3492. }
  3493. /*
  3494. * erts_pid2proc_nropt() is normally the same as
  3495. * erts_pid2proc_not_running(). However it is only
  3496. * to be used when 'not running' is a pure optimization,
  3497. * not a requirement.
  3498. */
  3499. Process *
  3500. erts_pid2proc_nropt(Process *c_p, ErtsProcLocks c_p_locks,
  3501. Eterm pid, ErtsProcLocks pid_locks)
  3502. {
  3503. if (erts_disable_proc_not_running_opt)
  3504. return erts_pid2proc(c_p, c_p_locks, pid, pid_locks);
  3505. else
  3506. return erts_pid2proc_not_running(c_p, c_p_locks, pid, pid_locks);
  3507. }
  3508. static ERTS_INLINE void
  3509. do_bif_suspend_process(ErtsSuspendMonitor *smon,
  3510. Process *suspendee,
  3511. ErtsRunQueue *locked_runq)
  3512. {
  3513. ASSERT(suspendee);
  3514. ASSERT(!suspendee->is_exiting);
  3515. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS
  3516. & erts_proc_lc_my_proc_locks(suspendee));
  3517. if (smon) {
  3518. if (!smon->active) {
  3519. ErtsRunQueue *rq;
  3520. if (locked_runq)
  3521. rq = locked_runq;
  3522. else {
  3523. rq = erts_get_runq_proc(suspendee);
  3524. erts_smp_runq_lock(rq);
  3525. }
  3526. suspend_process(rq, suspendee);
  3527. if (!locked_runq)
  3528. erts_smp_runq_unlock(rq);
  3529. }
  3530. smon->active += smon->pending;
  3531. ASSERT(smon->active);
  3532. smon->pending = 0;
  3533. }
  3534. }
  3535. static void
  3536. handle_pend_bif_sync_suspend(Process *suspendee,
  3537. ErtsProcLocks suspendee_locks,
  3538. int suspendee_alive,
  3539. Eterm suspender_pid)
  3540. {
  3541. Process *suspender;
  3542. ERTS_SMP_LC_ASSERT(suspendee_locks & ERTS_PROC_LOCK_STATUS);
  3543. suspender = erts_pid2proc(suspendee,
  3544. suspendee_locks,
  3545. suspender_pid,
  3546. ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCK_STATUS);
  3547. if (suspender) {
  3548. ASSERT(is_nil(suspender->suspendee));
  3549. if (!suspendee_alive)
  3550. erts_delete_suspend_monitor(&suspender->suspend_monitors,
  3551. suspendee->id);
  3552. else {
  3553. ErtsSuspendMonitor *smon;
  3554. smon = erts_lookup_suspend_monitor(suspender->suspend_monitors,
  3555. suspendee->id);
  3556. do_bif_suspend_process(smon, suspendee, NULL);
  3557. suspender->suspendee = suspendee->id;
  3558. }
  3559. /* suspender is suspended waiting for suspendee to suspend;
  3560. resume suspender */
  3561. resume_process(suspender);
  3562. erts_smp_proc_unlock(suspender,
  3563. ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCK_STATUS);
  3564. }
  3565. }
  3566. static void
  3567. handle_pend_bif_async_suspend(Process *suspendee,
  3568. ErtsProcLocks suspendee_locks,
  3569. int suspendee_alive,
  3570. Eterm suspender_pid)
  3571. {
  3572. Process *suspender;
  3573. ERTS_SMP_LC_ASSERT(suspendee_locks & ERTS_PROC_LOCK_STATUS);
  3574. suspender = erts_pid2proc(suspendee,
  3575. suspendee_locks,
  3576. suspender_pid,
  3577. ERTS_PROC_LOCK_LINK);
  3578. if (suspender) {
  3579. ASSERT(is_nil(suspender->suspendee));
  3580. if (!suspendee_alive)
  3581. erts_delete_suspend_monitor(&suspender->suspend_monitors,
  3582. suspendee->id);
  3583. else {
  3584. ErtsSuspendMonitor *smon;
  3585. smon = erts_lookup_suspend_monitor(suspender->suspend_monitors,
  3586. suspendee->id);
  3587. do_bif_suspend_process(smon, suspendee, NULL);
  3588. }
  3589. erts_smp_proc_unlock(suspender, ERTS_PROC_LOCK_LINK);
  3590. }
  3591. }
  3592. #endif /* ERTS_SMP */
  3593. /*
  3594. * The erlang:suspend_process/2 BIF
  3595. */
  3596. BIF_RETTYPE
  3597. suspend_process_2(BIF_ALIST_2)
  3598. {
  3599. Eterm res;
  3600. Process* suspendee = NULL;
  3601. ErtsSuspendMonitor *smon;
  3602. ErtsProcLocks xlocks = (ErtsProcLocks) 0;
  3603. /* Options and default values: */
  3604. int asynchronous = 0;
  3605. int unless_suspending = 0;
  3606. if (BIF_P->id == BIF_ARG_1)
  3607. goto badarg; /* We are not allowed to suspend ourselves */
  3608. if (is_not_nil(BIF_ARG_2)) {
  3609. /* Parse option list */
  3610. Eterm arg = BIF_ARG_2;
  3611. while (is_list(arg)) {
  3612. Eterm *lp = list_val(arg);
  3613. arg = CAR(lp);
  3614. switch (arg) {
  3615. case am_unless_suspending:
  3616. unless_suspending = 1;
  3617. break;
  3618. case am_asynchronous:
  3619. asynchronous = 1;
  3620. break;
  3621. default:
  3622. goto badarg;
  3623. }
  3624. arg = CDR(lp);
  3625. }
  3626. if (is_not_nil(arg))
  3627. goto badarg;
  3628. }
  3629. xlocks = ERTS_PROC_LOCK_LINK | (asynchronous
  3630. ? (ErtsProcLocks) 0
  3631. : ERTS_PROC_LOCK_STATUS);
  3632. erts_smp_proc_lock(BIF_P, xlocks);
  3633. suspendee = erts_pid2proc(BIF_P,
  3634. ERTS_PROC_LOCK_MAIN|xlocks,
  3635. BIF_ARG_1,
  3636. ERTS_PROC_LOCK_STATUS);
  3637. if (!suspendee)
  3638. goto no_suspendee;
  3639. smon = erts_add_or_lookup_suspend_monitor(&BIF_P->suspend_monitors,
  3640. BIF_ARG_1);
  3641. #ifndef ERTS_SMP /* no ERTS_SMP */
  3642. /* This is really a piece of cake without SMP support... */
  3643. if (!smon->active) {
  3644. suspend_process(erts_common_run_queue, suspendee);
  3645. smon->active++;
  3646. res = am_true;
  3647. }
  3648. else if (unless_suspending)
  3649. res = am_false;
  3650. else if (smon->active == INT_MAX)
  3651. goto system_limit;
  3652. else {
  3653. smon->active++;
  3654. res = am_true;
  3655. }
  3656. #else /* ERTS_SMP */
  3657. /* ... but a little trickier with SMP support ... */
  3658. if (asynchronous) {
  3659. /* --- Asynchronous suspend begin ---------------------------------- */
  3660. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_LINK
  3661. & erts_proc_lc_my_proc_locks(BIF_P));
  3662. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS
  3663. == erts_proc_lc_my_proc_locks(suspendee));
  3664. if (smon->active) {
  3665. smon->active += smon->pending;
  3666. smon->pending = 0;
  3667. if (unless_suspending)
  3668. res = am_false;
  3669. else if (smon->active == INT_MAX)
  3670. goto system_limit;
  3671. else {
  3672. smon->active++;
  3673. res = am_true;
  3674. }
  3675. /* done */
  3676. }
  3677. else {
  3678. /* We havn't got any active suspends on the suspendee */
  3679. if (smon->pending && unless_suspending)
  3680. res = am_false;
  3681. else {
  3682. ErtsRunQueue *rq;
  3683. if (smon->pending == INT_MAX)
  3684. goto system_limit;
  3685. smon->pending++;
  3686. rq = erts_get_runq_proc(suspendee);
  3687. erts_smp_runq_lock(rq);
  3688. if (suspendee->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING)
  3689. add_pend_suspend(suspendee,
  3690. BIF_P->id,
  3691. handle_pend_bif_async_suspend);
  3692. else
  3693. do_bif_suspend_process(smon, suspendee, rq);
  3694. erts_smp_runq_unlock(rq);
  3695. res = am_true;
  3696. }
  3697. /* done */
  3698. }
  3699. /* --- Asynchronous suspend end ------------------------------------ */
  3700. }
  3701. else /* if (!asynchronous) */ {
  3702. /* --- Synchronous suspend begin ----------------------------------- */
  3703. ERTS_SMP_LC_ASSERT(((ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCK_STATUS)
  3704. & erts_proc_lc_my_proc_locks(BIF_P))
  3705. == (ERTS_PROC_LOCK_LINK|ERTS_PROC_LOCK_STATUS));
  3706. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS
  3707. == erts_proc_lc_my_proc_locks(suspendee));
  3708. if (BIF_P->suspendee == BIF_ARG_1) {
  3709. /* We are back after a yield and the suspendee
  3710. has been suspended on behalf of us. */
  3711. ASSERT(smon->active >= 1);
  3712. BIF_P->suspendee = NIL;
  3713. res = (!unless_suspending || smon->active == 1
  3714. ? am_true
  3715. : am_false);
  3716. /* done */
  3717. }
  3718. else if (smon->active) {
  3719. if (unless_suspending)
  3720. res = am_false;
  3721. else {
  3722. smon->active++;
  3723. res = am_true;
  3724. }
  3725. /* done */
  3726. }
  3727. else {
  3728. ErtsRunQueue *cp_rq, *s_rq;
  3729. /* We haven't got any active suspends on the suspendee */
  3730. /*
  3731. * If we have pending suspenders and suspend ourselves waiting
  3732. * to suspend another process, or suspend another process
  3733. * we might deadlock. In this case we have to yield,
  3734. * be suspended by someone else, and then do it all over again.
  3735. */
  3736. if (BIF_P->pending_suspenders)
  3737. goto yield;
  3738. if (!unless_suspending && smon->pending == INT_MAX)
  3739. goto system_limit;
  3740. if (!unless_suspending || smon->pending == 0)
  3741. smon->pending++;
  3742. cp_rq = erts_get_runq_proc(BIF_P);
  3743. s_rq = erts_get_runq_proc(suspendee);
  3744. erts_smp_runqs_lock(cp_rq, s_rq);
  3745. if (!(suspendee->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING)) {
  3746. do_bif_suspend_process(smon, suspendee, s_rq);
  3747. erts_smp_runqs_unlock(cp_rq, s_rq);
  3748. res = (!unless_suspending || smon->active == 1
  3749. ? am_true
  3750. : am_false);
  3751. /* done */
  3752. }
  3753. else {
  3754. /* Mark suspendee pending for suspend by BIF_P */
  3755. add_pend_suspend(suspendee,
  3756. BIF_P->id,
  3757. handle_pend_bif_sync_suspend);
  3758. ASSERT(is_nil(BIF_P->suspendee));
  3759. /*
  3760. * Suspend BIF_P; when suspendee is suspended, BIF_P
  3761. * will be resumed and this BIF will be called again.
  3762. * This time with BIF_P->suspendee == BIF_ARG_1 (see
  3763. * above).
  3764. */
  3765. suspend_process(cp_rq, BIF_P);
  3766. erts_smp_runqs_unlock(cp_rq, s_rq);
  3767. goto yield;
  3768. }
  3769. }
  3770. /* --- Synchronous suspend end ------------------------------------- */
  3771. }
  3772. #endif /* ERTS_SMP */
  3773. ASSERT(suspendee->status == P_SUSPENDED || (asynchronous && smon->pending));
  3774. ASSERT(suspendee->status == P_SUSPENDED || !smon->active);
  3775. erts_smp_proc_unlock(suspendee, ERTS_PROC_LOCK_STATUS);
  3776. erts_smp_proc_unlock(BIF_P, xlocks);
  3777. BIF_RET(res);
  3778. system_limit:
  3779. ERTS_BIF_PREP_ERROR(res, BIF_P, SYSTEM_LIMIT);
  3780. goto do_return;
  3781. no_suspendee:
  3782. #ifdef ERTS_SMP
  3783. BIF_P->suspendee = NIL;
  3784. #endif
  3785. erts_delete_suspend_monitor(&BIF_P->suspend_monitors, BIF_ARG_1);
  3786. badarg:
  3787. ERTS_BIF_PREP_ERROR(res, BIF_P, BADARG);
  3788. #ifdef ERTS_SMP
  3789. goto do_return;
  3790. yield:
  3791. ERTS_BIF_PREP_YIELD2(res, bif_export[BIF_suspend_process_2],
  3792. BIF_P, BIF_ARG_1, BIF_ARG_2);
  3793. #endif
  3794. do_return:
  3795. if (suspendee)
  3796. erts_smp_proc_unlock(suspendee, ERTS_PROC_LOCK_STATUS);
  3797. if (xlocks)
  3798. erts_smp_proc_unlock(BIF_P, xlocks);
  3799. return res;
  3800. }
  3801. /*
  3802. * The erlang:resume_process/1 BIF
  3803. */
  3804. BIF_RETTYPE
  3805. resume_process_1(BIF_ALIST_1)
  3806. {
  3807. ErtsSuspendMonitor *smon;
  3808. Process *suspendee;
  3809. int is_active;
  3810. if (BIF_P->id == BIF_ARG_1)
  3811. BIF_ERROR(BIF_P, BADARG);
  3812. erts_smp_proc_lock(BIF_P, ERTS_PROC_LOCK_LINK);
  3813. smon = erts_lookup_suspend_monitor(BIF_P->suspend_monitors, BIF_ARG_1);
  3814. if (!smon) {
  3815. /* No previous suspend or dead suspendee */
  3816. goto error;
  3817. }
  3818. else if (smon->pending) {
  3819. smon->pending--;
  3820. ASSERT(smon->pending >= 0);
  3821. if (smon->active) {
  3822. smon->active += smon->pending;
  3823. smon->pending = 0;
  3824. }
  3825. is_active = smon->active;
  3826. }
  3827. else if (smon->active) {
  3828. smon->active--;
  3829. ASSERT(smon->pending >= 0);
  3830. is_active = 1;
  3831. }
  3832. else {
  3833. /* No previous suspend or dead suspendee */
  3834. goto error;
  3835. }
  3836. if (smon->active || smon->pending || !is_active) {
  3837. /* Leave the suspendee as it is; just verify that it is still alive */
  3838. suspendee = erts_pid2proc(BIF_P,
  3839. ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_LINK,
  3840. BIF_ARG_1,
  3841. 0);
  3842. if (!suspendee)
  3843. goto no_suspendee;
  3844. }
  3845. else {
  3846. /* Resume */
  3847. suspendee = erts_pid2proc(BIF_P,
  3848. ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_LINK,
  3849. BIF_ARG_1,
  3850. ERTS_PROC_LOCK_STATUS);
  3851. if (!suspendee)
  3852. goto no_suspendee;
  3853. ASSERT(suspendee->status == P_SUSPENDED
  3854. || (suspendee->status == P_GARBING
  3855. && suspendee->gcstatus == P_SUSPENDED));
  3856. resume_process(suspendee);
  3857. erts_smp_proc_unlock(suspendee, ERTS_PROC_LOCK_STATUS);
  3858. }
  3859. if (!smon->active && !smon->pending)
  3860. erts_delete_suspend_monitor(&BIF_P->suspend_monitors, BIF_ARG_1);
  3861. erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_LINK);
  3862. BIF_RET(am_true);
  3863. no_suspendee:
  3864. /* cleanup */
  3865. erts_delete_suspend_monitor(&BIF_P->suspend_monitors, BIF_ARG_1);
  3866. error:
  3867. erts_smp_proc_unlock(BIF_P, ERTS_PROC_LOCK_LINK);
  3868. BIF_ERROR(BIF_P, BADARG);
  3869. }
  3870. Uint
  3871. erts_run_queues_len(Uint *qlen)
  3872. {
  3873. int i = 0;
  3874. Uint len = 0;
  3875. ERTS_ATOMIC_FOREACH_RUNQ(rq,
  3876. {
  3877. if (qlen)
  3878. qlen[i++] = rq->procs.len;
  3879. len += rq->procs.len;
  3880. }
  3881. );
  3882. return len;
  3883. }
  3884. #ifdef HARDDEBUG_RUNQS
  3885. static void
  3886. check_procs_runq(ErtsRunQueue *runq, Process *p_in_q, Process *p_not_in_q)
  3887. {
  3888. int len[ERTS_NO_PROC_PRIO_LEVELS] = {0};
  3889. int tot_len;
  3890. int prioq, prio;
  3891. int found_p_in_q;
  3892. Process *p, *prevp;
  3893. found_p_in_q = 0;
  3894. for (prioq = 0; prioq < ERTS_NO_PROC_PRIO_LEVELS - 1; prioq++) {
  3895. prevp = NULL;
  3896. for (p = runq->procs.prio[prioq].first; p; p = p->next) {
  3897. ASSERT(p != p_not_in_q);
  3898. if (p == p_in_q)
  3899. found_p_in_q = 1;
  3900. switch (p->prio) {
  3901. case PRIORITY_MAX:
  3902. case PRIORITY_HIGH:
  3903. case PRIORITY_NORMAL:
  3904. ASSERT(prioq == p->prio);
  3905. break;
  3906. case PRIORITY_LOW:
  3907. ASSERT(prioq == PRIORITY_NORMAL);
  3908. break;
  3909. default:
  3910. ASSERT(!"Bad prio on process");
  3911. }
  3912. len[p->prio]++;
  3913. ASSERT(prevp == p->prev);
  3914. if (p->prev) {
  3915. ASSERT(p->prev->next == p);
  3916. }
  3917. else {
  3918. ASSERT(runq->procs.prio[prioq].first == p);
  3919. }
  3920. if (p->next) {
  3921. ASSERT(p->next->prev == p);
  3922. }
  3923. else {
  3924. ASSERT(runq->procs.prio[prioq].last == p);
  3925. }
  3926. ASSERT(p->run_queue == runq);
  3927. prevp = p;
  3928. }
  3929. }
  3930. ASSERT(!p_in_q || found_p_in_q);
  3931. tot_len = 0;
  3932. for (prio = 0; prio < ERTS_NO_PROC_PRIO_LEVELS; prio++) {
  3933. ASSERT(len[prio] == runq->procs.prio_info[prio].len);
  3934. if (len[prio]) {
  3935. ASSERT(runq->flags & (1 << prio));
  3936. }
  3937. else {
  3938. ASSERT(!(runq->flags & (1 << prio)));
  3939. }
  3940. tot_len += len[prio];
  3941. }
  3942. ASSERT(runq->procs.len == tot_len);
  3943. }
  3944. # define ERTS_DBG_CHK_PROCS_RUNQ(RQ) check_procs_runq((RQ), NULL, NULL)
  3945. # define ERTS_DBG_CHK_PROCS_RUNQ_PROC(RQ, P) check_procs_runq((RQ), (P), NULL)
  3946. # define ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(RQ, P) check_procs_runq((RQ), NULL, (P))
  3947. #else
  3948. # define ERTS_DBG_CHK_PROCS_RUNQ(RQ)
  3949. # define ERTS_DBG_CHK_PROCS_RUNQ_PROC(RQ, P)
  3950. # define ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(RQ, P)
  3951. #endif
  3952. static ERTS_INLINE void
  3953. enqueue_process(ErtsRunQueue *runq, Process *p)
  3954. {
  3955. ErtsRunPrioQueue *rpq;
  3956. ErtsRunQueueInfo *rqi;
  3957. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));
  3958. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
  3959. ASSERT(p->bound_runq || !(runq->flags & ERTS_RUNQ_FLG_SUSPENDED));
  3960. rqi = &runq->procs.prio_info[p->prio];
  3961. rqi->len++;
  3962. if (rqi->max_len < rqi->len)
  3963. rqi->max_len = rqi->len;
  3964. runq->procs.len++;
  3965. runq->len++;
  3966. if (runq->max_len < runq->len)
  3967. runq->max_len = runq->len;
  3968. runq->flags |= (1 << p->prio);
  3969. rpq = (p->prio == PRIORITY_LOW
  3970. ? &runq->procs.prio[PRIORITY_NORMAL]
  3971. : &runq->procs.prio[p->prio]);
  3972. p->next = NULL;
  3973. p->prev = rpq->last;
  3974. if (rpq->last)
  3975. rpq->last->next = p;
  3976. else
  3977. rpq->first = p;
  3978. rpq->last = p;
  3979. switch (p->status) {
  3980. case P_EXITING:
  3981. break;
  3982. case P_GARBING:
  3983. p->gcstatus = P_RUNABLE;
  3984. break;
  3985. default:
  3986. p->status = P_RUNABLE;
  3987. break;
  3988. }
  3989. #ifdef ERTS_SMP
  3990. p->status_flags |= ERTS_PROC_SFLG_INRUNQ;
  3991. #endif
  3992. ERTS_DBG_CHK_PROCS_RUNQ_PROC(runq, p);
  3993. }
  3994. static ERTS_INLINE int
  3995. dequeue_process(ErtsRunQueue *runq, Process *p)
  3996. {
  3997. ErtsRunPrioQueue *rpq;
  3998. int res = 1;
  3999. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));
  4000. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
  4001. ERTS_DBG_CHK_PROCS_RUNQ(runq);
  4002. rpq = &runq->procs.prio[p->prio == PRIORITY_LOW ? PRIORITY_NORMAL : p->prio];
  4003. if (p->prev) {
  4004. p->prev->next = p->next;
  4005. }
  4006. else if (rpq->first == p) {
  4007. rpq->first = p->next;
  4008. }
  4009. else {
  4010. res = 0;
  4011. }
  4012. if (p->next) {
  4013. p->next->prev = p->prev;
  4014. }
  4015. else if (rpq->last == p) {
  4016. rpq->last = p->prev;
  4017. }
  4018. else {
  4019. ASSERT(res == 0);
  4020. }
  4021. if (res) {
  4022. if (--runq->procs.prio_info[p->prio].len == 0)
  4023. runq->flags &= ~(1 << p->prio);
  4024. runq->procs.len--;
  4025. runq->len--;
  4026. #ifdef ERTS_SMP
  4027. p->status_flags &= ~ERTS_PROC_SFLG_INRUNQ;
  4028. #endif
  4029. }
  4030. ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(runq, p);
  4031. return res;
  4032. }
  4033. /* schedule a process */
  4034. static ERTS_INLINE ErtsRunQueue *
  4035. internal_add_to_runq(ErtsRunQueue *runq, Process *p)
  4036. {
  4037. Uint32 prev_status = p->status;
  4038. ErtsRunQueue *add_runq;
  4039. #ifdef ERTS_SMP
  4040. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
  4041. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(runq));
  4042. if (p->status_flags & ERTS_PROC_SFLG_INRUNQ)
  4043. return NULL;
  4044. else if (p->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING) {
  4045. ASSERT(p->status != P_SUSPENDED);
  4046. ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(runq, p);
  4047. p->status_flags |= ERTS_PROC_SFLG_PENDADD2SCHEDQ;
  4048. return NULL;
  4049. }
  4050. ASSERT(!p->scheduler_data);
  4051. #endif
  4052. ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(runq, p);
  4053. #ifndef ERTS_SMP
  4054. /* Never schedule a suspended process (ok in smp case) */
  4055. ASSERT(p->status != P_SUSPENDED);
  4056. add_runq = runq;
  4057. #else
  4058. ASSERT(!p->bound_runq || p->bound_runq == p->run_queue);
  4059. if (p->bound_runq) {
  4060. if (p->bound_runq == runq)
  4061. add_runq = runq;
  4062. else {
  4063. add_runq = p->bound_runq;
  4064. erts_smp_xrunq_lock(runq, add_runq);
  4065. }
  4066. }
  4067. else {
  4068. add_runq = erts_check_emigration_need(runq, p->prio);
  4069. if (!add_runq)
  4070. add_runq = runq;
  4071. else /* Process emigrated */
  4072. p->run_queue = add_runq;
  4073. }
  4074. #endif
  4075. /* Enqueue the process */
  4076. enqueue_process(add_runq, p);
  4077. if ((erts_system_profile_flags.runnable_procs)
  4078. && (prev_status == P_WAITING
  4079. || prev_status == P_SUSPENDED)) {
  4080. profile_runnable_proc(p, am_active);
  4081. }
  4082. if (add_runq != runq)
  4083. erts_smp_runq_unlock(add_runq);
  4084. return add_runq;
  4085. }
  4086. void
  4087. erts_add_to_runq(Process *p)
  4088. {
  4089. ErtsRunQueue *notify_runq;
  4090. ErtsRunQueue *runq = erts_get_runq_proc(p);
  4091. erts_smp_runq_lock(runq);
  4092. notify_runq = internal_add_to_runq(runq, p);
  4093. erts_smp_runq_unlock(runq);
  4094. smp_notify_inc_runq(notify_runq);
  4095. }
  4096. /* Possibly remove a scheduled process we need to suspend */
  4097. static int
  4098. remove_proc_from_runq(ErtsRunQueue *rq, Process *p, int to_inactive)
  4099. {
  4100. int res;
  4101. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
  4102. #ifdef ERTS_SMP
  4103. if (p->status_flags & ERTS_PROC_SFLG_PENDADD2SCHEDQ) {
  4104. p->status_flags &= ~ERTS_PROC_SFLG_PENDADD2SCHEDQ;
  4105. ASSERT(!remove_proc_from_runq(rq, p, 0));
  4106. return 1;
  4107. }
  4108. #endif
  4109. res = dequeue_process(rq, p);
  4110. if (res && erts_system_profile_flags.runnable_procs && to_inactive)
  4111. profile_runnable_proc(p, am_inactive);
  4112. #ifdef ERTS_SMP
  4113. ASSERT(!(p->status_flags & ERTS_PROC_SFLG_INRUNQ));
  4114. #endif
  4115. return res;
  4116. }
  4117. #ifdef ERTS_SMP
  4118. ErtsMigrateResult
  4119. erts_proc_migrate(Process *p, ErtsProcLocks *plcks,
  4120. ErtsRunQueue *from_rq, int *from_locked,
  4121. ErtsRunQueue *to_rq, int *to_locked)
  4122. {
  4123. ERTS_SMP_LC_ASSERT(*plcks == erts_proc_lc_my_proc_locks(p));
  4124. ERTS_SMP_LC_ASSERT((ERTS_PROC_LOCK_STATUS & *plcks)
  4125. || from_locked);
  4126. ERTS_SMP_LC_CHK_RUNQ_LOCK(from_rq, *from_locked);
  4127. ERTS_SMP_LC_CHK_RUNQ_LOCK(to_rq, *to_locked);
  4128. ASSERT(!erts_common_run_queue);
  4129. /*
  4130. * If we have the lock on the run queue to migrate to,
  4131. * check that it isn't suspended. If it is suspended,
  4132. * we will refuse to migrate to it anyway.
  4133. */
  4134. if (*to_locked && (to_rq->flags & ERTS_RUNQ_FLG_SUSPENDED))
  4135. return ERTS_MIGRATE_FAILED_RUNQ_SUSPENDED;
  4136. /* We need status lock on process and locks on both run queues */
  4137. if (!(ERTS_PROC_LOCK_STATUS & *plcks)) {
  4138. if (erts_smp_proc_trylock(p, ERTS_PROC_LOCK_STATUS) == EBUSY) {
  4139. ErtsProcLocks lcks = *plcks;
  4140. Eterm pid = p->id;
  4141. Process *proc = *plcks ? p : NULL;
  4142. if (*from_locked) {
  4143. *from_locked = 0;
  4144. erts_smp_runq_unlock(from_rq);
  4145. }
  4146. if (*to_locked) {
  4147. *to_locked = 0;
  4148. erts_smp_runq_unlock(to_rq);
  4149. }
  4150. proc = erts_pid2proc_opt(proc,
  4151. lcks,
  4152. pid,
  4153. lcks|ERTS_PROC_LOCK_STATUS,
  4154. ERTS_P2P_FLG_ALLOW_OTHER_X);
  4155. if (!proc) {
  4156. *plcks = 0;
  4157. return ERTS_MIGRATE_FAILED_NOT_IN_RUNQ;
  4158. }
  4159. ASSERT(proc == p);
  4160. }
  4161. *plcks |= ERTS_PROC_LOCK_STATUS;
  4162. }
  4163. ASSERT(!p->bound_runq);
  4164. ERTS_SMP_LC_CHK_RUNQ_LOCK(from_rq, *from_locked);
  4165. ERTS_SMP_LC_CHK_RUNQ_LOCK(to_rq, *to_locked);
  4166. if (p->run_queue != from_rq)
  4167. return ERTS_MIGRATE_FAILED_RUNQ_CHANGED;
  4168. if (!*from_locked || !*to_locked) {
  4169. if (from_rq < to_rq) {
  4170. if (!*to_locked) {
  4171. if (!*from_locked)
  4172. erts_smp_runq_lock(from_rq);
  4173. erts_smp_runq_lock(to_rq);
  4174. }
  4175. else if (erts_smp_runq_trylock(from_rq) == EBUSY) {
  4176. erts_smp_runq_unlock(to_rq);
  4177. erts_smp_runq_lock(from_rq);
  4178. erts_smp_runq_lock(to_rq);
  4179. }
  4180. }
  4181. else {
  4182. if (!*from_locked) {
  4183. if (!*to_locked)
  4184. erts_smp_runq_lock(to_rq);
  4185. erts_smp_runq_lock(from_rq);
  4186. }
  4187. else if (erts_smp_runq_trylock(to_rq) == EBUSY) {
  4188. erts_smp_runq_unlock(from_rq);
  4189. erts_smp_runq_lock(to_rq);
  4190. erts_smp_runq_lock(from_rq);
  4191. }
  4192. }
  4193. *to_locked = *from_locked = 1;
  4194. }
  4195. ERTS_SMP_LC_CHK_RUNQ_LOCK(from_rq, *from_locked);
  4196. ERTS_SMP_LC_CHK_RUNQ_LOCK(to_rq, *to_locked);
  4197. /* Ok we now got all locks we need; do it... */
  4198. /* Refuse to migrate to a suspended run queue */
  4199. if (to_rq->flags & ERTS_RUNQ_FLG_SUSPENDED)
  4200. return ERTS_MIGRATE_FAILED_RUNQ_SUSPENDED;
  4201. if ((p->runq_flags & ERTS_PROC_RUNQ_FLG_RUNNING)
  4202. || !(p->status_flags & ERTS_PROC_SFLG_INRUNQ))
  4203. return ERTS_MIGRATE_FAILED_NOT_IN_RUNQ;
  4204. dequeue_process(from_rq, p);
  4205. p->run_queue = to_rq;
  4206. enqueue_process(to_rq, p);
  4207. return ERTS_MIGRATE_SUCCESS;
  4208. }
  4209. #endif /* ERTS_SMP */
  4210. Eterm
  4211. erts_process_status(Process *c_p, ErtsProcLocks c_p_locks,
  4212. Process *rp, Eterm rpid)
  4213. {
  4214. Eterm res = am_undefined;
  4215. Process *p;
  4216. if (rp) {
  4217. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS
  4218. & erts_proc_lc_my_proc_locks(rp));
  4219. p = rp;
  4220. }
  4221. else {
  4222. p = erts_pid2proc_opt(c_p, c_p_locks,
  4223. rpid, ERTS_PROC_LOCK_STATUS,
  4224. ERTS_P2P_FLG_ALLOW_OTHER_X);
  4225. }
  4226. if (p) {
  4227. switch (p->status) {
  4228. case P_RUNABLE:
  4229. res = am_runnable;
  4230. break;
  4231. case P_WAITING:
  4232. res = am_waiting;
  4233. break;
  4234. case P_RUNNING:
  4235. res = am_running;
  4236. break;
  4237. case P_EXITING:
  4238. res = am_exiting;
  4239. break;
  4240. case P_GARBING:
  4241. res = am_garbage_collecting;
  4242. break;
  4243. case P_SUSPENDED:
  4244. res = am_suspended;
  4245. break;
  4246. case P_FREE: /* We cannot look up a process in P_FREE... */
  4247. default: /* Not a valid status... */
  4248. erl_exit(1, "Bad status (%b32u) found for process %T\n",
  4249. p->status, p->id);
  4250. break;
  4251. }
  4252. #ifdef ERTS_SMP
  4253. if (!rp && (p != c_p || !(ERTS_PROC_LOCK_STATUS & c_p_locks)))
  4254. erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
  4255. }
  4256. else {
  4257. int i;
  4258. ErtsSchedulerData *esdp;
  4259. if (erts_common_run_queue)
  4260. erts_smp_runq_lock(erts_common_run_queue);
  4261. for (i = 0; i < erts_no_schedulers; i++) {
  4262. esdp = ERTS_SCHEDULER_IX(i);
  4263. if (!erts_common_run_queue)
  4264. erts_smp_runq_lock(esdp->run_queue);
  4265. if (esdp->free_process && esdp->free_process->id == rpid) {
  4266. res = am_free;
  4267. if (!erts_common_run_queue)
  4268. erts_smp_runq_unlock(esdp->run_queue);
  4269. break;
  4270. }
  4271. if (!erts_common_run_queue)
  4272. erts_smp_runq_unlock(esdp->run_queue);
  4273. }
  4274. if (erts_common_run_queue)
  4275. erts_smp_runq_unlock(erts_common_run_queue);
  4276. #endif
  4277. }
  4278. return res;
  4279. }
  4280. /*
  4281. ** Suspend a process
  4282. ** If we are to suspend on a port the busy_port is the thing
  4283. ** otherwise busy_port is NIL
  4284. */
  4285. void
  4286. erts_suspend(Process* process, ErtsProcLocks process_locks, Port *busy_port)
  4287. {
  4288. ErtsRunQueue *rq;
  4289. ERTS_SMP_LC_ASSERT(process_locks == erts_proc_lc_my_proc_locks(process));
  4290. if (!(process_locks & ERTS_PROC_LOCK_STATUS))
  4291. erts_smp_proc_lock(process, ERTS_PROC_LOCK_STATUS);
  4292. rq = erts_get_runq_proc(process);
  4293. erts_smp_runq_lock(rq);
  4294. suspend_process(rq, process);
  4295. erts_smp_runq_unlock(rq);
  4296. if (busy_port)
  4297. erts_wake_process_later(busy_port, process);
  4298. if (!(process_locks & ERTS_PROC_LOCK_STATUS))
  4299. erts_smp_proc_unlock(process, ERTS_PROC_LOCK_STATUS);
  4300. }
  4301. void
  4302. erts_resume(Process* process, ErtsProcLocks process_locks)
  4303. {
  4304. ERTS_SMP_LC_ASSERT(process_locks == erts_proc_lc_my_proc_locks(process));
  4305. if (!(process_locks & ERTS_PROC_LOCK_STATUS))
  4306. erts_smp_proc_lock(process, ERTS_PROC_LOCK_STATUS);
  4307. resume_process(process);
  4308. if (!(process_locks & ERTS_PROC_LOCK_STATUS))
  4309. erts_smp_proc_unlock(process, ERTS_PROC_LOCK_STATUS);
  4310. }
  4311. int
  4312. erts_resume_processes(ErtsProcList *plp)
  4313. {
  4314. int nresumed = 0;
  4315. while (plp) {
  4316. Process *proc;
  4317. ErtsProcList *fplp;
  4318. ASSERT(is_internal_pid(plp->pid));
  4319. proc = erts_pid2proc(NULL, 0, plp->pid, ERTS_PROC_LOCK_STATUS);
  4320. if (proc) {
  4321. if (proclist_same(plp, proc)) {
  4322. resume_process(proc);
  4323. nresumed++;
  4324. }
  4325. erts_smp_proc_unlock(proc, ERTS_PROC_LOCK_STATUS);
  4326. }
  4327. fplp = plp;
  4328. plp = plp->next;
  4329. proclist_destroy(fplp);
  4330. }
  4331. return nresumed;
  4332. }
  4333. Eterm
  4334. erts_get_process_priority(Process *p)
  4335. {
  4336. ErtsRunQueue *rq;
  4337. Eterm value;
  4338. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
  4339. rq = erts_get_runq_proc(p);
  4340. erts_smp_runq_lock(rq);
  4341. switch(p->prio) {
  4342. case PRIORITY_MAX: value = am_max; break;
  4343. case PRIORITY_HIGH: value = am_high; break;
  4344. case PRIORITY_NORMAL: value = am_normal; break;
  4345. case PRIORITY_LOW: value = am_low; break;
  4346. default: ASSERT(0); value = am_undefined; break;
  4347. }
  4348. erts_smp_runq_unlock(rq);
  4349. return value;
  4350. }
  4351. Eterm
  4352. erts_set_process_priority(Process *p, Eterm new_value)
  4353. {
  4354. ErtsRunQueue *rq;
  4355. Eterm old_value;
  4356. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
  4357. rq = erts_get_runq_proc(p);
  4358. #ifdef ERTS_SMP
  4359. ASSERT(!(p->status_flags & ERTS_PROC_SFLG_INRUNQ));
  4360. #endif
  4361. erts_smp_runq_lock(rq);
  4362. switch(p->prio) {
  4363. case PRIORITY_MAX: old_value = am_max; break;
  4364. case PRIORITY_HIGH: old_value = am_high; break;
  4365. case PRIORITY_NORMAL: old_value = am_normal; break;
  4366. case PRIORITY_LOW: old_value = am_low; break;
  4367. default: ASSERT(0); old_value = am_undefined; break;
  4368. }
  4369. switch (new_value) {
  4370. case am_max: p->prio = PRIORITY_MAX; break;
  4371. case am_high: p->prio = PRIORITY_HIGH; break;
  4372. case am_normal: p->prio = PRIORITY_NORMAL; break;
  4373. case am_low: p->prio = PRIORITY_LOW; break;
  4374. default: old_value = THE_NON_VALUE; break;
  4375. }
  4376. erts_smp_runq_unlock(rq);
  4377. return old_value;
  4378. }
  4379. /* note that P_RUNNING is only set so that we don't try to remove
  4380. ** running processes from the schedule queue if they exit - a running
  4381. ** process not being in the schedule queue!!
  4382. ** Schedule for up to INPUT_REDUCTIONS context switches,
  4383. ** return 1 if more to do.
  4384. */
  4385. /*
  4386. * schedule() is called from BEAM (process_main()) or HiPE
  4387. * (hipe_mode_switch()) when the current process is to be
  4388. * replaced by a new process. 'calls' is the number of reduction
  4389. * steps the current process consumed.
  4390. * schedule() returns the new process, and the new process'
  4391. * ->fcalls field is initialised with its allowable number of
  4392. * reduction steps.
  4393. *
  4394. * When no process is runnable, or when sufficiently many reduction
  4395. * steps have been made, schedule() calls erl_sys_schedule() to
  4396. * schedule system-level activities.
  4397. *
  4398. * We use the same queue for normal and low prio processes.
  4399. * We reschedule low prio processes a certain number of times
  4400. * so that normal processes get to run more frequently.
  4401. */
  4402. Process *schedule(Process *p, int calls)
  4403. {
  4404. ErtsRunQueue *rq;
  4405. ErtsRunPrioQueue *rpq;
  4406. erts_aint_t dt;
  4407. ErtsSchedulerData *esdp;
  4408. int context_reds;
  4409. int fcalls;
  4410. int input_reductions;
  4411. int actual_reds;
  4412. int reds;
  4413. if (ERTS_USE_MODIFIED_TIMING()) {
  4414. context_reds = ERTS_MODIFIED_TIMING_CONTEXT_REDS;
  4415. input_reductions = ERTS_MODIFIED_TIMING_INPUT_REDS;
  4416. }
  4417. else {
  4418. context_reds = CONTEXT_REDS;
  4419. input_reductions = INPUT_REDUCTIONS;
  4420. }
  4421. ERTS_SMP_LC_ASSERT(!ERTS_LC_IS_BLOCKING);
  4422. /*
  4423. * Clean up after the process being scheduled out.
  4424. */
  4425. if (!p) { /* NULL in the very first schedule() call */
  4426. esdp = erts_get_scheduler_data();
  4427. rq = erts_get_runq_current(esdp);
  4428. ASSERT(esdp);
  4429. fcalls = (int) erts_smp_atomic32_read(&function_calls);
  4430. actual_reds = reds = 0;
  4431. erts_smp_runq_lock(rq);
  4432. } else {
  4433. #ifdef ERTS_SMP
  4434. ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
  4435. esdp = p->scheduler_data;
  4436. ASSERT(esdp->current_process == p
  4437. || esdp->free_process == p);
  4438. #else
  4439. esdp = erts_scheduler_data;
  4440. ASSERT(esdp->current_process == p);
  4441. #endif
  4442. reds = actual_reds = calls - esdp->virtual_reds;
  4443. if (reds < ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST)
  4444. reds = ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST;
  4445. esdp->virtual_reds = 0;
  4446. fcalls = (int) erts_smp_atomic32_addtest(&function_calls, reds);
  4447. ASSERT(esdp && esdp == erts_get_scheduler_data());
  4448. rq = erts_get_runq_current(esdp);
  4449. p->reds += actual_reds;
  4450. erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
  4451. if ((erts_system_profile_flags.runnable_procs)
  4452. && (p->status == P_WAITING)) {
  4453. profile_runnable_proc(p, am_inactive);
  4454. }
  4455. if (IS_TRACED(p)) {
  4456. if (IS_TRACED_FL(p, F_TRACE_CALLS) && p->status != P_FREE) {
  4457. erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_OUT);
  4458. }
  4459. switch (p->status) {
  4460. case P_EXITING:
  4461. if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT))
  4462. trace_sched(p, am_out_exiting);
  4463. break;
  4464. case P_FREE:
  4465. if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT))
  4466. trace_sched(p, am_out_exited);
  4467. break;
  4468. default:
  4469. if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED))
  4470. trace_sched(p, am_out);
  4471. else if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS))
  4472. trace_virtual_sched(p, am_out);
  4473. break;
  4474. }
  4475. }
  4476. #ifdef ERTS_SMP
  4477. if (ERTS_PROC_PENDING_EXIT(p)) {
  4478. erts_handle_pending_exit(p,
  4479. ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
  4480. p->status_flags |= ERTS_PROC_SFLG_PENDADD2SCHEDQ;
  4481. }
  4482. if (p->pending_suspenders) {
  4483. handle_pending_suspend(p,
  4484. ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
  4485. ASSERT(!(p->status_flags & ERTS_PROC_SFLG_PENDADD2SCHEDQ)
  4486. || p->status != P_SUSPENDED);
  4487. }
  4488. #endif
  4489. erts_smp_runq_lock(rq);
  4490. ERTS_PROC_REDUCTIONS_EXECUTED(rq, p->prio, reds, actual_reds);
  4491. esdp->current_process = NULL;
  4492. #ifdef ERTS_SMP
  4493. p->scheduler_data = NULL;
  4494. p->runq_flags &= ~ERTS_PROC_RUNQ_FLG_RUNNING;
  4495. p->status_flags &= ~ERTS_PROC_SFLG_RUNNING;
  4496. if (p->status_flags & ERTS_PROC_SFLG_PENDADD2SCHEDQ) {
  4497. ErtsRunQueue *notify_runq;
  4498. p->status_flags &= ~ERTS_PROC_SFLG_PENDADD2SCHEDQ;
  4499. notify_runq = internal_add_to_runq(rq, p);
  4500. if (notify_runq != rq)
  4501. smp_notify_inc_runq(notify_runq);
  4502. }
  4503. #endif
  4504. if (p->status == P_FREE) {
  4505. #ifdef ERTS_SMP
  4506. ASSERT(esdp->free_process == p);
  4507. esdp->free_process = NULL;
  4508. erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
  4509. erts_smp_proc_dec_refc(p);
  4510. #else
  4511. erts_free_proc(p);
  4512. #endif
  4513. } else {
  4514. erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
  4515. }
  4516. #ifdef ERTS_SMP
  4517. {
  4518. ErtsProcList *pnd_xtrs = rq->procs.pending_exiters;
  4519. rq->procs.pending_exiters = NULL;
  4520. if (pnd_xtrs) {
  4521. erts_smp_runq_unlock(rq);
  4522. handle_pending_exiters(pnd_xtrs);
  4523. erts_smp_runq_lock(rq);
  4524. }
  4525. }
  4526. ASSERT(!esdp->free_process);
  4527. #endif
  4528. ASSERT(!esdp->current_process);
  4529. ERTS_SMP_CHK_NO_PROC_LOCKS;
  4530. dt = erts_do_time_read_and_reset();
  4531. if (dt) {
  4532. erts_smp_runq_unlock(rq);
  4533. erts_bump_timer(dt);
  4534. erts_smp_runq_lock(rq);
  4535. }
  4536. BM_STOP_TIMER(system);
  4537. }
  4538. ERTS_SMP_LC_ASSERT(!ERTS_LC_IS_BLOCKING);
  4539. check_activities_to_run: {
  4540. #ifdef ERTS_SMP
  4541. if (!(rq->flags & ERTS_RUNQ_FLG_SHARED_RUNQ)
  4542. && rq->check_balance_reds <= 0) {
  4543. check_balance(rq);
  4544. }
  4545. ERTS_SMP_LC_ASSERT(!ERTS_LC_IS_BLOCKING);
  4546. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  4547. if (rq->flags & ERTS_RUNQ_FLGS_IMMIGRATE_QMASK)
  4548. immigrate(rq);
  4549. continue_check_activities_to_run:
  4550. if (rq->flags & (ERTS_RUNQ_FLG_SHARED_RUNQ
  4551. | ERTS_RUNQ_FLG_CHK_CPU_BIND
  4552. | ERTS_RUNQ_FLG_SUSPENDED)) {
  4553. if ((rq->flags & ERTS_RUNQ_FLG_SUSPENDED)
  4554. || (erts_smp_atomic32_read(&esdp->ssi->flags)
  4555. & ERTS_SSI_FLG_SUSPENDED)) {
  4556. ASSERT(erts_smp_atomic32_read(&esdp->ssi->flags)
  4557. & ERTS_SSI_FLG_SUSPENDED);
  4558. suspend_scheduler(esdp);
  4559. }
  4560. if ((rq->flags & ERTS_RUNQ_FLG_CHK_CPU_BIND)
  4561. || erts_smp_atomic32_read(&esdp->chk_cpu_bind)) {
  4562. erts_sched_check_cpu_bind(esdp);
  4563. }
  4564. }
  4565. #if defined(ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK) \
  4566. || defined(ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK)
  4567. {
  4568. ErtsSchedulerSleepInfo *ssi = esdp->ssi;
  4569. erts_aint32_t aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  4570. if (aux_work) {
  4571. erts_smp_runq_unlock(rq);
  4572. #ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  4573. aux_work = blockable_aux_work(esdp, ssi, aux_work);
  4574. #endif
  4575. #ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
  4576. nonblockable_aux_work(esdp, ssi, aux_work);
  4577. #endif
  4578. erts_smp_runq_lock(rq);
  4579. }
  4580. }
  4581. #endif
  4582. erts_smp_chk_system_block(prepare_for_block,
  4583. resume_after_block,
  4584. (void *) rq);
  4585. ERTS_SMP_LC_ASSERT(!ERTS_LC_IS_BLOCKING);
  4586. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  4587. #endif
  4588. ASSERT(rq->len == rq->procs.len + rq->ports.info.len);
  4589. #ifndef ERTS_SMP
  4590. if (rq->len == 0 && !rq->misc.start)
  4591. goto do_sys_schedule;
  4592. #else /* ERTS_SMP */
  4593. if (rq->len == 0 && !rq->misc.start) {
  4594. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  4595. rq->wakeup_other = 0;
  4596. rq->wakeup_other_reds = 0;
  4597. empty_runq(rq);
  4598. if (rq->flags & (ERTS_RUNQ_FLG_SHARED_RUNQ
  4599. | ERTS_RUNQ_FLG_SUSPENDED)) {
  4600. if ((rq->flags & ERTS_RUNQ_FLG_SUSPENDED)
  4601. || (erts_smp_atomic32_read(&esdp->ssi->flags)
  4602. & ERTS_SSI_FLG_SUSPENDED)) {
  4603. ASSERT(erts_smp_atomic32_read(&esdp->ssi->flags)
  4604. & ERTS_SSI_FLG_SUSPENDED);
  4605. non_empty_runq(rq);
  4606. goto continue_check_activities_to_run;
  4607. }
  4608. }
  4609. else if (!(rq->flags & ERTS_RUNQ_FLG_INACTIVE)) {
  4610. /*
  4611. * Check for ERTS_RUNQ_FLG_SUSPENDED has to be done
  4612. * after trying to steal a task.
  4613. */
  4614. if (try_steal_task(rq)
  4615. || (rq->flags & ERTS_RUNQ_FLG_SUSPENDED)) {
  4616. non_empty_runq(rq);
  4617. goto continue_check_activities_to_run;
  4618. }
  4619. }
  4620. scheduler_wait(&fcalls, esdp, rq);
  4621. non_empty_runq(rq);
  4622. goto check_activities_to_run;
  4623. }
  4624. else
  4625. #endif /* ERTS_SMP */
  4626. if (fcalls > input_reductions && prepare_for_sys_schedule()) {
  4627. int runnable;
  4628. #ifdef ERTS_SMP
  4629. runnable = 1;
  4630. #else
  4631. do_sys_schedule:
  4632. runnable = rq->len != 0;
  4633. if (!runnable)
  4634. sched_waiting_sys(esdp->no, rq);
  4635. #endif
  4636. /*
  4637. * Schedule system-level activities.
  4638. */
  4639. erts_smp_atomic32_set(&function_calls, 0);
  4640. fcalls = 0;
  4641. ASSERT(!erts_port_task_have_outstanding_io_tasks());
  4642. #ifdef ERTS_SMP
  4643. /* erts_sys_schedule_interrupt(0); */
  4644. #endif
  4645. erts_smp_runq_unlock(rq);
  4646. erl_sys_schedule(runnable);
  4647. dt = erts_do_time_read_and_reset();
  4648. if (dt) erts_bump_timer(dt);
  4649. #ifdef ERTS_SMP
  4650. erts_smp_runq_lock(rq);
  4651. erts_smp_atomic32_set(&doing_sys_schedule, 0);
  4652. goto continue_check_activities_to_run;
  4653. #else
  4654. if (!runnable)
  4655. sched_active_sys(esdp->no, rq);
  4656. goto check_activities_to_run;
  4657. #endif
  4658. }
  4659. if (rq->misc.start)
  4660. exec_misc_ops(rq);
  4661. #ifdef ERTS_SMP
  4662. {
  4663. int wo_reds = rq->wakeup_other_reds;
  4664. if (wo_reds) {
  4665. if (rq->len < 2) {
  4666. rq->wakeup_other -= ERTS_WAKEUP_OTHER_DEC*wo_reds;
  4667. if (rq->wakeup_other < 0)
  4668. rq->wakeup_other = 0;
  4669. }
  4670. else if (rq->wakeup_other < wakeup_other_limit)
  4671. rq->wakeup_other += rq->len*wo_reds + ERTS_WAKEUP_OTHER_FIXED_INC;
  4672. else {
  4673. if (erts_common_run_queue) {
  4674. if (erts_common_run_queue->waiting)
  4675. wake_scheduler(erts_common_run_queue, 0, 1);
  4676. }
  4677. else if (erts_smp_atomic32_read(&no_empty_run_queues) != 0) {
  4678. wake_scheduler_on_empty_runq(rq);
  4679. rq->wakeup_other = 0;
  4680. }
  4681. rq->wakeup_other = 0;
  4682. }
  4683. }
  4684. rq->wakeup_other_reds = 0;
  4685. }
  4686. #endif
  4687. /*
  4688. * Find a new port to run.
  4689. */
  4690. if (rq->ports.info.len) {
  4691. int have_outstanding_io;
  4692. have_outstanding_io = erts_port_task_execute(rq, &esdp->current_port);
  4693. if (have_outstanding_io && fcalls > 2*input_reductions) {
  4694. /*
  4695. * If we have performed more than 2*INPUT_REDUCTIONS since
  4696. * last call to erl_sys_schedule() and we still haven't
  4697. * handled all I/O tasks we stop running processes and
  4698. * focus completely on ports.
  4699. *
  4700. * One could argue that this is a strange behavior. The
  4701. * reason for doing it this way is that it is similar
  4702. * to the behavior before port tasks were introduced.
  4703. * We don't want to change the behavior too much, at
  4704. * least not at the time of writing. This behavior
  4705. * might change in the future.
  4706. *
  4707. * /rickard
  4708. */
  4709. goto check_activities_to_run;
  4710. }
  4711. }
  4712. /*
  4713. * Find a new process to run.
  4714. */
  4715. pick_next_process:
  4716. ERTS_DBG_CHK_PROCS_RUNQ(rq);
  4717. switch (rq->flags & ERTS_RUNQ_FLGS_PROCS_QMASK) {
  4718. case MAX_BIT:
  4719. case MAX_BIT|HIGH_BIT:
  4720. case MAX_BIT|NORMAL_BIT:
  4721. case MAX_BIT|LOW_BIT:
  4722. case MAX_BIT|HIGH_BIT|NORMAL_BIT:
  4723. case MAX_BIT|HIGH_BIT|LOW_BIT:
  4724. case MAX_BIT|NORMAL_BIT|LOW_BIT:
  4725. case MAX_BIT|HIGH_BIT|NORMAL_BIT|LOW_BIT:
  4726. rpq = &rq->procs.prio[PRIORITY_MAX];
  4727. break;
  4728. case HIGH_BIT:
  4729. case HIGH_BIT|NORMAL_BIT:
  4730. case HIGH_BIT|LOW_BIT:
  4731. case HIGH_BIT|NORMAL_BIT|LOW_BIT:
  4732. rpq = &rq->procs.prio[PRIORITY_HIGH];
  4733. break;
  4734. case NORMAL_BIT:
  4735. rpq = &rq->procs.prio[PRIORITY_NORMAL];
  4736. break;
  4737. case LOW_BIT:
  4738. rpq = &rq->procs.prio[PRIORITY_NORMAL];
  4739. break;
  4740. case NORMAL_BIT|LOW_BIT:
  4741. rpq = &rq->procs.prio[PRIORITY_NORMAL];
  4742. ASSERT(rpq->first != NULL);
  4743. p = rpq->first;
  4744. if (p->prio == PRIORITY_LOW) {
  4745. if (p == rpq->last || p->skipped >= RESCHEDULE_LOW-1)
  4746. p->skipped = 0;
  4747. else {
  4748. /* skip it */
  4749. p->skipped++;
  4750. rpq->first = p->next;
  4751. rpq->first->prev = NULL;
  4752. rpq->last->next = p;
  4753. p->prev = rpq->last;
  4754. p->next = NULL;
  4755. rpq->last = p;
  4756. goto pick_next_process;
  4757. }
  4758. }
  4759. break;
  4760. case 0: /* No process at all */
  4761. default:
  4762. ASSERT((rq->flags & ERTS_RUNQ_FLGS_PROCS_QMASK) == 0);
  4763. ASSERT(rq->procs.len == 0);
  4764. goto check_activities_to_run;
  4765. }
  4766. BM_START_TIMER(system);
  4767. /*
  4768. * Take the chosen process out of the queue.
  4769. */
  4770. ASSERT(rpq->first); /* Wrong qmask in rq->flags? */
  4771. p = rpq->first;
  4772. #ifdef ERTS_SMP
  4773. ERTS_SMP_LC_ASSERT(rq == p->run_queue);
  4774. #endif
  4775. rpq->first = p->next;
  4776. if (!rpq->first)
  4777. rpq->last = NULL;
  4778. else
  4779. rpq->first->prev = NULL;
  4780. p->next = p->prev = NULL;
  4781. if (--rq->procs.prio_info[p->prio].len == 0)
  4782. rq->flags &= ~(1 << p->prio);
  4783. ASSERT(rq->procs.len > 0);
  4784. rq->procs.len--;
  4785. ASSERT(rq->len > 0);
  4786. rq->len--;
  4787. {
  4788. Uint32 ee_flgs = (ERTS_RUNQ_FLG_EVACUATE(p->prio)
  4789. | ERTS_RUNQ_FLG_EMIGRATE(p->prio));
  4790. if ((rq->flags & (ERTS_RUNQ_FLG_SUSPENDED|ee_flgs)) == ee_flgs)
  4791. ERTS_UNSET_RUNQ_FLG_EVACUATE(rq->flags, p->prio);
  4792. }
  4793. ERTS_DBG_CHK_PROCS_RUNQ_NOPROC(rq, p);
  4794. rq->procs.context_switches++;
  4795. esdp->current_process = p;
  4796. #ifdef ERTS_SMP
  4797. p->runq_flags |= ERTS_PROC_RUNQ_FLG_RUNNING;
  4798. erts_smp_runq_unlock(rq);
  4799. ERTS_SMP_CHK_NO_PROC_LOCKS;
  4800. erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
  4801. if (erts_sched_stat.enabled) {
  4802. UWord old = ERTS_PROC_SCHED_ID(p,
  4803. (ERTS_PROC_LOCK_MAIN
  4804. | ERTS_PROC_LOCK_STATUS),
  4805. (UWord) esdp->no);
  4806. int migrated = old && old != esdp->no;
  4807. erts_smp_spin_lock(&erts_sched_stat.lock);
  4808. erts_sched_stat.prio[p->prio].total_executed++;
  4809. erts_sched_stat.prio[p->prio].executed++;
  4810. if (migrated) {
  4811. erts_sched_stat.prio[p->prio].total_migrated++;
  4812. erts_sched_stat.prio[p->prio].migrated++;
  4813. }
  4814. erts_smp_spin_unlock(&erts_sched_stat.lock);
  4815. }
  4816. p->status_flags |= ERTS_PROC_SFLG_RUNNING;
  4817. p->status_flags &= ~ERTS_PROC_SFLG_INRUNQ;
  4818. if (ERTS_PROC_PENDING_EXIT(p)) {
  4819. erts_handle_pending_exit(p,
  4820. ERTS_PROC_LOCK_MAIN|ERTS_PROC_LOCK_STATUS);
  4821. }
  4822. ASSERT(!p->scheduler_data);
  4823. p->scheduler_data = esdp;
  4824. #endif
  4825. ASSERT(p->status != P_SUSPENDED); /* Never run a suspended process */
  4826. ACTIVATE(p);
  4827. reds = context_reds;
  4828. if (IS_TRACED(p)) {
  4829. switch (p->status) {
  4830. case P_EXITING:
  4831. if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_EXIT))
  4832. trace_sched(p, am_in_exiting);
  4833. break;
  4834. default:
  4835. if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED))
  4836. trace_sched(p, am_in);
  4837. else if (ARE_TRACE_FLAGS_ON(p, F_TRACE_SCHED_PROCS))
  4838. trace_virtual_sched(p, am_in);
  4839. break;
  4840. }
  4841. if (IS_TRACED_FL(p, F_TRACE_CALLS)) {
  4842. erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_IN);
  4843. }
  4844. }
  4845. if (p->status != P_EXITING)
  4846. p->status = P_RUNNING;
  4847. erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
  4848. #ifdef ERTS_SMP
  4849. if (is_not_nil(p->tracer_proc))
  4850. erts_check_my_tracer_proc(p);
  4851. #endif
  4852. if (!ERTS_PROC_IS_EXITING(p)
  4853. && ((FLAGS(p) & F_FORCE_GC)
  4854. || (MSO(p).overhead > BIN_VHEAP_SZ(p)))) {
  4855. reds -= erts_garbage_collect(p, 0, p->arg_reg, p->arity);
  4856. if (reds < 0) {
  4857. reds = 1;
  4858. }
  4859. }
  4860. p->fcalls = reds;
  4861. ASSERT(IS_ACTIVE(p));
  4862. ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
  4863. return p;
  4864. }
  4865. }
  4866. void
  4867. erts_sched_stat_modify(int what)
  4868. {
  4869. int ix;
  4870. switch (what) {
  4871. case ERTS_SCHED_STAT_MODIFY_ENABLE:
  4872. erts_smp_block_system(0);
  4873. erts_sched_stat.enabled = 1;
  4874. erts_smp_release_system();
  4875. break;
  4876. case ERTS_SCHED_STAT_MODIFY_DISABLE:
  4877. erts_smp_block_system(0);
  4878. erts_sched_stat.enabled = 1;
  4879. erts_smp_release_system();
  4880. break;
  4881. case ERTS_SCHED_STAT_MODIFY_CLEAR:
  4882. erts_smp_spin_lock(&erts_sched_stat.lock);
  4883. for (ix = 0; ix < ERTS_NO_PRIO_LEVELS; ix++) {
  4884. erts_sched_stat.prio[ix].total_executed = 0;
  4885. erts_sched_stat.prio[ix].executed = 0;
  4886. erts_sched_stat.prio[ix].total_migrated = 0;
  4887. erts_sched_stat.prio[ix].migrated = 0;
  4888. }
  4889. erts_smp_spin_unlock(&erts_sched_stat.lock);
  4890. break;
  4891. }
  4892. }
  4893. Eterm
  4894. erts_sched_stat_term(Process *p, int total)
  4895. {
  4896. Uint sz;
  4897. Uint *hp;
  4898. Eterm prio[ERTS_NO_PRIO_LEVELS];
  4899. Uint executed[ERTS_NO_PRIO_LEVELS];
  4900. Uint migrated[ERTS_NO_PRIO_LEVELS];
  4901. erts_smp_spin_lock(&erts_sched_stat.lock);
  4902. if (total) {
  4903. int i;
  4904. for (i = 0; i < ERTS_NO_PRIO_LEVELS; i++) {
  4905. prio[i] = erts_sched_stat.prio[i].name;
  4906. executed[i] = erts_sched_stat.prio[i].total_executed;
  4907. migrated[i] = erts_sched_stat.prio[i].total_migrated;
  4908. }
  4909. }
  4910. else {
  4911. int i;
  4912. for (i = 0; i < ERTS_NO_PRIO_LEVELS; i++) {
  4913. prio[i] = erts_sched_stat.prio[i].name;
  4914. executed[i] = erts_sched_stat.prio[i].executed;
  4915. erts_sched_stat.prio[i].executed = 0;
  4916. migrated[i] = erts_sched_stat.prio[i].migrated;
  4917. erts_sched_stat.prio[i].migrated = 0;
  4918. }
  4919. }
  4920. erts_smp_spin_unlock(&erts_sched_stat.lock);
  4921. sz = 0;
  4922. (void) erts_bld_atom_2uint_3tup_list(NULL, &sz, ERTS_NO_PRIO_LEVELS,
  4923. prio, executed, migrated);
  4924. hp = HAlloc(p, sz);
  4925. return erts_bld_atom_2uint_3tup_list(&hp, NULL, ERTS_NO_PRIO_LEVELS,
  4926. prio, executed, migrated);
  4927. }
  4928. /*
  4929. * Scheduling of misc stuff
  4930. */
  4931. void
  4932. erts_schedule_misc_op(void (*func)(void *), void *arg)
  4933. {
  4934. ErtsRunQueue *rq = erts_get_runq_current(NULL);
  4935. ErtsMiscOpList *molp = misc_op_list_alloc();
  4936. if (!rq) {
  4937. /*
  4938. * This can only happen when the sys msg dispatcher
  4939. * thread schedules misc ops (this happens *very*
  4940. * seldom; only when trace drivers are unloaded).
  4941. */
  4942. rq = ERTS_RUNQ_IX(0);
  4943. }
  4944. erts_smp_runq_lock(rq);
  4945. while (rq->misc.evac_runq) {
  4946. ErtsRunQueue *tmp_rq = rq->misc.evac_runq;
  4947. erts_smp_runq_unlock(rq);
  4948. rq = tmp_rq;
  4949. erts_smp_runq_lock(rq);
  4950. }
  4951. ASSERT(!(rq->flags & ERTS_RUNQ_FLG_SUSPENDED));
  4952. molp->next = NULL;
  4953. molp->func = func;
  4954. molp->arg = arg;
  4955. if (rq->misc.end)
  4956. rq->misc.end->next = molp;
  4957. else
  4958. rq->misc.start = molp;
  4959. rq->misc.end = molp;
  4960. erts_smp_runq_unlock(rq);
  4961. smp_notify_inc_runq(rq);
  4962. }
  4963. static void
  4964. exec_misc_ops(ErtsRunQueue *rq)
  4965. {
  4966. int i;
  4967. ErtsMiscOpList *molp = rq->misc.start;
  4968. ErtsMiscOpList *tmp_molp = molp;
  4969. for (i = 0; i < ERTS_MAX_MISC_OPS-1; i++) {
  4970. if (!tmp_molp)
  4971. goto mtq;
  4972. tmp_molp = tmp_molp->next;
  4973. }
  4974. if (!tmp_molp) {
  4975. mtq:
  4976. rq->misc.start = NULL;
  4977. rq->misc.end = NULL;
  4978. }
  4979. else {
  4980. rq->misc.start = tmp_molp->next;
  4981. tmp_molp->next = NULL;
  4982. if (!rq->misc.start)
  4983. rq->misc.end = NULL;
  4984. }
  4985. erts_smp_runq_unlock(rq);
  4986. while (molp) {
  4987. tmp_molp = molp;
  4988. (*molp->func)(molp->arg);
  4989. molp = molp->next;
  4990. misc_op_list_free(tmp_molp);
  4991. }
  4992. erts_smp_runq_lock(rq);
  4993. }
  4994. Uint
  4995. erts_get_total_context_switches(void)
  4996. {
  4997. Uint res = 0;
  4998. ERTS_ATOMIC_FOREACH_RUNQ(rq, res += rq->procs.context_switches);
  4999. return res;
  5000. }
  5001. void
  5002. erts_get_total_reductions(Uint *redsp, Uint *diffp)
  5003. {
  5004. Uint reds = 0;
  5005. ERTS_ATOMIC_FOREACH_RUNQ_X(rq,
  5006. reds += rq->procs.reductions,
  5007. if (redsp) *redsp = reds;
  5008. if (diffp) *diffp = reds - last_reductions;
  5009. last_reductions = reds);
  5010. }
  5011. void
  5012. erts_get_exact_total_reductions(Process *c_p, Uint *redsp, Uint *diffp)
  5013. {
  5014. Uint reds = erts_current_reductions(c_p, c_p);
  5015. int ix;
  5016. erts_smp_proc_unlock(c_p, ERTS_PROC_LOCK_MAIN);
  5017. /*
  5018. * Wait for other schedulers to schedule out their processes
  5019. * and update 'reductions'.
  5020. */
  5021. erts_smp_block_system(0);
  5022. for (reds = 0, ix = 0; ix < erts_no_run_queues; ix++)
  5023. reds += ERTS_RUNQ_IX(ix)->procs.reductions;
  5024. if (redsp)
  5025. *redsp = reds;
  5026. if (diffp)
  5027. *diffp = reds - last_exact_reductions;
  5028. last_exact_reductions = reds;
  5029. erts_smp_release_system();
  5030. erts_smp_proc_lock(c_p, ERTS_PROC_LOCK_MAIN);
  5031. }
  5032. /*
  5033. * erts_test_next_pid() is only used for testing.
  5034. */
  5035. Sint
  5036. erts_test_next_pid(int set, Uint next)
  5037. {
  5038. Sint res;
  5039. Sint p_prev;
  5040. erts_smp_mtx_lock(&proc_tab_mtx);
  5041. if (!set) {
  5042. res = p_next < 0 ? -1 : (p_serial << p_serial_shift | p_next);
  5043. }
  5044. else {
  5045. p_serial = (Sint) ((next >> p_serial_shift) & p_serial_mask);
  5046. p_next = (Sint) (erts_process_tab_index_mask & next);
  5047. if (p_next >= erts_max_processes) {
  5048. p_next = 0;
  5049. p_serial++;
  5050. p_serial &= p_serial_mask;
  5051. }
  5052. p_prev = p_next;
  5053. do {
  5054. if (!process_tab[p_next])
  5055. break;
  5056. p_next++;
  5057. if(p_next >= erts_max_processes) {
  5058. p_next = 0;
  5059. p_serial++;
  5060. p_serial &= p_serial_mask;
  5061. }
  5062. } while (p_prev != p_next);
  5063. res = process_tab[p_next] ? -1 : (p_serial << p_serial_shift | p_next);
  5064. }
  5065. erts_smp_mtx_unlock(&proc_tab_mtx);
  5066. return res;
  5067. }
  5068. Uint erts_process_count(void)
  5069. {
  5070. erts_aint32_t res = erts_smp_atomic32_read(&process_count);
  5071. ASSERT(res >= 0);
  5072. return (Uint) res;
  5073. }
  5074. void
  5075. erts_free_proc(Process *p)
  5076. {
  5077. #if defined(ERTS_ENABLE_LOCK_COUNT) && defined(ERTS_SMP)
  5078. erts_lcnt_proc_lock_destroy(p);
  5079. #endif
  5080. erts_free(ERTS_ALC_T_PROC, (void *) p);
  5081. }
  5082. /*
  5083. ** Allocate process and find out where to place next process.
  5084. */
  5085. static Process*
  5086. alloc_process(void)
  5087. {
  5088. #ifdef ERTS_SMP
  5089. erts_pix_lock_t *pix_lock;
  5090. #endif
  5091. Process* p;
  5092. int p_prev;
  5093. erts_smp_mtx_lock(&proc_tab_mtx);
  5094. if (p_next == -1) {
  5095. p = NULL;
  5096. goto error; /* Process table full! */
  5097. }
  5098. p = (Process*) erts_alloc_fnf(ERTS_ALC_T_PROC, sizeof(Process));
  5099. if (!p)
  5100. goto error; /* ENOMEM */
  5101. p_last = p_next;
  5102. erts_get_emu_time(&p->started);
  5103. #ifdef ERTS_SMP
  5104. pix_lock = ERTS_PIX2PIXLOCK(p_next);
  5105. erts_pix_lock(pix_lock);
  5106. #endif
  5107. ASSERT(!process_tab[p_next]);
  5108. process_tab[p_next] = p;
  5109. erts_smp_atomic32_inc(&process_count);
  5110. p->id = make_internal_pid(p_serial << p_serial_shift | p_next);
  5111. if (p->id == ERTS_INVALID_PID) {
  5112. /* Do not use the invalid pid; change serial */
  5113. p_serial++;
  5114. p_serial &= p_serial_mask;
  5115. p->id = make_internal_pid(p_serial << p_serial_shift | p_next);
  5116. ASSERT(p->id != ERTS_INVALID_PID);
  5117. }
  5118. ASSERT(internal_pid_serial(p->id) <= (erts_use_r9_pids_ports
  5119. ? ERTS_MAX_PID_R9_SERIAL
  5120. : ERTS_MAX_PID_SERIAL));
  5121. #ifdef ERTS_SMP
  5122. erts_proc_lock_init(p); /* All locks locked */
  5123. erts_pix_unlock(pix_lock);
  5124. #endif
  5125. p->rstatus = P_FREE;
  5126. p->rcount = 0;
  5127. /*
  5128. * set p_next to the next available slot
  5129. */
  5130. p_prev = p_next;
  5131. while (1) {
  5132. p_next++;
  5133. if(p_next >= erts_max_processes) {
  5134. p_serial++;
  5135. p_serial &= p_serial_mask;
  5136. p_next = 0;
  5137. }
  5138. if (p_prev == p_next) {
  5139. p_next = -1;
  5140. break; /* Table full! */
  5141. }
  5142. if (!process_tab[p_next])
  5143. break; /* found a free slot */
  5144. }
  5145. error:
  5146. erts_smp_mtx_unlock(&proc_tab_mtx);
  5147. return p;
  5148. }
  5149. Eterm
  5150. erl_create_process(Process* parent, /* Parent of process (default group leader). */
  5151. Eterm mod, /* Tagged atom for module. */
  5152. Eterm func, /* Tagged atom for function. */
  5153. Eterm args, /* Arguments for function (must be well-formed list). */
  5154. ErlSpawnOpts* so) /* Options for spawn. */
  5155. {
  5156. ErtsRunQueue *rq, *notify_runq;
  5157. Process *p;
  5158. Sint arity; /* Number of arguments. */
  5159. #ifndef HYBRID
  5160. Uint arg_size; /* Size of arguments. */
  5161. #endif
  5162. Uint sz; /* Needed words on heap. */
  5163. Uint heap_need; /* Size needed on heap. */
  5164. Eterm res = THE_NON_VALUE;
  5165. #ifdef ERTS_SMP
  5166. erts_smp_proc_lock(parent, ERTS_PROC_LOCKS_ALL_MINOR);
  5167. #endif
  5168. #ifdef HYBRID
  5169. /*
  5170. * Copy the arguments to the global heap
  5171. * Since global GC might occur we want to do this before adding the
  5172. * new process to the process_tab.
  5173. */
  5174. BM_SWAP_TIMER(system,copy);
  5175. LAZY_COPY(parent,args);
  5176. BM_SWAP_TIMER(copy,system);
  5177. heap_need = 0;
  5178. #endif /* HYBRID */
  5179. /*
  5180. * Check for errors.
  5181. */
  5182. if (is_not_atom(mod) || is_not_atom(func) || ((arity = list_length(args)) < 0)) {
  5183. so->error_code = BADARG;
  5184. goto error;
  5185. }
  5186. p = alloc_process(); /* All proc locks are locked by this thread
  5187. on success */
  5188. if (!p) {
  5189. erts_send_error_to_logger_str(parent->group_leader,
  5190. "Too many processes\n");
  5191. so->error_code = SYSTEM_LIMIT;
  5192. goto error;
  5193. }
  5194. processes_busy++;
  5195. BM_COUNT(processes_spawned);
  5196. #ifndef HYBRID
  5197. BM_SWAP_TIMER(system,size);
  5198. arg_size = size_object(args);
  5199. BM_SWAP_TIMER(size,system);
  5200. heap_need = arg_size;
  5201. #endif
  5202. p->flags = erts_default_process_flags;
  5203. /* Scheduler queue mutex should be locked when changeing
  5204. * prio. In this case we don't have to lock it, since
  5205. * noone except us has access to the process.
  5206. */
  5207. if (so->flags & SPO_USE_ARGS) {
  5208. p->min_heap_size = so->min_heap_size;
  5209. p->min_vheap_size = so->min_vheap_size;
  5210. p->prio = so->priority;
  5211. p->max_gen_gcs = so->max_gen_gcs;
  5212. } else {
  5213. p->min_heap_size = H_MIN_SIZE;
  5214. p->min_vheap_size = BIN_VH_MIN_SIZE;
  5215. p->prio = PRIORITY_NORMAL;
  5216. p->max_gen_gcs = (Uint16) erts_smp_atomic32_read(&erts_max_gen_gcs);
  5217. }
  5218. p->skipped = 0;
  5219. ASSERT(p->min_heap_size == erts_next_heap_size(p->min_heap_size, 0));
  5220. p->initial[INITIAL_MOD] = mod;
  5221. p->initial[INITIAL_FUN] = func;
  5222. p->initial[INITIAL_ARI] = (Uint) arity;
  5223. /*
  5224. * Must initialize binary lists here before copying binaries to process.
  5225. */
  5226. p->off_heap.first = NULL;
  5227. p->off_heap.overhead = 0;
  5228. heap_need +=
  5229. IS_CONST(parent->group_leader) ? 0 : NC_HEAP_SIZE(parent->group_leader);
  5230. if (heap_need < p->min_heap_size) {
  5231. sz = heap_need = p->min_heap_size;
  5232. } else {
  5233. sz = erts_next_heap_size(heap_need, 0);
  5234. }
  5235. #ifdef HIPE
  5236. hipe_init_process(&p->hipe);
  5237. #ifdef ERTS_SMP
  5238. hipe_init_process_smp(&p->hipe_smp);
  5239. #endif
  5240. #endif
  5241. p->heap = (Eterm *) ERTS_HEAP_ALLOC(ERTS_ALC_T_HEAP, sizeof(Eterm)*sz);
  5242. p->old_hend = p->old_htop = p->old_heap = NULL;
  5243. p->high_water = p->heap;
  5244. #ifdef INCREMENTAL
  5245. p->scan_top = p->high_water;
  5246. #endif
  5247. p->gen_gcs = 0;
  5248. p->stop = p->hend = p->heap + sz;
  5249. p->htop = p->heap;
  5250. p->heap_sz = sz;
  5251. p->catches = 0;
  5252. p->bin_vheap_sz = p->min_vheap_size;
  5253. p->bin_old_vheap_sz = p->min_vheap_size;
  5254. p->bin_old_vheap = 0;
  5255. p->bin_vheap_mature = 0;
  5256. /* No need to initialize p->fcalls. */
  5257. p->current = p->initial+INITIAL_MOD;
  5258. p->i = (BeamInstr *) beam_apply;
  5259. p->cp = (BeamInstr *) beam_apply+1;
  5260. p->arg_reg = p->def_arg_reg;
  5261. p->max_arg_reg = sizeof(p->def_arg_reg)/sizeof(p->def_arg_reg[0]);
  5262. p->arg_reg[0] = mod;
  5263. p->arg_reg[1] = func;
  5264. BM_STOP_TIMER(system);
  5265. BM_MESSAGE(args,p,parent);
  5266. BM_START_TIMER(system);
  5267. #ifdef HYBRID
  5268. p->arg_reg[2] = args;
  5269. #ifdef INCREMENTAL
  5270. p->active = 0;
  5271. if (ptr_val(args) >= inc_fromspc && ptr_val(args) < inc_fromend)
  5272. INC_ACTIVATE(p);
  5273. #endif
  5274. #else
  5275. BM_SWAP_TIMER(system,copy);
  5276. p->arg_reg[2] = copy_struct(args, arg_size, &p->htop, &p->off_heap);
  5277. BM_MESSAGE_COPIED(arg_size);
  5278. BM_SWAP_TIMER(copy,system);
  5279. #endif
  5280. p->arity = 3;
  5281. p->fvalue = NIL;
  5282. p->freason = EXC_NULL;
  5283. p->ftrace = NIL;
  5284. p->reds = 0;
  5285. #ifdef ERTS_SMP
  5286. p->u.ptimer = NULL;
  5287. #else
  5288. sys_memset(&p->u.tm, 0, sizeof(ErlTimer));
  5289. #endif
  5290. p->reg = NULL;
  5291. p->nlinks = NULL;
  5292. p->monitors = NULL;
  5293. p->nodes_monitors = NULL;
  5294. p->suspend_monitors = NULL;
  5295. ASSERT(is_pid(parent->group_leader));
  5296. if (parent->group_leader == ERTS_INVALID_PID)
  5297. p->group_leader = p->id;
  5298. else {
  5299. /* Needs to be done after the heap has been set up */
  5300. p->group_leader =
  5301. IS_CONST(parent->group_leader)
  5302. ? parent->group_leader
  5303. : STORE_NC(&p->htop, &p->off_heap, parent->group_leader);
  5304. }
  5305. erts_get_default_tracing(&p->trace_flags, &p->tracer_proc);
  5306. p->msg.first = NULL;
  5307. p->msg.last = &p->msg.first;
  5308. p->msg.save = &p->msg.first;
  5309. p->msg.len = 0;
  5310. #ifdef ERTS_SMP
  5311. p->msg_inq.first = NULL;
  5312. p->msg_inq.last = &p->msg_inq.first;
  5313. p->msg_inq.len = 0;
  5314. p->bound_runq = NULL;
  5315. #endif
  5316. p->bif_timers = NULL;
  5317. p->mbuf = NULL;
  5318. p->mbuf_sz = 0;
  5319. p->psd = NULL;
  5320. p->dictionary = NULL;
  5321. p->seq_trace_lastcnt = 0;
  5322. p->seq_trace_clock = 0;
  5323. SEQ_TRACE_TOKEN(p) = NIL;
  5324. p->parent = parent->id == ERTS_INVALID_PID ? NIL : parent->id;
  5325. #ifdef HYBRID
  5326. p->rrma = NULL;
  5327. p->rrsrc = NULL;
  5328. p->nrr = 0;
  5329. p->rrsz = 0;
  5330. #endif
  5331. INIT_HOLE_CHECK(p);
  5332. #ifdef DEBUG
  5333. p->last_old_htop = NULL;
  5334. #endif
  5335. if (IS_TRACED(parent)) {
  5336. if (parent->trace_flags & F_TRACE_SOS) {
  5337. p->trace_flags |= (parent->trace_flags & TRACEE_FLAGS);
  5338. p->tracer_proc = parent->tracer_proc;
  5339. }
  5340. if (ARE_TRACE_FLAGS_ON(parent, F_TRACE_PROCS)) {
  5341. trace_proc_spawn(parent, p->id, mod, func, args);
  5342. }
  5343. if (parent->trace_flags & F_TRACE_SOS1) { /* Overrides TRACE_CHILDREN */
  5344. p->trace_flags |= (parent->trace_flags & TRACEE_FLAGS);
  5345. p->tracer_proc = parent->tracer_proc;
  5346. p->trace_flags &= ~(F_TRACE_SOS1 | F_TRACE_SOS);
  5347. parent->trace_flags &= ~(F_TRACE_SOS1 | F_TRACE_SOS);
  5348. }
  5349. }
  5350. /*
  5351. * Check if this process should be initially linked to its parent.
  5352. */
  5353. if (so->flags & SPO_LINK) {
  5354. #ifdef DEBUG
  5355. int ret;
  5356. #endif
  5357. if (IS_TRACED_FL(parent, F_TRACE_PROCS)) {
  5358. trace_proc(parent, parent, am_link, p->id);
  5359. }
  5360. #ifdef DEBUG
  5361. ret = erts_add_link(&(parent->nlinks), LINK_PID, p->id);
  5362. ASSERT(ret == 0);
  5363. ret = erts_add_link(&(p->nlinks), LINK_PID, parent->id);
  5364. ASSERT(ret == 0);
  5365. #else
  5366. erts_add_link(&(parent->nlinks), LINK_PID, p->id);
  5367. erts_add_link(&(p->nlinks), LINK_PID, parent->id);
  5368. #endif
  5369. if (IS_TRACED(parent)) {
  5370. if (parent->trace_flags & (F_TRACE_SOL|F_TRACE_SOL1)) {
  5371. p->trace_flags |= (parent->trace_flags & TRACEE_FLAGS);
  5372. p->tracer_proc = parent->tracer_proc; /* maybe steal */
  5373. if (parent->trace_flags & F_TRACE_SOL1) { /* maybe override */
  5374. p ->trace_flags &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
  5375. parent->trace_flags &= ~(F_TRACE_SOL1 | F_TRACE_SOL);
  5376. }
  5377. }
  5378. }
  5379. }
  5380. /*
  5381. * Test whether this process should be initially monitored by its parent.
  5382. */
  5383. if (so->flags & SPO_MONITOR) {
  5384. Eterm mref;
  5385. mref = erts_make_ref(parent);
  5386. erts_add_monitor(&(parent->monitors), MON_ORIGIN, mref, p->id, NIL);
  5387. erts_add_monitor(&(p->monitors), MON_TARGET, mref, parent->id, NIL);
  5388. so->mref = mref;
  5389. }
  5390. #ifdef HYBRID
  5391. /*
  5392. * Add process to the array of active processes.
  5393. */
  5394. ACTIVATE(p);
  5395. p->active_index = erts_num_active_procs++;
  5396. erts_active_procs[p->active_index] = p;
  5397. #endif
  5398. #ifdef ERTS_SMP
  5399. p->scheduler_data = NULL;
  5400. p->is_exiting = 0;
  5401. p->status_flags = 0;
  5402. p->runq_flags = 0;
  5403. p->suspendee = NIL;
  5404. p->pending_suspenders = NULL;
  5405. p->pending_exit.reason = THE_NON_VALUE;
  5406. p->pending_exit.bp = NULL;
  5407. #endif
  5408. #if !defined(NO_FPE_SIGNALS)
  5409. p->fp_exception = 0;
  5410. #endif
  5411. /*
  5412. * Schedule process for execution.
  5413. */
  5414. if (!((so->flags & SPO_USE_ARGS) && so->scheduler))
  5415. rq = erts_get_runq_proc(parent);
  5416. else {
  5417. int ix = so->scheduler-1;
  5418. ASSERT(0 <= ix && ix < erts_no_run_queues);
  5419. rq = ERTS_RUNQ_IX(ix);
  5420. p->bound_runq = rq;
  5421. }
  5422. erts_smp_runq_lock(rq);
  5423. #ifdef ERTS_SMP
  5424. p->run_queue = rq;
  5425. #endif
  5426. p->status = P_WAITING;
  5427. notify_runq = internal_add_to_runq(rq, p);
  5428. erts_smp_runq_unlock(rq);
  5429. smp_notify_inc_runq(notify_runq);
  5430. res = p->id;
  5431. erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
  5432. VERBOSE(DEBUG_PROCESSES, ("Created a new process: %T\n",p->id));
  5433. error:
  5434. erts_smp_proc_unlock(parent, ERTS_PROC_LOCKS_ALL_MINOR);
  5435. return res;
  5436. }
  5437. /*
  5438. * Initiates a pseudo process that can be used
  5439. * for arithmetic BIFs.
  5440. */
  5441. void erts_init_empty_process(Process *p)
  5442. {
  5443. p->htop = NULL;
  5444. p->stop = NULL;
  5445. p->hend = NULL;
  5446. p->heap = NULL;
  5447. p->gen_gcs = 0;
  5448. p->max_gen_gcs = 0;
  5449. p->min_heap_size = 0;
  5450. p->min_vheap_size = 0;
  5451. p->status = P_RUNABLE;
  5452. p->gcstatus = P_RUNABLE;
  5453. p->rstatus = P_RUNABLE;
  5454. p->rcount = 0;
  5455. p->id = ERTS_INVALID_PID;
  5456. p->prio = PRIORITY_NORMAL;
  5457. p->reds = 0;
  5458. p->tracer_proc = NIL;
  5459. p->trace_flags = F_INITIAL_TRACE_FLAGS;
  5460. p->group_leader = ERTS_INVALID_PID;
  5461. p->flags = 0;
  5462. p->fvalue = NIL;
  5463. p->freason = EXC_NULL;
  5464. p->ftrace = NIL;
  5465. p->fcalls = 0;
  5466. p->bin_vheap_sz = BIN_VH_MIN_SIZE;
  5467. p->bin_old_vheap_sz = BIN_VH_MIN_SIZE;
  5468. p->bin_old_vheap = 0;
  5469. p->bin_vheap_mature = 0;
  5470. #ifdef ERTS_SMP
  5471. p->u.ptimer = NULL;
  5472. p->bound_runq = NULL;
  5473. #else
  5474. memset(&(p->u.tm), 0, sizeof(ErlTimer));
  5475. #endif
  5476. p->next = NULL;
  5477. p->off_heap.first = NULL;
  5478. p->off_heap.overhead = 0;
  5479. p->reg = NULL;
  5480. p->heap_sz = 0;
  5481. p->high_water = NULL;
  5482. #ifdef INCREMENTAL
  5483. p->scan_top = NULL;
  5484. #endif
  5485. p->old_hend = NULL;
  5486. p->old_htop = NULL;
  5487. p->old_heap = NULL;
  5488. p->mbuf = NULL;
  5489. p->mbuf_sz = 0;
  5490. p->psd = NULL;
  5491. p->monitors = NULL;
  5492. p->nlinks = NULL; /* List of links */
  5493. p->nodes_monitors = NULL;
  5494. p->suspend_monitors = NULL;
  5495. p->msg.first = NULL;
  5496. p->msg.last = &p->msg.first;
  5497. p->msg.save = &p->msg.first;
  5498. p->msg.len = 0;
  5499. p->bif_timers = NULL;
  5500. p->dictionary = NULL;
  5501. p->seq_trace_clock = 0;
  5502. p->seq_trace_lastcnt = 0;
  5503. p->seq_trace_token = NIL;
  5504. p->initial[0] = 0;
  5505. p->initial[1] = 0;
  5506. p->initial[2] = 0;
  5507. p->catches = 0;
  5508. p->cp = NULL;
  5509. p->i = NULL;
  5510. p->current = NULL;
  5511. /*
  5512. * Saved x registers.
  5513. */
  5514. p->arity = 0;
  5515. p->arg_reg = NULL;
  5516. p->max_arg_reg = 0;
  5517. p->def_arg_reg[0] = 0;
  5518. p->def_arg_reg[1] = 0;
  5519. p->def_arg_reg[2] = 0;
  5520. p->def_arg_reg[3] = 0;
  5521. p->def_arg_reg[4] = 0;
  5522. p->def_arg_reg[5] = 0;
  5523. p->parent = NIL;
  5524. p->started.tv_sec = 0;
  5525. p->started.tv_usec = 0;
  5526. #ifdef HIPE
  5527. hipe_init_process(&p->hipe);
  5528. #ifdef ERTS_SMP
  5529. hipe_init_process_smp(&p->hipe_smp);
  5530. #endif
  5531. #endif
  5532. ACTIVATE(p);
  5533. #ifdef HYBRID
  5534. p->rrma = NULL;
  5535. p->rrsrc = NULL;
  5536. p->nrr = 0;
  5537. p->rrsz = 0;
  5538. #endif
  5539. INIT_HOLE_CHECK(p);
  5540. #ifdef DEBUG
  5541. p->last_old_htop = NULL;
  5542. #endif
  5543. #ifdef ERTS_SMP
  5544. p->scheduler_data = NULL;
  5545. p->is_exiting = 0;
  5546. p->status_flags = 0;
  5547. p->runq_flags = 0;
  5548. p->msg_inq.first = NULL;
  5549. p->msg_inq.last = &p->msg_inq.first;
  5550. p->msg_inq.len = 0;
  5551. p->suspendee = NIL;
  5552. p->pending_suspenders = NULL;
  5553. p->pending_exit.reason = THE_NON_VALUE;
  5554. p->pending_exit.bp = NULL;
  5555. erts_proc_lock_init(p);
  5556. erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
  5557. p->run_queue = ERTS_RUNQ_IX(0);
  5558. #endif
  5559. #if !defined(NO_FPE_SIGNALS)
  5560. p->fp_exception = 0;
  5561. #endif
  5562. }
  5563. #ifdef DEBUG
  5564. void
  5565. erts_debug_verify_clean_empty_process(Process* p)
  5566. {
  5567. /* Things that erts_cleanup_empty_process() will *not* cleanup... */
  5568. ASSERT(p->htop == NULL);
  5569. ASSERT(p->stop == NULL);
  5570. ASSERT(p->hend == NULL);
  5571. ASSERT(p->heap == NULL);
  5572. ASSERT(p->id == ERTS_INVALID_PID);
  5573. ASSERT(p->tracer_proc == NIL);
  5574. ASSERT(p->trace_flags == F_INITIAL_TRACE_FLAGS);
  5575. ASSERT(p->group_leader == ERTS_INVALID_PID);
  5576. ASSERT(p->next == NULL);
  5577. ASSERT(p->reg == NULL);
  5578. ASSERT(p->heap_sz == 0);
  5579. ASSERT(p->high_water == NULL);
  5580. #ifdef INCREMENTAL
  5581. ASSERT(p->scan_top == NULL);
  5582. #endif
  5583. ASSERT(p->old_hend == NULL);
  5584. ASSERT(p->old_htop == NULL);
  5585. ASSERT(p->old_heap == NULL);
  5586. ASSERT(p->monitors == NULL);
  5587. ASSERT(p->nlinks == NULL);
  5588. ASSERT(p->nodes_monitors == NULL);
  5589. ASSERT(p->suspend_monitors == NULL);
  5590. ASSERT(p->msg.first == NULL);
  5591. ASSERT(p->msg.len == 0);
  5592. ASSERT(p->bif_timers == NULL);
  5593. ASSERT(p->dictionary == NULL);
  5594. ASSERT(p->catches == 0);
  5595. ASSERT(p->cp == NULL);
  5596. ASSERT(p->i == NULL);
  5597. ASSERT(p->current == NULL);
  5598. ASSERT(p->parent == NIL);
  5599. #ifdef ERTS_SMP
  5600. ASSERT(p->msg_inq.first == NULL);
  5601. ASSERT(p->msg_inq.len == 0);
  5602. ASSERT(p->suspendee == NIL);
  5603. ASSERT(p->pending_suspenders == NULL);
  5604. ASSERT(p->pending_exit.reason == THE_NON_VALUE);
  5605. ASSERT(p->pending_exit.bp == NULL);
  5606. #endif
  5607. /* Thing that erts_cleanup_empty_process() cleans up */
  5608. ASSERT(p->off_heap.first == NULL);
  5609. ASSERT(p->off_heap.overhead == 0);
  5610. ASSERT(p->mbuf == NULL);
  5611. }
  5612. #endif
  5613. void
  5614. erts_cleanup_empty_process(Process* p)
  5615. {
  5616. /* We only check fields that are known to be used... */
  5617. erts_cleanup_offheap(&p->off_heap);
  5618. p->off_heap.first = NULL;
  5619. p->off_heap.overhead = 0;
  5620. if (p->mbuf != NULL) {
  5621. free_message_buffer(p->mbuf);
  5622. p->mbuf = NULL;
  5623. }
  5624. #if defined(ERTS_ENABLE_LOCK_COUNT) && defined(ERTS_SMP)
  5625. erts_lcnt_proc_lock_destroy(p);
  5626. #endif
  5627. #ifdef DEBUG
  5628. erts_debug_verify_clean_empty_process(p);
  5629. #endif
  5630. }
  5631. /*
  5632. * p must be the currently executing process.
  5633. */
  5634. static void
  5635. delete_process(Process* p)
  5636. {
  5637. ErlMessage* mp;
  5638. VERBOSE(DEBUG_PROCESSES, ("Removing process: %T\n",p->id));
  5639. /* Cleanup psd */
  5640. if (p->psd)
  5641. erts_free(ERTS_ALC_T_PSD, p->psd);
  5642. /* Clean binaries and funs */
  5643. erts_cleanup_offheap(&p->off_heap);
  5644. /*
  5645. * The mso list should not be used anymore, but if it is, make sure that
  5646. * we'll notice.
  5647. */
  5648. p->off_heap.first = (void *) 0x8DEFFACD;
  5649. if (p->arg_reg != p->def_arg_reg) {
  5650. erts_free(ERTS_ALC_T_ARG_REG, p->arg_reg);
  5651. }
  5652. /*
  5653. * Release heaps. Clobber contents in DEBUG build.
  5654. */
  5655. #ifdef DEBUG
  5656. sys_memset(p->heap, DEBUG_BAD_BYTE, p->heap_sz*sizeof(Eterm));
  5657. #endif
  5658. #ifdef HIPE
  5659. hipe_delete_process(&p->hipe);
  5660. #endif
  5661. ERTS_HEAP_FREE(ERTS_ALC_T_HEAP, (void*) p->heap, p->heap_sz*sizeof(Eterm));
  5662. if (p->old_heap != NULL) {
  5663. #ifdef DEBUG
  5664. sys_memset(p->old_heap, DEBUG_BAD_BYTE,
  5665. (p->old_hend-p->old_heap)*sizeof(Eterm));
  5666. #endif
  5667. ERTS_HEAP_FREE(ERTS_ALC_T_OLD_HEAP,
  5668. p->old_heap,
  5669. (p->old_hend-p->old_heap)*sizeof(Eterm));
  5670. }
  5671. /*
  5672. * Free all pending message buffers.
  5673. */
  5674. if (p->mbuf != NULL) {
  5675. free_message_buffer(p->mbuf);
  5676. }
  5677. erts_erase_dicts(p);
  5678. /* free all pending messages */
  5679. mp = p->msg.first;
  5680. while(mp != NULL) {
  5681. ErlMessage* next_mp = mp->next;
  5682. if (mp->data.attached) {
  5683. if (is_value(mp->m[0]))
  5684. free_message_buffer(mp->data.heap_frag);
  5685. else {
  5686. if (is_not_nil(mp->m[1])) {
  5687. ErlHeapFragment *heap_frag;
  5688. heap_frag = (ErlHeapFragment *) mp->data.dist_ext->ext_endp;
  5689. erts_cleanup_offheap(&heap_frag->off_heap);
  5690. }
  5691. erts_free_dist_ext_copy(mp->data.dist_ext);
  5692. }
  5693. }
  5694. free_message(mp);
  5695. mp = next_mp;
  5696. }
  5697. ASSERT(!p->monitors);
  5698. ASSERT(!p->nlinks);
  5699. ASSERT(!p->nodes_monitors);
  5700. ASSERT(!p->suspend_monitors);
  5701. p->fvalue = NIL;
  5702. #ifdef HYBRID
  5703. erts_active_procs[p->active_index] =
  5704. erts_active_procs[--erts_num_active_procs];
  5705. erts_active_procs[p->active_index]->active_index = p->active_index;
  5706. #ifdef INCREMENTAL
  5707. if (INC_IS_ACTIVE(p))
  5708. INC_DEACTIVATE(p);
  5709. #endif
  5710. if (p->rrma != NULL) {
  5711. erts_free(ERTS_ALC_T_ROOTSET,p->rrma);
  5712. erts_free(ERTS_ALC_T_ROOTSET,p->rrsrc);
  5713. }
  5714. #endif
  5715. }
  5716. static ERTS_INLINE void
  5717. set_proc_exiting(Process *p, Eterm reason, ErlHeapFragment *bp)
  5718. {
  5719. #ifdef ERTS_SMP
  5720. erts_pix_lock_t *pix_lock = ERTS_PID2PIXLOCK(p->id);
  5721. ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(p) == ERTS_PROC_LOCKS_ALL);
  5722. /*
  5723. * You are required to have all proc locks and the pix lock when going
  5724. * to status P_EXITING. This makes it is enough to take any lock when
  5725. * looking up a process (pid2proc()) to prevent the looked up process
  5726. * from exiting until the lock has been released.
  5727. */
  5728. erts_pix_lock(pix_lock);
  5729. p->is_exiting = 1;
  5730. #endif
  5731. p->status = P_EXITING;
  5732. #ifdef ERTS_SMP
  5733. erts_pix_unlock(pix_lock);
  5734. #endif
  5735. p->fvalue = reason;
  5736. if (bp)
  5737. erts_link_mbuf_to_proc(p, bp);
  5738. /*
  5739. * We used to set freason to EXC_EXIT here, but there is no need to
  5740. * save the stack trace since this process irreversibly is going to
  5741. * exit.
  5742. */
  5743. p->freason = EXTAG_EXIT;
  5744. KILL_CATCHES(p);
  5745. cancel_timer(p);
  5746. p->i = (BeamInstr *) beam_exit;
  5747. }
  5748. #ifdef ERTS_SMP
  5749. void
  5750. erts_handle_pending_exit(Process *c_p, ErtsProcLocks locks)
  5751. {
  5752. ErtsProcLocks xlocks;
  5753. ASSERT(is_value(c_p->pending_exit.reason));
  5754. ERTS_SMP_LC_ASSERT(erts_proc_lc_my_proc_locks(c_p) == locks);
  5755. ERTS_SMP_LC_ASSERT(locks & ERTS_PROC_LOCK_MAIN);
  5756. ERTS_SMP_LC_ASSERT(c_p->status != P_EXITING);
  5757. ERTS_SMP_LC_ASSERT(c_p->status != P_FREE);
  5758. /* Ensure that all locks on c_p are locked before proceeding... */
  5759. if (locks == ERTS_PROC_LOCKS_ALL)
  5760. xlocks = 0;
  5761. else {
  5762. xlocks = ~locks & ERTS_PROC_LOCKS_ALL;
  5763. if (erts_smp_proc_trylock(c_p, xlocks) == EBUSY) {
  5764. erts_smp_proc_unlock(c_p, locks & ~ERTS_PROC_LOCK_MAIN);
  5765. erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
  5766. }
  5767. }
  5768. set_proc_exiting(c_p, c_p->pending_exit.reason, c_p->pending_exit.bp);
  5769. c_p->pending_exit.reason = THE_NON_VALUE;
  5770. c_p->pending_exit.bp = NULL;
  5771. if (xlocks)
  5772. erts_smp_proc_unlock(c_p, xlocks);
  5773. }
  5774. static void
  5775. handle_pending_exiters(ErtsProcList *pnd_xtrs)
  5776. {
  5777. ErtsProcList *plp = pnd_xtrs;
  5778. ErtsProcList *free_plp;
  5779. while (plp) {
  5780. Process *p = erts_pid2proc(NULL, 0, plp->pid, ERTS_PROC_LOCKS_ALL);
  5781. if (p) {
  5782. if (proclist_same(plp, p)
  5783. && !(p->status_flags & ERTS_PROC_SFLG_RUNNING)) {
  5784. ASSERT(p->status_flags & ERTS_PROC_SFLG_INRUNQ);
  5785. ASSERT(ERTS_PROC_PENDING_EXIT(p));
  5786. erts_handle_pending_exit(p, ERTS_PROC_LOCKS_ALL);
  5787. }
  5788. erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
  5789. }
  5790. free_plp = plp;
  5791. plp = plp->next;
  5792. proclist_destroy(free_plp);
  5793. }
  5794. }
  5795. static void
  5796. save_pending_exiter(Process *p)
  5797. {
  5798. ErtsProcList *plp;
  5799. ErtsRunQueue *rq;
  5800. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_STATUS & erts_proc_lc_my_proc_locks(p));
  5801. rq = erts_get_runq_current(NULL);
  5802. plp = proclist_create(p);
  5803. erts_smp_runq_lock(rq);
  5804. plp->next = rq->procs.pending_exiters;
  5805. rq->procs.pending_exiters = plp;
  5806. erts_smp_runq_unlock(rq);
  5807. }
  5808. #endif
  5809. /*
  5810. * This function delivers an EXIT message to a process
  5811. * which is trapping EXITs.
  5812. */
  5813. static ERTS_INLINE void
  5814. send_exit_message(Process *to, ErtsProcLocks *to_locksp,
  5815. Eterm exit_term, Uint term_size, Eterm token)
  5816. {
  5817. if (token == NIL) {
  5818. Eterm* hp;
  5819. Eterm mess;
  5820. ErlHeapFragment* bp;
  5821. ErlOffHeap *ohp;
  5822. hp = erts_alloc_message_heap(term_size, &bp, &ohp, to, to_locksp);
  5823. mess = copy_struct(exit_term, term_size, &hp, ohp);
  5824. erts_queue_message(to, to_locksp, bp, mess, NIL);
  5825. } else {
  5826. ErlHeapFragment* bp;
  5827. Eterm* hp;
  5828. Eterm mess;
  5829. Eterm temp_token;
  5830. Uint sz_token;
  5831. ASSERT(is_tuple(token));
  5832. sz_token = size_object(token);
  5833. bp = new_message_buffer(term_size+sz_token);
  5834. hp = bp->mem;
  5835. mess = copy_struct(exit_term, term_size, &hp, &bp->off_heap);
  5836. /* the trace token must in this case be updated by the caller */
  5837. seq_trace_output(token, mess, SEQ_TRACE_SEND, to->id, NULL);
  5838. temp_token = copy_struct(token, sz_token, &hp, &bp->off_heap);
  5839. erts_queue_message(to, to_locksp, bp, mess, temp_token);
  5840. }
  5841. }
  5842. /*
  5843. *
  5844. * *** Exit signal behavior ***
  5845. *
  5846. * Exit signals are asynchronous (truly asynchronous in the
  5847. * SMP emulator). When the signal is received the receiver receives an
  5848. * 'EXIT' message if it is trapping exits; otherwise, it will either
  5849. * ignore the signal if the exit reason is normal, or go into an
  5850. * exiting state (status P_EXITING). When a process has gone into the
  5851. * exiting state it will not execute any more Erlang code, but it might
  5852. * take a while before it actually exits. The exit signal is being
  5853. * received when the 'EXIT' message is put in the message queue, the
  5854. * signal is dropped, or when it changes state into exiting. The time it
  5855. * is in the exiting state before actually exiting is undefined (it
  5856. * might take a really long time under certain conditions). The
  5857. * receiver of the exit signal does not break links or trigger monitors
  5858. * until it actually exits.
  5859. *
  5860. * Exit signals and other signals, e.g. messages, have to be received
  5861. * by a receiver in the same order as sent by a sender.
  5862. *
  5863. *
  5864. *
  5865. * Exit signal implementation in the SMP emulator:
  5866. *
  5867. * If the receiver is trapping exits, the signal is transformed
  5868. * into an 'EXIT' message and sent as a normal message, if the
  5869. * reason is normal the signal is dropped; otherwise, the process
  5870. * is determined to be exited. The interesting case is when the
  5871. * process is to be exited and this is what is described below.
  5872. *
  5873. * If it is possible, the receiver is set in the exiting state straight
  5874. * away and we are done; otherwise, the sender places the exit reason
  5875. * in the pending_exit field of the process struct and if necessary
  5876. * adds the receiver to the run queue. It is typically not possible
  5877. * to set a scheduled process or a process which we cannot get all locks
  5878. * on without releasing locks on it in an exiting state straight away.
  5879. *
  5880. * The receiver will poll the pending_exit field when it reach certain
  5881. * places during it's execution. When it discovers the pending exit
  5882. * it will change state into the exiting state. If the receiver wasn't
  5883. * scheduled when the pending exit was set, the first scheduler that
  5884. * schedules a new process will set the receiving process in the exiting
  5885. * state just before it schedules next process.
  5886. *
  5887. * When the exit signal is placed in the pending_exit field, the signal
  5888. * is considered as being in transit on the Erlang level. The signal is
  5889. * actually in some kind of semi transit state, since we have already
  5890. * determined how it should be received. It will exit the process no
  5891. * matter what if it is received (the process may exit by itself before
  5892. * reception of the exit signal). The signal is received when it is
  5893. * discovered in the pending_exit field by the receiver.
  5894. *
  5895. * The receiver have to poll the pending_exit field at least before:
  5896. * - moving messages from the message in queue to the private message
  5897. * queue. This in order to preserve signal order.
  5898. * - unlink. Otherwise the process might get exited on a link that
  5899. * have been removed.
  5900. * - changing the trap_exit flag to true. This in order to simplify the
  5901. * implementation; otherwise, we would have to transform the signal
  5902. * into an 'EXIT' message when setting the trap_exit flag to true. We
  5903. * would also have to maintain a queue of exit signals in transit.
  5904. * - being scheduled in or out.
  5905. */
  5906. static ERTS_INLINE int
  5907. send_exit_signal(Process *c_p, /* current process if and only
  5908. if reason is stored on it */
  5909. Eterm from, /* Id of sender of signal */
  5910. Process *rp, /* receiving process */
  5911. ErtsProcLocks *rp_locks,/* current locks on receiver */
  5912. Eterm reason, /* exit reason */
  5913. Eterm exit_tuple, /* Prebuild exit tuple
  5914. or THE_NON_VALUE */
  5915. Uint exit_tuple_sz, /* Size of prebuilt exit tuple
  5916. (if exit_tuple != THE_NON_VALUE) */
  5917. Eterm token, /* token */
  5918. Process *token_update, /* token updater */
  5919. Uint32 flags /* flags */
  5920. )
  5921. {
  5922. Eterm rsn = reason == am_kill ? am_killed : reason;
  5923. ERTS_SMP_LC_ASSERT(*rp_locks == erts_proc_lc_my_proc_locks(rp));
  5924. ERTS_SMP_LC_ASSERT((*rp_locks & ERTS_PROC_LOCKS_XSIG_SEND)
  5925. == ERTS_PROC_LOCKS_XSIG_SEND);
  5926. ASSERT(reason != THE_NON_VALUE);
  5927. if (ERTS_PROC_IS_TRAPPING_EXITS(rp)
  5928. && (reason != am_kill || (flags & ERTS_XSIG_FLG_IGN_KILL))) {
  5929. if (is_not_nil(token) && token_update)
  5930. seq_trace_update_send(token_update);
  5931. if (is_value(exit_tuple))
  5932. send_exit_message(rp, rp_locks, exit_tuple, exit_tuple_sz, token);
  5933. else
  5934. erts_deliver_exit_message(from, rp, rp_locks, rsn, token);
  5935. return 1; /* Receiver will get a message */
  5936. }
  5937. else if (reason != am_normal || (flags & ERTS_XSIG_FLG_NO_IGN_NORMAL)) {
  5938. #ifdef ERTS_SMP
  5939. if (!ERTS_PROC_PENDING_EXIT(rp) && !rp->is_exiting) {
  5940. ASSERT(rp->status != P_EXITING);
  5941. ASSERT(rp->status != P_FREE);
  5942. ASSERT(!rp->pending_exit.bp);
  5943. if (rp == c_p && (*rp_locks & ERTS_PROC_LOCK_MAIN)) {
  5944. /* Ensure that all locks on c_p are locked before
  5945. proceeding... */
  5946. if (*rp_locks != ERTS_PROC_LOCKS_ALL) {
  5947. ErtsProcLocks need_locks = (~(*rp_locks)
  5948. & ERTS_PROC_LOCKS_ALL);
  5949. if (erts_smp_proc_trylock(c_p, need_locks) == EBUSY) {
  5950. erts_smp_proc_unlock(c_p,
  5951. *rp_locks & ~ERTS_PROC_LOCK_MAIN);
  5952. erts_smp_proc_lock(c_p, ERTS_PROC_LOCKS_ALL_MINOR);
  5953. }
  5954. *rp_locks = ERTS_PROC_LOCKS_ALL;
  5955. }
  5956. set_proc_exiting(c_p, rsn, NULL);
  5957. }
  5958. else if (!(rp->status_flags & ERTS_PROC_SFLG_RUNNING)) {
  5959. /* Process not running ... */
  5960. ErtsProcLocks need_locks = ~(*rp_locks) & ERTS_PROC_LOCKS_ALL;
  5961. if (need_locks
  5962. && erts_smp_proc_trylock(rp, need_locks) == EBUSY) {
  5963. /* ... but we havn't got all locks on it ... */
  5964. save_pending_exiter(rp);
  5965. /*
  5966. * The pending exit will be discovered when next
  5967. * process is scheduled in
  5968. */
  5969. goto set_pending_exit;
  5970. }
  5971. else {
  5972. /* ...and we have all locks on it... */
  5973. *rp_locks = ERTS_PROC_LOCKS_ALL;
  5974. set_proc_exiting(rp,
  5975. (is_immed(rsn)
  5976. ? rsn
  5977. : copy_object(rsn, rp)),
  5978. NULL);
  5979. }
  5980. }
  5981. else { /* Process running... */
  5982. /*
  5983. * The pending exit will be discovered when the process
  5984. * is scheduled out if not discovered earlier.
  5985. */
  5986. set_pending_exit:
  5987. if (is_immed(rsn)) {
  5988. rp->pending_exit.reason = rsn;
  5989. }
  5990. else {
  5991. Eterm *hp;
  5992. Uint sz = size_object(rsn);
  5993. ErlHeapFragment *bp = new_message_buffer(sz);
  5994. hp = &bp->mem[0];
  5995. rp->pending_exit.reason = copy_struct(rsn,
  5996. sz,
  5997. &hp,
  5998. &bp->off_heap);
  5999. rp->pending_exit.bp = bp;
  6000. }
  6001. ASSERT(ERTS_PROC_PENDING_EXIT(rp));
  6002. }
  6003. if (!(rp->status_flags
  6004. & (ERTS_PROC_SFLG_INRUNQ|ERTS_PROC_SFLG_RUNNING)))
  6005. erts_add_to_runq(rp);
  6006. }
  6007. /* else:
  6008. *
  6009. * The receiver already has a pending exit (or is exiting)
  6010. * so we drop this signal.
  6011. *
  6012. * NOTE: dropping this exit signal is based on the assumption
  6013. * that the receiver *will* exit; either on the pending
  6014. * exit or by itself before seeing the pending exit.
  6015. */
  6016. #else /* !ERTS_SMP */
  6017. if (c_p == rp) {
  6018. rp->status = P_EXITING;
  6019. c_p->fvalue = rsn;
  6020. }
  6021. else if (rp->status != P_EXITING) { /* No recursive process exits /PaN */
  6022. Eterm old_status = rp->status;
  6023. set_proc_exiting(rp,
  6024. is_immed(rsn) ? rsn : copy_object(rsn, rp),
  6025. NULL);
  6026. ACTIVATE(rp);
  6027. if (old_status != P_RUNABLE && old_status != P_RUNNING)
  6028. erts_add_to_runq(rp);
  6029. }
  6030. #endif
  6031. return -1; /* Receiver will exit */
  6032. }
  6033. return 0; /* Receiver unaffected */
  6034. }
  6035. int
  6036. erts_send_exit_signal(Process *c_p,
  6037. Eterm from,
  6038. Process *rp,
  6039. ErtsProcLocks *rp_locks,
  6040. Eterm reason,
  6041. Eterm token,
  6042. Process *token_update,
  6043. Uint32 flags)
  6044. {
  6045. return send_exit_signal(c_p,
  6046. from,
  6047. rp,
  6048. rp_locks,
  6049. reason,
  6050. THE_NON_VALUE,
  6051. 0,
  6052. token,
  6053. token_update,
  6054. flags);
  6055. }
  6056. typedef struct {
  6057. Eterm reason;
  6058. Process *p;
  6059. } ExitMonitorContext;
  6060. static void doit_exit_monitor(ErtsMonitor *mon, void *vpcontext)
  6061. {
  6062. ExitMonitorContext *pcontext = vpcontext;
  6063. DistEntry *dep;
  6064. ErtsMonitor *rmon;
  6065. Process *rp;
  6066. if (mon->type == MON_ORIGIN) {
  6067. /* We are monitoring someone else, we need to demonitor that one.. */
  6068. if (is_atom(mon->pid)) { /* remote by name */
  6069. ASSERT(is_node_name_atom(mon->pid));
  6070. dep = erts_sysname_to_connected_dist_entry(mon->pid);
  6071. if (dep) {
  6072. erts_smp_de_links_lock(dep);
  6073. rmon = erts_remove_monitor(&(dep->monitors), mon->ref);
  6074. erts_smp_de_links_unlock(dep);
  6075. if (rmon) {
  6076. ErtsDSigData dsd;
  6077. int code = erts_dsig_prepare(&dsd, dep, NULL,
  6078. ERTS_DSP_NO_LOCK, 0);
  6079. if (code == ERTS_DSIG_PREP_CONNECTED) {
  6080. code = erts_dsig_send_demonitor(&dsd,
  6081. rmon->pid,
  6082. mon->name,
  6083. mon->ref,
  6084. 1);
  6085. ASSERT(code == ERTS_DSIG_SEND_OK);
  6086. }
  6087. erts_destroy_monitor(rmon);
  6088. }
  6089. erts_deref_dist_entry(dep);
  6090. }
  6091. } else {
  6092. ASSERT(is_pid(mon->pid));
  6093. if (is_internal_pid(mon->pid)) { /* local by pid or name */
  6094. rp = erts_pid2proc(NULL, 0, mon->pid, ERTS_PROC_LOCK_LINK);
  6095. if (!rp) {
  6096. goto done;
  6097. }
  6098. rmon = erts_remove_monitor(&(rp->monitors),mon->ref);
  6099. erts_smp_proc_unlock(rp, ERTS_PROC_LOCK_LINK);
  6100. if (rmon == NULL) {
  6101. goto done;
  6102. }
  6103. erts_destroy_monitor(rmon);
  6104. } else { /* remote by pid */
  6105. ASSERT(is_external_pid(mon->pid));
  6106. dep = external_pid_dist_entry(mon->pid);
  6107. ASSERT(dep != NULL);
  6108. if (dep) {
  6109. erts_smp_de_links_lock(dep);
  6110. rmon = erts_remove_monitor(&(dep->monitors), mon->ref);
  6111. erts_smp_de_links_unlock(dep);
  6112. if (rmon) {
  6113. ErtsDSigData dsd;
  6114. int code = erts_dsig_prepare(&dsd, dep, NULL,
  6115. ERTS_DSP_NO_LOCK, 0);
  6116. if (code == ERTS_DSIG_PREP_CONNECTED) {
  6117. code = erts_dsig_send_demonitor(&dsd,
  6118. rmon->pid,
  6119. mon->pid,
  6120. mon->ref,
  6121. 1);
  6122. ASSERT(code == ERTS_DSIG_SEND_OK);
  6123. }
  6124. erts_destroy_monitor(rmon);
  6125. }
  6126. }
  6127. }
  6128. }
  6129. } else { /* type == MON_TARGET */
  6130. ASSERT(mon->type == MON_TARGET);
  6131. ASSERT(is_pid(mon->pid) || is_internal_port(mon->pid));
  6132. if (is_internal_port(mon->pid)) {
  6133. Port *prt = erts_id2port(mon->pid, NULL, 0);
  6134. if (prt == NULL) {
  6135. goto done;
  6136. }
  6137. erts_fire_port_monitor(prt, mon->ref);
  6138. erts_port_release(prt);
  6139. } else if (is_internal_pid(mon->pid)) {/* local by name or pid */
  6140. Eterm watched;
  6141. DeclareTmpHeapNoproc(lhp,3);
  6142. ErtsProcLocks rp_locks = (ERTS_PROC_LOCK_LINK
  6143. | ERTS_PROC_LOCKS_MSG_SEND);
  6144. UseTmpHeapNoproc(3);
  6145. rp = erts_pid2proc(NULL, 0, mon->pid, rp_locks);
  6146. if (rp == NULL) {
  6147. goto done;
  6148. }
  6149. rmon = erts_remove_monitor(&(rp->monitors),mon->ref);
  6150. if (rmon) {
  6151. erts_destroy_monitor(rmon);
  6152. watched = (is_atom(mon->name)
  6153. ? TUPLE2(lhp, mon->name,
  6154. erts_this_dist_entry->sysname)
  6155. : pcontext->p->id);
  6156. erts_queue_monitor_message(rp, &rp_locks, mon->ref, am_process,
  6157. watched, pcontext->reason);
  6158. }
  6159. UnUseTmpHeapNoproc(3);
  6160. /* else: demonitor while we exited, i.e. do nothing... */
  6161. erts_smp_proc_unlock(rp, rp_locks);
  6162. } else { /* external by pid or name */
  6163. ASSERT(is_external_pid(mon->pid));
  6164. dep = external_pid_dist_entry(mon->pid);
  6165. ASSERT(dep != NULL);
  6166. if (dep) {
  6167. erts_smp_de_links_lock(dep);
  6168. rmon = erts_remove_monitor(&(dep->monitors), mon->ref);
  6169. erts_smp_de_links_unlock(dep);
  6170. if (rmon) {
  6171. ErtsDSigData dsd;
  6172. int code = erts_dsig_prepare(&dsd, dep, NULL,
  6173. ERTS_DSP_NO_LOCK, 0);
  6174. if (code == ERTS_DSIG_PREP_CONNECTED) {
  6175. code = erts_dsig_send_m_exit(&dsd,
  6176. mon->pid,
  6177. (rmon->name != NIL
  6178. ? rmon->name
  6179. : rmon->pid),
  6180. mon->ref,
  6181. pcontext->reason);
  6182. ASSERT(code == ERTS_DSIG_SEND_OK);
  6183. }
  6184. erts_destroy_monitor(rmon);
  6185. }
  6186. }
  6187. }
  6188. }
  6189. done:
  6190. /* As the monitors are previously removed from the process,
  6191. distribution operations will not cause monitors to disappear,
  6192. we can safely delete it. */
  6193. erts_destroy_monitor(mon);
  6194. }
  6195. typedef struct {
  6196. Process *p;
  6197. Eterm reason;
  6198. Eterm exit_tuple;
  6199. Uint exit_tuple_sz;
  6200. } ExitLinkContext;
  6201. static void doit_exit_link(ErtsLink *lnk, void *vpcontext)
  6202. {
  6203. ExitLinkContext *pcontext = vpcontext;
  6204. /* Unpack context, it's readonly */
  6205. Process *p = pcontext->p;
  6206. Eterm reason = pcontext->reason;
  6207. Eterm exit_tuple = pcontext->exit_tuple;
  6208. Uint exit_tuple_sz = pcontext->exit_tuple_sz;
  6209. Eterm item = lnk->pid;
  6210. ErtsLink *rlnk;
  6211. DistEntry *dep;
  6212. Process *rp;
  6213. switch(lnk->type) {
  6214. case LINK_PID:
  6215. if(is_internal_port(item)) {
  6216. Port *prt = erts_id2port(item, NULL, 0);
  6217. if (prt) {
  6218. rlnk = erts_remove_link(&prt->nlinks, p->id);
  6219. if (rlnk)
  6220. erts_destroy_link(rlnk);
  6221. erts_do_exit_port(prt, p->id, reason);
  6222. erts_port_release(prt);
  6223. }
  6224. }
  6225. else if(is_external_port(item)) {
  6226. erts_dsprintf_buf_t *dsbufp = erts_create_logger_dsbuf();
  6227. erts_dsprintf(dsbufp,
  6228. "Erroneous link between %T and external port %T "
  6229. "found\n",
  6230. p->id,
  6231. item);
  6232. erts_send_error_to_logger_nogl(dsbufp);
  6233. ASSERT(0); /* It isn't possible to setup such a link... */
  6234. }
  6235. else if (is_internal_pid(item)) {
  6236. ErtsProcLocks rp_locks = (ERTS_PROC_LOCK_LINK
  6237. | ERTS_PROC_LOCKS_XSIG_SEND);
  6238. rp = erts_pid2proc(NULL, 0, item, rp_locks);
  6239. if (rp) {
  6240. rlnk = erts_remove_link(&(rp->nlinks), p->id);
  6241. /* If rlnk == NULL, we got unlinked while exiting,
  6242. i.e., do nothing... */
  6243. if (rlnk) {
  6244. int xres;
  6245. erts_destroy_link(rlnk);
  6246. xres = send_exit_signal(NULL,
  6247. p->id,
  6248. rp,
  6249. &rp_locks,
  6250. reason,
  6251. exit_tuple,
  6252. exit_tuple_sz,
  6253. SEQ_TRACE_TOKEN(p),
  6254. p,
  6255. ERTS_XSIG_FLG_IGN_KILL);
  6256. if (xres >= 0 && IS_TRACED_FL(rp, F_TRACE_PROCS)) {
  6257. /* We didn't exit the process and it is traced */
  6258. if (IS_TRACED_FL(rp, F_TRACE_PROCS)) {
  6259. trace_proc(p, rp, am_getting_unlinked, p->id);
  6260. }
  6261. }
  6262. }
  6263. ASSERT(rp != p);
  6264. erts_smp_proc_unlock(rp, rp_locks);
  6265. }
  6266. }
  6267. else if (is_external_pid(item)) {
  6268. dep = external_pid_dist_entry(item);
  6269. if(dep != erts_this_dist_entry) {
  6270. ErtsDSigData dsd;
  6271. int code;
  6272. ErtsDistLinkData dld;
  6273. erts_remove_dist_link(&dld, p->id, item, dep);
  6274. erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
  6275. code = erts_dsig_prepare(&dsd, dep, p, ERTS_DSP_NO_LOCK, 0);
  6276. if (code == ERTS_DSIG_PREP_CONNECTED) {
  6277. code = erts_dsig_send_exit_tt(&dsd, p->id, item, reason,
  6278. SEQ_TRACE_TOKEN(p));
  6279. ASSERT(code == ERTS_DSIG_SEND_OK);
  6280. }
  6281. erts_smp_proc_unlock(p, ERTS_PROC_LOCK_MAIN);
  6282. erts_destroy_dist_link(&dld);
  6283. }
  6284. }
  6285. break;
  6286. case LINK_NODE:
  6287. ASSERT(is_node_name_atom(item));
  6288. dep = erts_sysname_to_connected_dist_entry(item);
  6289. if(dep) {
  6290. /* dist entries have node links in a separate structure to
  6291. avoid confusion */
  6292. erts_smp_de_links_lock(dep);
  6293. rlnk = erts_remove_link(&(dep->node_links), p->id);
  6294. erts_smp_de_links_unlock(dep);
  6295. if (rlnk)
  6296. erts_destroy_link(rlnk);
  6297. erts_deref_dist_entry(dep);
  6298. } else {
  6299. #ifndef ERTS_SMP
  6300. /* XXX Is this possible? Shouldn't this link
  6301. previously have been removed if the node
  6302. had previously been disconnected. */
  6303. ASSERT(0);
  6304. #endif
  6305. /* This is possible when smp support has been enabled,
  6306. and dist port and process exits simultaneously. */
  6307. }
  6308. break;
  6309. default:
  6310. erl_exit(1, "bad type in link list\n");
  6311. break;
  6312. }
  6313. erts_destroy_link(lnk);
  6314. }
  6315. static void
  6316. resume_suspend_monitor(ErtsSuspendMonitor *smon, void *vc_p)
  6317. {
  6318. Process *suspendee = erts_pid2proc((Process *) vc_p, ERTS_PROC_LOCK_MAIN,
  6319. smon->pid, ERTS_PROC_LOCK_STATUS);
  6320. if (suspendee) {
  6321. if (smon->active)
  6322. resume_process(suspendee);
  6323. erts_smp_proc_unlock(suspendee, ERTS_PROC_LOCK_STATUS);
  6324. }
  6325. erts_destroy_suspend_monitor(smon);
  6326. }
  6327. static void
  6328. continue_exit_process(Process *p
  6329. #ifdef ERTS_SMP
  6330. , erts_pix_lock_t *pix_lock
  6331. #endif
  6332. );
  6333. /* this function fishishes a process and propagates exit messages - called
  6334. by process_main when a process dies */
  6335. void
  6336. erts_do_exit_process(Process* p, Eterm reason)
  6337. {
  6338. #ifdef ERTS_SMP
  6339. erts_pix_lock_t *pix_lock = ERTS_PID2PIXLOCK(p->id);
  6340. #endif
  6341. p->arity = 0; /* No live registers */
  6342. p->fvalue = reason;
  6343. #ifdef ERTS_SMP
  6344. ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
  6345. /* By locking all locks (main lock is already locked) when going
  6346. to status P_EXITING, it is enough to take any lock when
  6347. looking up a process (erts_pid2proc()) to prevent the looked up
  6348. process from exiting until the lock has been released. */
  6349. erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
  6350. #endif
  6351. if (erts_system_profile_flags.runnable_procs && (p->status != P_WAITING)) {
  6352. profile_runnable_proc(p, am_inactive);
  6353. }
  6354. #ifdef ERTS_SMP
  6355. erts_pix_lock(pix_lock);
  6356. p->is_exiting = 1;
  6357. #endif
  6358. p->status = P_EXITING;
  6359. #ifdef ERTS_SMP
  6360. erts_pix_unlock(pix_lock);
  6361. if (ERTS_PROC_PENDING_EXIT(p)) {
  6362. /* Process exited before pending exit was received... */
  6363. p->pending_exit.reason = THE_NON_VALUE;
  6364. if (p->pending_exit.bp) {
  6365. free_message_buffer(p->pending_exit.bp);
  6366. p->pending_exit.bp = NULL;
  6367. }
  6368. }
  6369. cancel_suspend_of_suspendee(p, ERTS_PROC_LOCKS_ALL);
  6370. ERTS_SMP_MSGQ_MV_INQ2PRIVQ(p);
  6371. #endif
  6372. if (IS_TRACED(p)) {
  6373. if (IS_TRACED_FL(p, F_TRACE_CALLS))
  6374. erts_schedule_time_break(p, ERTS_BP_CALL_TIME_SCHEDULE_EXITING);
  6375. if (IS_TRACED_FL(p,F_TRACE_PROCS))
  6376. trace_proc(p, p, am_exit, reason);
  6377. }
  6378. erts_trace_check_exiting(p->id);
  6379. ASSERT((p->trace_flags & F_INITIAL_TRACE_FLAGS) == F_INITIAL_TRACE_FLAGS);
  6380. cancel_timer(p); /* Always cancel timer just in case */
  6381. /*
  6382. * The timer of this process can *not* be used anymore. The field used
  6383. * for the timer is now used for misc exiting data.
  6384. */
  6385. p->u.exit_data = NULL;
  6386. if (p->bif_timers)
  6387. erts_cancel_bif_timers(p, ERTS_PROC_LOCKS_ALL);
  6388. erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL_MINOR);
  6389. #ifdef ERTS_SMP
  6390. continue_exit_process(p, pix_lock);
  6391. #else
  6392. continue_exit_process(p);
  6393. #endif
  6394. }
  6395. void
  6396. erts_continue_exit_process(Process *c_p)
  6397. {
  6398. #ifdef ERTS_SMP
  6399. continue_exit_process(c_p, ERTS_PID2PIXLOCK(c_p->id));
  6400. #else
  6401. continue_exit_process(c_p);
  6402. #endif
  6403. }
  6404. static void
  6405. continue_exit_process(Process *p
  6406. #ifdef ERTS_SMP
  6407. , erts_pix_lock_t *pix_lock
  6408. #endif
  6409. )
  6410. {
  6411. ErtsLink* lnk;
  6412. ErtsMonitor *mon;
  6413. ErtsProcLocks curr_locks = ERTS_PROC_LOCK_MAIN;
  6414. Eterm reason = p->fvalue;
  6415. DistEntry *dep;
  6416. struct saved_calls *scb;
  6417. process_breakpoint_time_t *pbt;
  6418. #ifdef DEBUG
  6419. int yield_allowed = 1;
  6420. #endif
  6421. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN == erts_proc_lc_my_proc_locks(p));
  6422. #ifdef DEBUG
  6423. erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
  6424. ASSERT(p->status == P_EXITING);
  6425. erts_smp_proc_unlock(p, ERTS_PROC_LOCK_STATUS);
  6426. #endif
  6427. #ifdef ERTS_SMP
  6428. if (p->flags & F_HAVE_BLCKD_MSCHED) {
  6429. ErtsSchedSuspendResult ssr;
  6430. ssr = erts_block_multi_scheduling(p, ERTS_PROC_LOCK_MAIN, 0, 1);
  6431. switch (ssr) {
  6432. case ERTS_SCHDLR_SSPND_YIELD_RESTART:
  6433. goto yield;
  6434. case ERTS_SCHDLR_SSPND_DONE_MSCHED_BLOCKED:
  6435. case ERTS_SCHDLR_SSPND_YIELD_DONE_MSCHED_BLOCKED:
  6436. case ERTS_SCHDLR_SSPND_DONE:
  6437. case ERTS_SCHDLR_SSPND_YIELD_DONE:
  6438. p->flags &= ~F_HAVE_BLCKD_MSCHED;
  6439. break;
  6440. case ERTS_SCHDLR_SSPND_EINVAL:
  6441. default:
  6442. erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error: %d\n",
  6443. __FILE__, __LINE__, (int) ssr);
  6444. }
  6445. }
  6446. #endif
  6447. if (p->flags & F_USING_DB) {
  6448. if (erts_db_process_exiting(p, ERTS_PROC_LOCK_MAIN))
  6449. goto yield;
  6450. p->flags &= ~F_USING_DB;
  6451. }
  6452. if (p->flags & F_USING_DDLL) {
  6453. erts_ddll_proc_dead(p, ERTS_PROC_LOCK_MAIN);
  6454. p->flags &= ~F_USING_DDLL;
  6455. }
  6456. if (p->nodes_monitors) {
  6457. erts_delete_nodes_monitors(p, ERTS_PROC_LOCK_MAIN);
  6458. p->nodes_monitors = NULL;
  6459. }
  6460. if (p->suspend_monitors) {
  6461. erts_sweep_suspend_monitors(p->suspend_monitors,
  6462. resume_suspend_monitor,
  6463. p);
  6464. p->suspend_monitors = NULL;
  6465. }
  6466. /*
  6467. * The registered name *should* be the last "erlang resource" to
  6468. * cleanup.
  6469. */
  6470. if (p->reg) {
  6471. (void) erts_unregister_name(p, ERTS_PROC_LOCK_MAIN, NULL, THE_NON_VALUE);
  6472. ASSERT(!p->reg);
  6473. }
  6474. erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
  6475. curr_locks = ERTS_PROC_LOCKS_ALL;
  6476. /*
  6477. * From this point on we are no longer allowed to yield
  6478. * this process.
  6479. */
  6480. #ifdef DEBUG
  6481. yield_allowed = 0;
  6482. #endif
  6483. {
  6484. int pix;
  6485. /* Do *not* use erts_get_runq_proc() */
  6486. ErtsRunQueue *rq;
  6487. rq = erts_get_runq_current(ERTS_GET_SCHEDULER_DATA_FROM_PROC(p));
  6488. ASSERT(internal_pid_index(p->id) < erts_max_processes);
  6489. pix = internal_pid_index(p->id);
  6490. erts_smp_mtx_lock(&proc_tab_mtx);
  6491. erts_smp_runq_lock(rq);
  6492. #ifdef ERTS_SMP
  6493. erts_pix_lock(pix_lock);
  6494. ASSERT(p->scheduler_data);
  6495. ASSERT(p->scheduler_data->current_process == p);
  6496. ASSERT(p->scheduler_data->free_process == NULL);
  6497. p->scheduler_data->current_process = NULL;
  6498. p->scheduler_data->free_process = p;
  6499. p->status_flags = 0;
  6500. #endif
  6501. process_tab[pix] = NULL; /* Time of death! */
  6502. ASSERT(erts_smp_atomic32_read(&process_count) > 0);
  6503. erts_smp_atomic32_dec(&process_count);
  6504. #ifdef ERTS_SMP
  6505. erts_pix_unlock(pix_lock);
  6506. #endif
  6507. erts_smp_runq_unlock(rq);
  6508. if (p_next < 0) {
  6509. if (p_last >= p_next) {
  6510. p_serial++;
  6511. p_serial &= p_serial_mask;
  6512. }
  6513. p_next = pix;
  6514. }
  6515. ERTS_MAYBE_SAVE_TERMINATING_PROCESS(p);
  6516. erts_smp_mtx_unlock(&proc_tab_mtx);
  6517. }
  6518. /*
  6519. * All "erlang resources" have to be deallocated before this point,
  6520. * e.g. registered name, so monitoring and linked processes can
  6521. * be sure that all interesting resources have been deallocated
  6522. * when the monitors and/or links hit.
  6523. */
  6524. mon = p->monitors;
  6525. p->monitors = NULL; /* to avoid recursive deletion during traversal */
  6526. lnk = p->nlinks;
  6527. p->nlinks = NULL;
  6528. p->status = P_FREE;
  6529. dep = ((p->flags & F_DISTRIBUTION)
  6530. ? ERTS_PROC_SET_DIST_ENTRY(p, ERTS_PROC_LOCKS_ALL, NULL)
  6531. : NULL);
  6532. scb = ERTS_PROC_SET_SAVED_CALLS_BUF(p, ERTS_PROC_LOCKS_ALL, NULL);
  6533. pbt = ERTS_PROC_SET_CALL_TIME(p, ERTS_PROC_LOCKS_ALL, NULL);
  6534. erts_smp_proc_unlock(p, ERTS_PROC_LOCKS_ALL);
  6535. processes_busy--;
  6536. if (dep) {
  6537. erts_do_net_exits(dep, reason);
  6538. if(dep)
  6539. erts_deref_dist_entry(dep);
  6540. }
  6541. /*
  6542. * Pre-build the EXIT tuple if there are any links.
  6543. */
  6544. if (lnk) {
  6545. DeclareTmpHeap(tmp_heap,4,p);
  6546. Eterm exit_tuple;
  6547. Uint exit_tuple_sz;
  6548. Eterm* hp;
  6549. UseTmpHeap(4,p);
  6550. hp = &tmp_heap[0];
  6551. exit_tuple = TUPLE3(hp, am_EXIT, p->id, reason);
  6552. exit_tuple_sz = size_object(exit_tuple);
  6553. {
  6554. ExitLinkContext context = {p, reason, exit_tuple, exit_tuple_sz};
  6555. erts_sweep_links(lnk, &doit_exit_link, &context);
  6556. }
  6557. UnUseTmpHeap(4,p);
  6558. }
  6559. {
  6560. ExitMonitorContext context = {reason, p};
  6561. erts_sweep_monitors(mon,&doit_exit_monitor,&context); /* Allocates TmpHeap, but we
  6562. have none here */
  6563. }
  6564. if (scb)
  6565. erts_free(ERTS_ALC_T_CALLS_BUF, (void *) scb);
  6566. if (pbt)
  6567. erts_free(ERTS_ALC_T_BPD, (void *) pbt);
  6568. delete_process(p);
  6569. erts_smp_proc_lock(p, ERTS_PROC_LOCK_MAIN);
  6570. ERTS_SMP_CHK_HAVE_ONLY_MAIN_PROC_LOCK(p);
  6571. return;
  6572. yield:
  6573. #ifdef DEBUG
  6574. ASSERT(yield_allowed);
  6575. #endif
  6576. ERTS_SMP_LC_ASSERT(curr_locks == erts_proc_lc_my_proc_locks(p));
  6577. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & curr_locks);
  6578. ASSERT(p->status == P_EXITING);
  6579. p->i = (BeamInstr *) beam_continue_exit;
  6580. if (!(curr_locks & ERTS_PROC_LOCK_STATUS)) {
  6581. erts_smp_proc_lock(p, ERTS_PROC_LOCK_STATUS);
  6582. curr_locks |= ERTS_PROC_LOCK_STATUS;
  6583. }
  6584. erts_add_to_runq(p);
  6585. if (curr_locks != ERTS_PROC_LOCK_MAIN)
  6586. erts_smp_proc_unlock(p, ~ERTS_PROC_LOCK_MAIN & curr_locks);
  6587. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN == erts_proc_lc_my_proc_locks(p));
  6588. }
  6589. /* Callback for process timeout */
  6590. static void
  6591. timeout_proc(Process* p)
  6592. {
  6593. p->i = *((BeamInstr **) (UWord) p->def_arg_reg);
  6594. p->flags |= F_TIMO;
  6595. p->flags &= ~F_INSLPQUEUE;
  6596. if (p->status == P_WAITING)
  6597. erts_add_to_runq(p);
  6598. if (p->status == P_SUSPENDED)
  6599. p->rstatus = P_RUNABLE; /* MUST set resume status to runnable */
  6600. }
  6601. void
  6602. cancel_timer(Process* p)
  6603. {
  6604. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(p));
  6605. p->flags &= ~(F_INSLPQUEUE|F_TIMO);
  6606. #ifdef ERTS_SMP
  6607. erts_cancel_smp_ptimer(p->u.ptimer);
  6608. #else
  6609. erts_cancel_timer(&p->u.tm);
  6610. #endif
  6611. }
  6612. /*
  6613. * Insert a process into the time queue, with a timeout 'timeout' in ms.
  6614. */
  6615. void
  6616. set_timer(Process* p, Uint timeout)
  6617. {
  6618. ERTS_SMP_LC_ASSERT(ERTS_PROC_LOCK_MAIN & erts_proc_lc_my_proc_locks(p));
  6619. /* check for special case timeout=0 DONT ADD TO time queue */
  6620. if (timeout == 0) {
  6621. p->flags |= F_TIMO;
  6622. return;
  6623. }
  6624. p->flags |= F_INSLPQUEUE;
  6625. p->flags &= ~F_TIMO;
  6626. #ifdef ERTS_SMP
  6627. erts_create_smp_ptimer(&p->u.ptimer,
  6628. p->id,
  6629. (ErlTimeoutProc) timeout_proc,
  6630. timeout);
  6631. #else
  6632. erts_set_timer(&p->u.tm,
  6633. (ErlTimeoutProc) timeout_proc,
  6634. NULL,
  6635. (void*) p,
  6636. timeout);
  6637. #endif
  6638. }
  6639. /*
  6640. * Stack dump functions follow.
  6641. */
  6642. void
  6643. erts_stack_dump(int to, void *to_arg, Process *p)
  6644. {
  6645. Eterm* sp;
  6646. int yreg = -1;
  6647. if (p->trace_flags & F_SENSITIVE) {
  6648. return;
  6649. }
  6650. erts_program_counter_info(to, to_arg, p);
  6651. for (sp = p->stop; sp < STACK_START(p); sp++) {
  6652. yreg = stack_element_dump(to, to_arg, p, sp, yreg);
  6653. }
  6654. }
  6655. void
  6656. erts_program_counter_info(int to, void *to_arg, Process *p)
  6657. {
  6658. int i;
  6659. erts_print(to, to_arg, "Program counter: %p (", p->i);
  6660. print_function_from_pc(to, to_arg, p->i);
  6661. erts_print(to, to_arg, ")\n");
  6662. erts_print(to, to_arg, "CP: %p (", p->cp);
  6663. print_function_from_pc(to, to_arg, p->cp);
  6664. erts_print(to, to_arg, ")\n");
  6665. if (!((p->status == P_RUNNING) || (p->status == P_GARBING))) {
  6666. erts_print(to, to_arg, "arity = %d\n",p->arity);
  6667. if (!ERTS_IS_CRASH_DUMPING) {
  6668. /*
  6669. * Only print the arguments if we are not writing a
  6670. * crash dump file. The arguments cannot be interpreted
  6671. * by the crashdump_viewer application and will therefore
  6672. * only cause problems.
  6673. */
  6674. for (i = 0; i < p->arity; i++)
  6675. erts_print(to, to_arg, " %T\n", p->arg_reg[i]);
  6676. }
  6677. }
  6678. }
  6679. static void
  6680. print_function_from_pc(int to, void *to_arg, BeamInstr* x)
  6681. {
  6682. BeamInstr* addr = find_function_from_pc(x);
  6683. if (addr == NULL) {
  6684. if (x == beam_exit) {
  6685. erts_print(to, to_arg, "<terminate process>");
  6686. } else if (x == beam_continue_exit) {
  6687. erts_print(to, to_arg, "<continue terminate process>");
  6688. } else if (x == beam_apply+1) {
  6689. erts_print(to, to_arg, "<terminate process normally>");
  6690. } else if (x == 0) {
  6691. erts_print(to, to_arg, "invalid");
  6692. } else {
  6693. erts_print(to, to_arg, "unknown function");
  6694. }
  6695. } else {
  6696. erts_print(to, to_arg, "%T:%T/%d + %d",
  6697. addr[0], addr[1], addr[2], ((x-addr)-2) * sizeof(Eterm));
  6698. }
  6699. }
  6700. static int
  6701. stack_element_dump(int to, void *to_arg, Process* p, Eterm* sp, int yreg)
  6702. {
  6703. Eterm x = *sp;
  6704. if (yreg < 0 || is_CP(x)) {
  6705. erts_print(to, to_arg, "\n%p ", sp);
  6706. } else {
  6707. char sbuf[16];
  6708. sprintf(sbuf, "y(%d)", yreg);
  6709. erts_print(to, to_arg, "%-8s ", sbuf);
  6710. yreg++;
  6711. }
  6712. if (is_CP(x)) {
  6713. erts_print(to, to_arg, "Return addr %p (", (Eterm *) EXPAND_POINTER(x));
  6714. print_function_from_pc(to, to_arg, cp_val(x));
  6715. erts_print(to, to_arg, ")\n");
  6716. yreg = 0;
  6717. } else if is_catch(x) {
  6718. erts_print(to, to_arg, "Catch %p (", catch_pc(x));
  6719. print_function_from_pc(to, to_arg, catch_pc(x));
  6720. erts_print(to, to_arg, ")\n");
  6721. } else {
  6722. erts_print(to, to_arg, "%T\n", x);
  6723. }
  6724. return yreg;
  6725. }
  6726. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *\
  6727. * The processes/0 BIF implementation. *
  6728. \* */
  6729. #define ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED 25
  6730. #define ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE 1000
  6731. #define ERTS_PROCESSES_BIF_MIN_START_REDS \
  6732. (ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE \
  6733. / ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED)
  6734. #define ERTS_PROCESSES_BIF_TAB_FREE_TERM_PROC_REDS 1
  6735. #define ERTS_PROCESSES_BIF_INSPECT_TERM_PROC_PER_RED 10
  6736. #define ERTS_PROCESSES_INSPECT_TERM_PROC_MAX_REDS \
  6737. (ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE \
  6738. / ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED)
  6739. #define ERTS_PROCESSES_BIF_BUILD_RESULT_CONSES_PER_RED 75
  6740. #define ERTS_PROCS_DBG_DO_TRACE 0
  6741. #ifdef DEBUG
  6742. # define ERTS_PROCESSES_BIF_DEBUGLEVEL 100
  6743. #else
  6744. # define ERTS_PROCESSES_BIF_DEBUGLEVEL 0
  6745. #endif
  6746. #define ERTS_PROCS_DBGLVL_CHK_HALLOC 1
  6747. #define ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS 5
  6748. #define ERTS_PROCS_DBGLVL_CHK_PIDS 10
  6749. #define ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST 20
  6750. #define ERTS_PROCS_DBGLVL_CHK_RESLIST 20
  6751. #if ERTS_PROCESSES_BIF_DEBUGLEVEL == 0
  6752. # define ERTS_PROCS_ASSERT(EXP)
  6753. #else
  6754. # define ERTS_PROCS_ASSERT(EXP) \
  6755. ((void) ((EXP) \
  6756. ? 1 \
  6757. : (debug_processes_assert_error(#EXP, __FILE__, __LINE__), 0)))
  6758. #endif
  6759. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_HALLOC
  6760. # define ERTS_PROCS_DBG_SAVE_HEAP_ALLOC(PBDP, HP, SZ) \
  6761. do { \
  6762. ERTS_PROCS_ASSERT(!(PBDP)->debug.heap); \
  6763. ERTS_PROCS_ASSERT(!(PBDP)->debug.heap_size); \
  6764. (PBDP)->debug.heap = (HP); \
  6765. (PBDP)->debug.heap_size = (SZ); \
  6766. } while (0)
  6767. # define ERTS_PROCS_DBG_VERIFY_HEAP_ALLOC_USED(PBDP, HP) \
  6768. do { \
  6769. ERTS_PROCS_ASSERT((PBDP)->debug.heap); \
  6770. ERTS_PROCS_ASSERT((PBDP)->debug.heap_size); \
  6771. ERTS_PROCS_ASSERT((PBDP)->debug.heap + (PBDP)->debug.heap_size == (HP));\
  6772. (PBDP)->debug.heap = NULL; \
  6773. (PBDP)->debug.heap_size = 0; \
  6774. } while (0)
  6775. # define ERTS_PROCS_DBG_HEAP_ALLOC_INIT(PBDP) \
  6776. do { \
  6777. (PBDP)->debug.heap = NULL; \
  6778. (PBDP)->debug.heap_size = 0; \
  6779. } while (0)
  6780. #else
  6781. # define ERTS_PROCS_DBG_SAVE_HEAP_ALLOC(PBDP, HP, SZ)
  6782. # define ERTS_PROCS_DBG_VERIFY_HEAP_ALLOC_USED(PBDP, HP)
  6783. # define ERTS_PROCS_DBG_HEAP_ALLOC_INIT(PBDP)
  6784. #endif
  6785. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_RESLIST
  6786. # define ERTS_PROCS_DBG_CHK_RESLIST(R) debug_processes_check_res_list((R))
  6787. #else
  6788. # define ERTS_PROCS_DBG_CHK_RESLIST(R)
  6789. #endif
  6790. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_PIDS
  6791. # define ERTS_PROCS_DBG_SAVE_PIDS(PBDP) debug_processes_save_all_pids((PBDP))
  6792. # define ERTS_PROCS_DBG_VERIFY_PIDS(PBDP) \
  6793. do { \
  6794. if (!(PBDP)->debug.correct_pids_verified) \
  6795. debug_processes_verify_all_pids((PBDP)); \
  6796. } while (0)
  6797. # define ERTS_PROCS_DBG_CLEANUP_CHK_PIDS(PBDP) \
  6798. do { \
  6799. if ((PBDP)->debug.correct_pids) { \
  6800. erts_free(ERTS_ALC_T_PROCS_PIDS, \
  6801. (PBDP)->debug.correct_pids); \
  6802. (PBDP)->debug.correct_pids = NULL; \
  6803. } \
  6804. } while(0)
  6805. # define ERTS_PROCS_DBG_CHK_PIDS_INIT(PBDP) \
  6806. do { \
  6807. (PBDP)->debug.correct_pids_verified = 0; \
  6808. (PBDP)->debug.correct_pids = NULL; \
  6809. } while (0)
  6810. #else
  6811. # define ERTS_PROCS_DBG_SAVE_PIDS(PBDP)
  6812. # define ERTS_PROCS_DBG_VERIFY_PIDS(PBDP)
  6813. # define ERTS_PROCS_DBG_CLEANUP_CHK_PIDS(PBDP)
  6814. # define ERTS_PROCS_DBG_CHK_PIDS_INIT(PBDP)
  6815. #endif
  6816. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
  6817. # define ERTS_PROCS_DBG_CHK_PID_FOUND(PBDP, PID, TVP) \
  6818. debug_processes_check_found_pid((PBDP), (PID), (TVP), 1)
  6819. # define ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(PBDP, PID, TVP) \
  6820. debug_processes_check_found_pid((PBDP), (PID), (TVP), 0)
  6821. #else
  6822. # define ERTS_PROCS_DBG_CHK_PID_FOUND(PBDP, PID, TVP)
  6823. # define ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(PBDP, PID, TVP)
  6824. #endif
  6825. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST
  6826. # define ERTS_PROCS_DBG_CHK_TPLIST() \
  6827. debug_processes_check_term_proc_list()
  6828. # define ERTS_PROCS_DBG_CHK_FREELIST(FL) \
  6829. debug_processes_check_term_proc_free_list(FL)
  6830. #else
  6831. # define ERTS_PROCS_DBG_CHK_TPLIST()
  6832. # define ERTS_PROCS_DBG_CHK_FREELIST(FL)
  6833. #endif
  6834. #if ERTS_PROCESSES_BIF_DEBUGLEVEL == 0
  6835. #if ERTS_PROCS_DBG_DO_TRACE
  6836. # define ERTS_PROCS_DBG_INIT(P, PBDP) (PBDP)->debug.caller = (P)->id
  6837. # else
  6838. # define ERTS_PROCS_DBG_INIT(P, PBDP)
  6839. # endif
  6840. # define ERTS_PROCS_DBG_CLEANUP(PBDP)
  6841. #else
  6842. # define ERTS_PROCS_DBG_INIT(P, PBDP) \
  6843. do { \
  6844. (PBDP)->debug.caller = (P)->id; \
  6845. ERTS_PROCS_DBG_HEAP_ALLOC_INIT((PBDP)); \
  6846. ERTS_PROCS_DBG_CHK_PIDS_INIT((PBDP)); \
  6847. } while (0)
  6848. # define ERTS_PROCS_DBG_CLEANUP(PBDP) \
  6849. do { \
  6850. ERTS_PROCS_DBG_CLEANUP_CHK_PIDS((PBDP)); \
  6851. } while (0)
  6852. #endif
  6853. #if ERTS_PROCS_DBG_DO_TRACE
  6854. # define ERTS_PROCS_DBG_TRACE(PID, FUNC, WHAT) \
  6855. erts_fprintf(stderr, "%T %s:%d:%s(): %s\n", \
  6856. (PID), __FILE__, __LINE__, #FUNC, #WHAT)
  6857. #else
  6858. # define ERTS_PROCS_DBG_TRACE(PID, FUNC, WHAT)
  6859. #endif
  6860. static Uint processes_bif_tab_chunks;
  6861. static Export processes_trap_export;
  6862. typedef struct {
  6863. SysTimeval time;
  6864. } ErtsProcessesBifChunkInfo;
  6865. typedef enum {
  6866. INITIALIZING,
  6867. INSPECTING_TABLE,
  6868. INSPECTING_TERMINATED_PROCESSES,
  6869. BUILDING_RESULT,
  6870. RETURN_RESULT
  6871. } ErtsProcessesBifState;
  6872. typedef struct {
  6873. ErtsProcessesBifState state;
  6874. Eterm caller;
  6875. ErtsProcessesBifChunkInfo *chunk;
  6876. int tix;
  6877. int pid_ix;
  6878. int pid_sz;
  6879. Eterm *pid;
  6880. ErtsTermProcElement *bif_invocation; /* Only used when > 1 chunk */
  6881. #if ERTS_PROCESSES_BIF_DEBUGLEVEL != 0 || ERTS_PROCS_DBG_DO_TRACE
  6882. struct {
  6883. Eterm caller;
  6884. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
  6885. SysTimeval *pid_started;
  6886. #endif
  6887. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_HALLOC
  6888. Eterm *heap;
  6889. Uint heap_size;
  6890. #endif
  6891. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_PIDS
  6892. int correct_pids_verified;
  6893. Eterm *correct_pids;
  6894. #endif
  6895. } debug;
  6896. #endif
  6897. } ErtsProcessesBifData;
  6898. #if ERTS_PROCESSES_BIF_DEBUGLEVEL != 0
  6899. static void debug_processes_assert_error(char* expr, char* file, int line);
  6900. #endif
  6901. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_RESLIST
  6902. static void debug_processes_check_res_list(Eterm list);
  6903. #endif
  6904. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_PIDS
  6905. static void debug_processes_save_all_pids(ErtsProcessesBifData *pbdp);
  6906. static void debug_processes_verify_all_pids(ErtsProcessesBifData *pbdp);
  6907. #endif
  6908. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
  6909. static void debug_processes_check_found_pid(ErtsProcessesBifData *pbdp,
  6910. Eterm pid,
  6911. SysTimeval *started,
  6912. int pid_should_be_found);
  6913. #endif
  6914. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST
  6915. static SysTimeval debug_tv_start;
  6916. static void debug_processes_check_term_proc_list(void);
  6917. static void debug_processes_check_term_proc_free_list(ErtsTermProcElement *tpep);
  6918. #endif
  6919. static void
  6920. save_terminating_process(Process *p)
  6921. {
  6922. ErtsTermProcElement *tpep = erts_alloc(ERTS_ALC_T_PROCS_TPROC_EL,
  6923. sizeof(ErtsTermProcElement));
  6924. ERTS_PROCS_ASSERT(saved_term_procs.start && saved_term_procs.end);
  6925. ERTS_SMP_LC_ASSERT(erts_lc_mtx_is_locked(&proc_tab_mtx));
  6926. ERTS_PROCS_DBG_CHK_TPLIST();
  6927. tpep->prev = saved_term_procs.end;
  6928. tpep->next = NULL;
  6929. tpep->ix = internal_pid_index(p->id);
  6930. tpep->u.process.pid = p->id;
  6931. tpep->u.process.spawned = p->started;
  6932. erts_get_emu_time(&tpep->u.process.exited);
  6933. saved_term_procs.end->next = tpep;
  6934. saved_term_procs.end = tpep;
  6935. ERTS_PROCS_DBG_CHK_TPLIST();
  6936. ERTS_PROCS_ASSERT((tpep->prev->ix >= 0
  6937. ? erts_cmp_timeval(&tpep->u.process.exited,
  6938. &tpep->prev->u.process.exited)
  6939. : erts_cmp_timeval(&tpep->u.process.exited,
  6940. &tpep->prev->u.bif_invocation.time)) > 0);
  6941. }
  6942. static void
  6943. cleanup_processes_bif_data(Binary *bp)
  6944. {
  6945. ErtsProcessesBifData *pbdp = ERTS_MAGIC_BIN_DATA(bp);
  6946. ERTS_PROCS_DBG_TRACE(pbdp->debug.caller, cleanup_processes_bif_data, call);
  6947. if (pbdp->state != INITIALIZING) {
  6948. if (pbdp->chunk) {
  6949. erts_free(ERTS_ALC_T_PROCS_CNKINF, pbdp->chunk);
  6950. pbdp->chunk = NULL;
  6951. }
  6952. if (pbdp->pid) {
  6953. erts_free(ERTS_ALC_T_PROCS_PIDS, pbdp->pid);
  6954. pbdp->pid = NULL;
  6955. }
  6956. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
  6957. if (pbdp->debug.pid_started) {
  6958. erts_free(ERTS_ALC_T_PROCS_PIDS, pbdp->debug.pid_started);
  6959. pbdp->debug.pid_started = NULL;
  6960. }
  6961. #endif
  6962. if (pbdp->bif_invocation) {
  6963. ErtsTermProcElement *tpep;
  6964. erts_smp_mtx_lock(&proc_tab_mtx);
  6965. ERTS_PROCS_DBG_TRACE(pbdp->debug.caller,
  6966. cleanup_processes_bif_data,
  6967. term_proc_cleanup);
  6968. tpep = pbdp->bif_invocation;
  6969. pbdp->bif_invocation = NULL;
  6970. ERTS_PROCS_DBG_CHK_TPLIST();
  6971. if (tpep->prev) {
  6972. /*
  6973. * Only remove this bif invokation when we
  6974. * have preceding invokations.
  6975. */
  6976. tpep->prev->next = tpep->next;
  6977. if (tpep->next)
  6978. tpep->next->prev = tpep->prev;
  6979. else {
  6980. /*
  6981. * At the time of writing this branch cannot be
  6982. * reached. I don't want to remove this code though
  6983. * since it may be possible to reach this line
  6984. * in the future if the cleanup order in
  6985. * erts_do_exit_process() is changed. The ASSERT(0)
  6986. * is only here to make us aware that the reorder
  6987. * has happened. /rickard
  6988. */
  6989. ASSERT(0);
  6990. saved_term_procs.end = tpep->prev;
  6991. }
  6992. erts_free(ERTS_ALC_T_PROCS_TPROC_EL, tpep);
  6993. }
  6994. else {
  6995. /*
  6996. * Free all elements until next bif invokation
  6997. * is found.
  6998. */
  6999. ERTS_PROCS_ASSERT(saved_term_procs.start == tpep);
  7000. do {
  7001. ErtsTermProcElement *ftpep = tpep;
  7002. tpep = tpep->next;
  7003. erts_free(ERTS_ALC_T_PROCS_TPROC_EL, ftpep);
  7004. } while (tpep && tpep->ix >= 0);
  7005. saved_term_procs.start = tpep;
  7006. if (tpep)
  7007. tpep->prev = NULL;
  7008. else
  7009. saved_term_procs.end = NULL;
  7010. }
  7011. ERTS_PROCS_DBG_CHK_TPLIST();
  7012. erts_smp_mtx_unlock(&proc_tab_mtx);
  7013. }
  7014. }
  7015. ERTS_PROCS_DBG_TRACE(pbdp->debug.caller,
  7016. cleanup_processes_bif_data,
  7017. return);
  7018. ERTS_PROCS_DBG_CLEANUP(pbdp);
  7019. }
  7020. static int
  7021. processes_bif_engine(Process *p, Eterm *res_accp, Binary *mbp)
  7022. {
  7023. ErtsProcessesBifData *pbdp = ERTS_MAGIC_BIN_DATA(mbp);
  7024. int have_reds;
  7025. int reds;
  7026. int locked = 0;
  7027. do {
  7028. switch (pbdp->state) {
  7029. case INITIALIZING:
  7030. pbdp->chunk = erts_alloc(ERTS_ALC_T_PROCS_CNKINF,
  7031. (sizeof(ErtsProcessesBifChunkInfo)
  7032. * processes_bif_tab_chunks));
  7033. pbdp->tix = 0;
  7034. pbdp->pid_ix = 0;
  7035. erts_smp_mtx_lock(&proc_tab_mtx);
  7036. locked = 1;
  7037. ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, init);
  7038. pbdp->pid_sz = erts_process_count();
  7039. pbdp->pid = erts_alloc(ERTS_ALC_T_PROCS_PIDS,
  7040. sizeof(Eterm)*pbdp->pid_sz);
  7041. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
  7042. pbdp->debug.pid_started = erts_alloc(ERTS_ALC_T_PROCS_PIDS,
  7043. sizeof(SysTimeval)*pbdp->pid_sz);
  7044. #endif
  7045. ERTS_PROCS_DBG_SAVE_PIDS(pbdp);
  7046. if (processes_bif_tab_chunks == 1)
  7047. pbdp->bif_invocation = NULL;
  7048. else {
  7049. /*
  7050. * We will have to access the table multiple times
  7051. * releasing the table lock in between chunks.
  7052. */
  7053. pbdp->bif_invocation = erts_alloc(ERTS_ALC_T_PROCS_TPROC_EL,
  7054. sizeof(ErtsTermProcElement));
  7055. pbdp->bif_invocation->ix = -1;
  7056. erts_get_emu_time(&pbdp->bif_invocation->u.bif_invocation.time);
  7057. ERTS_PROCS_DBG_CHK_TPLIST();
  7058. pbdp->bif_invocation->next = NULL;
  7059. if (saved_term_procs.end) {
  7060. pbdp->bif_invocation->prev = saved_term_procs.end;
  7061. saved_term_procs.end->next = pbdp->bif_invocation;
  7062. ERTS_PROCS_ASSERT(saved_term_procs.start);
  7063. }
  7064. else {
  7065. pbdp->bif_invocation->prev = NULL;
  7066. saved_term_procs.start = pbdp->bif_invocation;
  7067. }
  7068. saved_term_procs.end = pbdp->bif_invocation;
  7069. ERTS_PROCS_DBG_CHK_TPLIST();
  7070. }
  7071. pbdp->state = INSPECTING_TABLE;
  7072. /* Fall through */
  7073. case INSPECTING_TABLE: {
  7074. int ix = pbdp->tix;
  7075. int indices = ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE;
  7076. int cix = ix / ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE;
  7077. int end_ix = ix + indices;
  7078. SysTimeval *invocation_timep;
  7079. invocation_timep = (pbdp->bif_invocation
  7080. ? &pbdp->bif_invocation->u.bif_invocation.time
  7081. : NULL);
  7082. ERTS_PROCS_ASSERT(is_nil(*res_accp));
  7083. if (!locked) {
  7084. erts_smp_mtx_lock(&proc_tab_mtx);
  7085. locked = 1;
  7086. }
  7087. ERTS_SMP_LC_ASSERT(erts_lc_mtx_is_locked(&proc_tab_mtx));
  7088. ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, insp_table);
  7089. if (cix != 0)
  7090. erts_get_emu_time(&pbdp->chunk[cix].time);
  7091. else if (pbdp->bif_invocation)
  7092. pbdp->chunk[0].time = *invocation_timep;
  7093. /* else: Time is irrelevant */
  7094. if (end_ix >= erts_max_processes) {
  7095. ERTS_PROCS_ASSERT(cix+1 == processes_bif_tab_chunks);
  7096. end_ix = erts_max_processes;
  7097. indices = end_ix - ix;
  7098. /* What to do when done with this chunk */
  7099. pbdp->state = (processes_bif_tab_chunks == 1
  7100. ? BUILDING_RESULT
  7101. : INSPECTING_TERMINATED_PROCESSES);
  7102. }
  7103. for (; ix < end_ix; ix++) {
  7104. Process *rp = process_tab[ix];
  7105. if (rp
  7106. && (!invocation_timep
  7107. || erts_cmp_timeval(&rp->started,
  7108. invocation_timep) < 0)) {
  7109. ERTS_PROCS_ASSERT(is_internal_pid(rp->id));
  7110. pbdp->pid[pbdp->pid_ix] = rp->id;
  7111. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
  7112. pbdp->debug.pid_started[pbdp->pid_ix] = rp->started;
  7113. #endif
  7114. pbdp->pid_ix++;
  7115. ERTS_PROCS_ASSERT(pbdp->pid_ix <= pbdp->pid_sz);
  7116. }
  7117. }
  7118. pbdp->tix = end_ix;
  7119. erts_smp_mtx_unlock(&proc_tab_mtx);
  7120. locked = 0;
  7121. reds = indices/ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED;
  7122. BUMP_REDS(p, reds);
  7123. have_reds = ERTS_BIF_REDS_LEFT(p);
  7124. if (have_reds && pbdp->state == INSPECTING_TABLE) {
  7125. ix = pbdp->tix;
  7126. indices = ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE;
  7127. end_ix = ix + indices;
  7128. if (end_ix > erts_max_processes) {
  7129. end_ix = erts_max_processes;
  7130. indices = end_ix - ix;
  7131. }
  7132. reds = indices/ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED;
  7133. /* Pretend we have no reds left if we haven't got enough
  7134. reductions to complete next chunk */
  7135. if (reds > have_reds)
  7136. have_reds = 0;
  7137. }
  7138. break;
  7139. }
  7140. case INSPECTING_TERMINATED_PROCESSES: {
  7141. int i;
  7142. int max_reds;
  7143. int free_term_procs = 0;
  7144. SysTimeval *invocation_timep;
  7145. ErtsTermProcElement *tpep;
  7146. ErtsTermProcElement *free_list = NULL;
  7147. tpep = pbdp->bif_invocation;
  7148. ERTS_PROCS_ASSERT(tpep);
  7149. invocation_timep = &tpep->u.bif_invocation.time;
  7150. max_reds = have_reds = ERTS_BIF_REDS_LEFT(p);
  7151. if (max_reds > ERTS_PROCESSES_INSPECT_TERM_PROC_MAX_REDS)
  7152. max_reds = ERTS_PROCESSES_INSPECT_TERM_PROC_MAX_REDS;
  7153. reds = 0;
  7154. erts_smp_mtx_lock(&proc_tab_mtx);
  7155. ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, insp_term_procs);
  7156. ERTS_PROCS_DBG_CHK_TPLIST();
  7157. if (tpep->prev)
  7158. tpep->prev->next = tpep->next;
  7159. else {
  7160. ERTS_PROCS_ASSERT(saved_term_procs.start == tpep);
  7161. saved_term_procs.start = tpep->next;
  7162. if (saved_term_procs.start && saved_term_procs.start->ix >= 0) {
  7163. free_list = saved_term_procs.start;
  7164. free_term_procs = 1;
  7165. }
  7166. }
  7167. if (tpep->next)
  7168. tpep->next->prev = tpep->prev;
  7169. else
  7170. saved_term_procs.end = tpep->prev;
  7171. tpep = tpep->next;
  7172. i = 0;
  7173. while (reds < max_reds && tpep) {
  7174. if (tpep->ix < 0) {
  7175. if (free_term_procs) {
  7176. ERTS_PROCS_ASSERT(free_list);
  7177. ERTS_PROCS_ASSERT(tpep->prev);
  7178. tpep->prev->next = NULL; /* end of free_list */
  7179. saved_term_procs.start = tpep;
  7180. tpep->prev = NULL;
  7181. free_term_procs = 0;
  7182. }
  7183. }
  7184. else {
  7185. int cix = tpep->ix/ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE;
  7186. SysTimeval *chunk_timep = &pbdp->chunk[cix].time;
  7187. Eterm pid = tpep->u.process.pid;
  7188. ERTS_PROCS_ASSERT(is_internal_pid(pid));
  7189. if (erts_cmp_timeval(&tpep->u.process.spawned,
  7190. invocation_timep) < 0) {
  7191. if (erts_cmp_timeval(&tpep->u.process.exited,
  7192. chunk_timep) < 0) {
  7193. ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(pbdp,
  7194. pid,
  7195. &tpep->u.process.spawned);
  7196. pbdp->pid[pbdp->pid_ix] = pid;
  7197. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
  7198. pbdp->debug.pid_started[pbdp->pid_ix] = tpep->u.process.spawned;
  7199. #endif
  7200. pbdp->pid_ix++;
  7201. ERTS_PROCS_ASSERT(pbdp->pid_ix <= pbdp->pid_sz);
  7202. }
  7203. else {
  7204. ERTS_PROCS_DBG_CHK_PID_FOUND(pbdp,
  7205. pid,
  7206. &tpep->u.process.spawned);
  7207. }
  7208. }
  7209. else {
  7210. ERTS_PROCS_DBG_CHK_PID_NOT_FOUND(pbdp,
  7211. pid,
  7212. &tpep->u.process.spawned);
  7213. }
  7214. i++;
  7215. if (i == ERTS_PROCESSES_BIF_INSPECT_TERM_PROC_PER_RED) {
  7216. reds++;
  7217. i = 0;
  7218. }
  7219. if (free_term_procs)
  7220. reds += ERTS_PROCESSES_BIF_TAB_FREE_TERM_PROC_REDS;
  7221. }
  7222. tpep = tpep->next;
  7223. }
  7224. if (free_term_procs) {
  7225. ERTS_PROCS_ASSERT(free_list);
  7226. saved_term_procs.start = tpep;
  7227. if (!tpep)
  7228. saved_term_procs.end = NULL;
  7229. else {
  7230. ERTS_PROCS_ASSERT(tpep->prev);
  7231. tpep->prev->next = NULL; /* end of free_list */
  7232. tpep->prev = NULL;
  7233. }
  7234. }
  7235. if (!tpep) {
  7236. /* Done */
  7237. ERTS_PROCS_ASSERT(pbdp->pid_ix == pbdp->pid_sz);
  7238. pbdp->state = BUILDING_RESULT;
  7239. pbdp->bif_invocation->next = free_list;
  7240. free_list = pbdp->bif_invocation;
  7241. pbdp->bif_invocation = NULL;
  7242. }
  7243. else {
  7244. /* Link in bif_invocation again where we left off */
  7245. pbdp->bif_invocation->prev = tpep->prev;
  7246. pbdp->bif_invocation->next = tpep;
  7247. tpep->prev = pbdp->bif_invocation;
  7248. if (pbdp->bif_invocation->prev)
  7249. pbdp->bif_invocation->prev->next = pbdp->bif_invocation;
  7250. else {
  7251. ERTS_PROCS_ASSERT(saved_term_procs.start == tpep);
  7252. saved_term_procs.start = pbdp->bif_invocation;
  7253. }
  7254. }
  7255. ERTS_PROCS_DBG_CHK_TPLIST();
  7256. ERTS_PROCS_DBG_CHK_FREELIST(free_list);
  7257. erts_smp_mtx_unlock(&proc_tab_mtx);
  7258. /*
  7259. * We do the actual free of term proc structures now when we
  7260. * have released the table lock instead of when we encountered
  7261. * them. This since free() isn't for free and we don't want to
  7262. * unnecessarily block other schedulers.
  7263. */
  7264. while (free_list) {
  7265. tpep = free_list;
  7266. free_list = tpep->next;
  7267. erts_free(ERTS_ALC_T_PROCS_TPROC_EL, tpep);
  7268. }
  7269. have_reds -= reds;
  7270. if (have_reds < 0)
  7271. have_reds = 0;
  7272. BUMP_REDS(p, reds);
  7273. break;
  7274. }
  7275. case BUILDING_RESULT: {
  7276. int conses, ix, min_ix;
  7277. Eterm *hp;
  7278. Eterm res = *res_accp;
  7279. ERTS_PROCS_DBG_VERIFY_PIDS(pbdp);
  7280. ERTS_PROCS_DBG_CHK_RESLIST(res);
  7281. ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, begin_build_res);
  7282. have_reds = ERTS_BIF_REDS_LEFT(p);
  7283. conses = ERTS_PROCESSES_BIF_BUILD_RESULT_CONSES_PER_RED*have_reds;
  7284. min_ix = pbdp->pid_ix - conses;
  7285. if (min_ix < 0) {
  7286. min_ix = 0;
  7287. conses = pbdp->pid_ix;
  7288. }
  7289. hp = HAlloc(p, conses*2);
  7290. ERTS_PROCS_DBG_SAVE_HEAP_ALLOC(pbdp, hp, conses*2);
  7291. for (ix = pbdp->pid_ix - 1; ix >= min_ix; ix--) {
  7292. ERTS_PROCS_ASSERT(is_internal_pid(pbdp->pid[ix]));
  7293. res = CONS(hp, pbdp->pid[ix], res);
  7294. hp += 2;
  7295. }
  7296. ERTS_PROCS_DBG_VERIFY_HEAP_ALLOC_USED(pbdp, hp);
  7297. pbdp->pid_ix = min_ix;
  7298. if (min_ix == 0)
  7299. pbdp->state = RETURN_RESULT;
  7300. else {
  7301. pbdp->pid_sz = min_ix;
  7302. pbdp->pid = erts_realloc(ERTS_ALC_T_PROCS_PIDS,
  7303. pbdp->pid,
  7304. sizeof(Eterm)*pbdp->pid_sz);
  7305. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
  7306. pbdp->debug.pid_started = erts_realloc(ERTS_ALC_T_PROCS_PIDS,
  7307. pbdp->debug.pid_started,
  7308. sizeof(SysTimeval)*pbdp->pid_sz);
  7309. #endif
  7310. }
  7311. reds = conses/ERTS_PROCESSES_BIF_BUILD_RESULT_CONSES_PER_RED;
  7312. BUMP_REDS(p, reds);
  7313. have_reds -= reds;
  7314. ERTS_PROCS_DBG_CHK_RESLIST(res);
  7315. ERTS_PROCS_DBG_TRACE(p->id, processes_bif_engine, end_build_res);
  7316. *res_accp = res;
  7317. break;
  7318. }
  7319. case RETURN_RESULT:
  7320. cleanup_processes_bif_data(mbp);
  7321. return 1;
  7322. default:
  7323. erl_exit(ERTS_ABORT_EXIT,
  7324. "erlang:processes/0: Invalid state: %d\n",
  7325. (int) pbdp->state);
  7326. }
  7327. } while (have_reds || pbdp->state == RETURN_RESULT);
  7328. return 0;
  7329. }
  7330. /*
  7331. * processes_trap/2 is a hidden BIF that processes/0 traps to.
  7332. */
  7333. static BIF_RETTYPE processes_trap(BIF_ALIST_2)
  7334. {
  7335. Eterm res_acc;
  7336. Binary *mbp;
  7337. /*
  7338. * This bif cannot be called from erlang code. It can only be
  7339. * trapped to from processes/0; therefore, a bad argument
  7340. * is a processes/0 internal error.
  7341. */
  7342. ERTS_PROCS_DBG_TRACE(BIF_P->id, processes_trap, call);
  7343. ERTS_PROCS_ASSERT(is_nil(BIF_ARG_1) || is_list(BIF_ARG_1));
  7344. res_acc = BIF_ARG_1;
  7345. ERTS_PROCS_ASSERT(ERTS_TERM_IS_MAGIC_BINARY(BIF_ARG_2));
  7346. mbp = ((ProcBin *) binary_val(BIF_ARG_2))->val;
  7347. ERTS_PROCS_ASSERT(ERTS_MAGIC_BIN_DESTRUCTOR(mbp)
  7348. == cleanup_processes_bif_data);
  7349. ERTS_PROCS_ASSERT(
  7350. ((ErtsProcessesBifData *) ERTS_MAGIC_BIN_DATA(mbp))->debug.caller
  7351. == BIF_P->id);
  7352. if (processes_bif_engine(BIF_P, &res_acc, mbp)) {
  7353. ERTS_PROCS_DBG_TRACE(BIF_P->id, processes_trap, return);
  7354. BIF_RET(res_acc);
  7355. }
  7356. else {
  7357. ERTS_PROCS_DBG_TRACE(BIF_P->id, processes_trap, trap);
  7358. ERTS_BIF_YIELD2(&processes_trap_export, BIF_P, res_acc, BIF_ARG_2);
  7359. }
  7360. }
  7361. /*
  7362. * The actual processes/0 BIF.
  7363. */
  7364. BIF_RETTYPE processes_0(BIF_ALIST_0)
  7365. {
  7366. /*
  7367. * A requirement: The list of pids returned should be a consistent
  7368. * snapshot of all processes existing at some point
  7369. * in time during the execution of processes/0. Since
  7370. * processes might terminate while processes/0 is
  7371. * executing, we have to keep track of terminated
  7372. * processes and add them to the result. We also
  7373. * ignore processes created after processes/0 has
  7374. * begun executing.
  7375. */
  7376. Eterm res_acc = NIL;
  7377. Binary *mbp = erts_create_magic_binary(sizeof(ErtsProcessesBifData),
  7378. cleanup_processes_bif_data);
  7379. ErtsProcessesBifData *pbdp = ERTS_MAGIC_BIN_DATA(mbp);
  7380. ERTS_PROCS_DBG_TRACE(BIF_P->id, processes_0, call);
  7381. pbdp->state = INITIALIZING;
  7382. ERTS_PROCS_DBG_INIT(BIF_P, pbdp);
  7383. if (ERTS_BIF_REDS_LEFT(BIF_P) >= ERTS_PROCESSES_BIF_MIN_START_REDS
  7384. && processes_bif_engine(BIF_P, &res_acc, mbp)) {
  7385. erts_bin_free(mbp);
  7386. ERTS_PROCS_DBG_CHK_RESLIST(res_acc);
  7387. ERTS_PROCS_DBG_TRACE(BIF_P->id, processes_0, return);
  7388. BIF_RET(res_acc);
  7389. }
  7390. else {
  7391. Eterm *hp;
  7392. Eterm magic_bin;
  7393. ERTS_PROCS_DBG_CHK_RESLIST(res_acc);
  7394. hp = HAlloc(BIF_P, PROC_BIN_SIZE);
  7395. ERTS_PROCS_DBG_SAVE_HEAP_ALLOC(pbdp, hp, PROC_BIN_SIZE);
  7396. magic_bin = erts_mk_magic_binary_term(&hp, &MSO(BIF_P), mbp);
  7397. ERTS_PROCS_DBG_VERIFY_HEAP_ALLOC_USED(pbdp, hp);
  7398. ERTS_PROCS_DBG_TRACE(BIF_P->id, processes_0, trap);
  7399. ERTS_BIF_YIELD2(&processes_trap_export, BIF_P, res_acc, magic_bin);
  7400. }
  7401. }
  7402. static void
  7403. init_processes_bif(void)
  7404. {
  7405. saved_term_procs.start = NULL;
  7406. saved_term_procs.end = NULL;
  7407. processes_bif_tab_chunks = (((erts_max_processes - 1)
  7408. / ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE)
  7409. + 1);
  7410. /* processes_trap/2 is a hidden BIF that the processes/0 BIF traps to. */
  7411. sys_memset((void *) &processes_trap_export, 0, sizeof(Export));
  7412. processes_trap_export.address = &processes_trap_export.code[3];
  7413. processes_trap_export.code[0] = am_erlang;
  7414. processes_trap_export.code[1] = am_processes_trap;
  7415. processes_trap_export.code[2] = 2;
  7416. processes_trap_export.code[3] = (BeamInstr) em_apply_bif;
  7417. processes_trap_export.code[4] = (BeamInstr) &processes_trap;
  7418. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST
  7419. erts_get_emu_time(&debug_tv_start);
  7420. #endif
  7421. }
  7422. /*
  7423. * Debug stuff
  7424. */
  7425. Eterm
  7426. erts_debug_processes(Process *c_p)
  7427. {
  7428. /* This is the old processes/0 BIF. */
  7429. int i;
  7430. Uint need;
  7431. Eterm res;
  7432. Eterm* hp;
  7433. Process *p;
  7434. #ifdef DEBUG
  7435. Eterm *hp_end;
  7436. #endif
  7437. erts_smp_mtx_lock(&proc_tab_mtx);
  7438. res = NIL;
  7439. need = erts_process_count() * 2;
  7440. hp = HAlloc(c_p, need); /* we need two heap words for each pid */
  7441. #ifdef DEBUG
  7442. hp_end = hp + need;
  7443. #endif
  7444. /* make the list by scanning bakward */
  7445. for (i = erts_max_processes-1; i >= 0; i--) {
  7446. if ((p = process_tab[i]) != NULL) {
  7447. res = CONS(hp, process_tab[i]->id, res);
  7448. hp += 2;
  7449. }
  7450. }
  7451. ASSERT(hp == hp_end);
  7452. erts_smp_mtx_unlock(&proc_tab_mtx);
  7453. return res;
  7454. }
  7455. Eterm
  7456. erts_debug_processes_bif_info(Process *c_p)
  7457. {
  7458. ERTS_DECL_AM(processes_bif_info);
  7459. Eterm elements[] = {
  7460. AM_processes_bif_info,
  7461. make_small((Uint) ERTS_PROCESSES_BIF_MIN_START_REDS),
  7462. make_small((Uint) processes_bif_tab_chunks),
  7463. make_small((Uint) ERTS_PROCESSES_BIF_TAB_CHUNK_SIZE),
  7464. make_small((Uint) ERTS_PROCESSES_BIF_TAB_INSPECT_INDICES_PER_RED),
  7465. make_small((Uint) ERTS_PROCESSES_BIF_TAB_FREE_TERM_PROC_REDS),
  7466. make_small((Uint) ERTS_PROCESSES_BIF_INSPECT_TERM_PROC_PER_RED),
  7467. make_small((Uint) ERTS_PROCESSES_INSPECT_TERM_PROC_MAX_REDS),
  7468. make_small((Uint) ERTS_PROCESSES_BIF_BUILD_RESULT_CONSES_PER_RED),
  7469. make_small((Uint) ERTS_PROCESSES_BIF_DEBUGLEVEL)
  7470. };
  7471. Uint sz = 0;
  7472. Eterm *hp;
  7473. (void) erts_bld_tuplev(NULL, &sz, sizeof(elements)/sizeof(Eterm), elements);
  7474. hp = HAlloc(c_p, sz);
  7475. return erts_bld_tuplev(&hp, NULL, sizeof(elements)/sizeof(Eterm), elements);
  7476. }
  7477. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_FOUND_PIDS
  7478. static void
  7479. debug_processes_check_found_pid(ErtsProcessesBifData *pbdp,
  7480. Eterm pid,
  7481. SysTimeval *tvp,
  7482. int pid_should_be_found)
  7483. {
  7484. int i;
  7485. for (i = 0; i < pbdp->pid_ix; i++) {
  7486. if (pbdp->pid[i] == pid
  7487. && pbdp->debug.pid_started[i].tv_sec == tvp->tv_sec
  7488. && pbdp->debug.pid_started[i].tv_usec == tvp->tv_usec) {
  7489. ERTS_PROCS_ASSERT(pid_should_be_found);
  7490. return;
  7491. }
  7492. }
  7493. ERTS_PROCS_ASSERT(!pid_should_be_found);
  7494. }
  7495. #endif
  7496. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_RESLIST
  7497. static void
  7498. debug_processes_check_res_list(Eterm list)
  7499. {
  7500. while (is_list(list)) {
  7501. Eterm* consp = list_val(list);
  7502. Eterm hd = CAR(consp);
  7503. ERTS_PROCS_ASSERT(is_internal_pid(hd));
  7504. list = CDR(consp);
  7505. }
  7506. ERTS_PROCS_ASSERT(is_nil(list));
  7507. }
  7508. #endif
  7509. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_PIDS
  7510. static void
  7511. debug_processes_save_all_pids(ErtsProcessesBifData *pbdp)
  7512. {
  7513. int ix, tix, cpix;
  7514. pbdp->debug.correct_pids_verified = 0;
  7515. pbdp->debug.correct_pids = erts_alloc(ERTS_ALC_T_PROCS_PIDS,
  7516. sizeof(Eterm)*pbdp->pid_sz);
  7517. for (tix = 0, cpix = 0; tix < erts_max_processes; tix++) {
  7518. Process *rp = process_tab[tix];
  7519. if (rp) {
  7520. ERTS_PROCS_ASSERT(is_internal_pid(rp->id));
  7521. pbdp->debug.correct_pids[cpix++] = rp->id;
  7522. ERTS_PROCS_ASSERT(cpix <= pbdp->pid_sz);
  7523. }
  7524. }
  7525. ERTS_PROCS_ASSERT(cpix == pbdp->pid_sz);
  7526. for (ix = 0; ix < pbdp->pid_sz; ix++)
  7527. pbdp->pid[ix] = make_small(ix);
  7528. }
  7529. static void
  7530. debug_processes_verify_all_pids(ErtsProcessesBifData *pbdp)
  7531. {
  7532. int ix, cpix;
  7533. ERTS_PROCS_ASSERT(pbdp->pid_ix == pbdp->pid_sz);
  7534. for (ix = 0; ix < pbdp->pid_sz; ix++) {
  7535. int found = 0;
  7536. Eterm pid = pbdp->pid[ix];
  7537. ERTS_PROCS_ASSERT(is_internal_pid(pid));
  7538. for (cpix = ix; cpix < pbdp->pid_sz; cpix++) {
  7539. if (pbdp->debug.correct_pids[cpix] == pid) {
  7540. pbdp->debug.correct_pids[cpix] = NIL;
  7541. found = 1;
  7542. break;
  7543. }
  7544. }
  7545. if (!found) {
  7546. for (cpix = 0; cpix < ix; cpix++) {
  7547. if (pbdp->debug.correct_pids[cpix] == pid) {
  7548. pbdp->debug.correct_pids[cpix] = NIL;
  7549. found = 1;
  7550. break;
  7551. }
  7552. }
  7553. }
  7554. ERTS_PROCS_ASSERT(found);
  7555. }
  7556. pbdp->debug.correct_pids_verified = 1;
  7557. erts_free(ERTS_ALC_T_PROCS_PIDS, pbdp->debug.correct_pids);
  7558. pbdp->debug.correct_pids = NULL;
  7559. }
  7560. #endif /* ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_PIDS */
  7561. #if ERTS_PROCESSES_BIF_DEBUGLEVEL >= ERTS_PROCS_DBGLVL_CHK_TERM_PROC_LIST
  7562. static void
  7563. debug_processes_check_term_proc_list(void)
  7564. {
  7565. ERTS_SMP_LC_ASSERT(erts_lc_mtx_is_locked(&proc_tab_mtx));
  7566. if (!saved_term_procs.start)
  7567. ERTS_PROCS_ASSERT(!saved_term_procs.end);
  7568. else {
  7569. SysTimeval tv_now;
  7570. SysTimeval *prev_xtvp = NULL;
  7571. ErtsTermProcElement *tpep;
  7572. erts_get_emu_time(&tv_now);
  7573. for (tpep = saved_term_procs.start; tpep; tpep = tpep->next) {
  7574. if (!tpep->prev)
  7575. ERTS_PROCS_ASSERT(saved_term_procs.start == tpep);
  7576. else
  7577. ERTS_PROCS_ASSERT(tpep->prev->next == tpep);
  7578. if (!tpep->next)
  7579. ERTS_PROCS_ASSERT(saved_term_procs.end == tpep);
  7580. else
  7581. ERTS_PROCS_ASSERT(tpep->next->prev == tpep);
  7582. if (tpep->ix < 0) {
  7583. SysTimeval *tvp = &tpep->u.bif_invocation.time;
  7584. ERTS_PROCS_ASSERT(erts_cmp_timeval(&debug_tv_start, tvp) < 0
  7585. && erts_cmp_timeval(tvp, &tv_now) < 0);
  7586. }
  7587. else {
  7588. SysTimeval *stvp = &tpep->u.process.spawned;
  7589. SysTimeval *xtvp = &tpep->u.process.exited;
  7590. ERTS_PROCS_ASSERT(erts_cmp_timeval(&debug_tv_start,
  7591. stvp) < 0);
  7592. ERTS_PROCS_ASSERT(erts_cmp_timeval(stvp, xtvp) < 0);
  7593. if (prev_xtvp)
  7594. ERTS_PROCS_ASSERT(erts_cmp_timeval(prev_xtvp, xtvp) < 0);
  7595. prev_xtvp = xtvp;
  7596. ERTS_PROCS_ASSERT(is_internal_pid(tpep->u.process.pid));
  7597. ERTS_PROCS_ASSERT(tpep->ix
  7598. == internal_pid_index(tpep->u.process.pid));
  7599. }
  7600. }
  7601. }
  7602. }
  7603. static void
  7604. debug_processes_check_term_proc_free_list(ErtsTermProcElement *free_list)
  7605. {
  7606. if (saved_term_procs.start) {
  7607. ErtsTermProcElement *ftpep;
  7608. ErtsTermProcElement *tpep;
  7609. for (ftpep = free_list; ftpep; ftpep = ftpep->next) {
  7610. for (tpep = saved_term_procs.start; tpep; tpep = tpep->next)
  7611. ERTS_PROCS_ASSERT(ftpep != tpep);
  7612. }
  7613. }
  7614. }
  7615. #endif
  7616. #if ERTS_PROCESSES_BIF_DEBUGLEVEL != 0
  7617. static void
  7618. debug_processes_assert_error(char* expr, char* file, int line)
  7619. {
  7620. fflush(stdout);
  7621. erts_fprintf(stderr, "%s:%d: Assertion failed: %s\n", file, line, expr);
  7622. fflush(stderr);
  7623. abort();
  7624. }
  7625. #endif
  7626. /* *\
  7627. * End of the processes/0 BIF implementation. *
  7628. \* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */