PageRenderTime 94ms CodeModel.GetById 1ms RepoModel.GetById 0ms app.codeStats 2ms

/erts/emulator/beam/erl_process.c

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