PageRenderTime 61ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 2ms

/erts/emulator/beam/erl_process.c

https://github.com/Bwooce/otp
C | 8823 lines | 6988 code | 1195 blank | 640 comment | 1474 complexity | 13f9e0f35e94464e4926f975dc2a129f MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, BSD-2-Clause

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

  1. /*
  2. * %CopyrightBegin%
  3. *
  4. * Copyright Ericsson AB 1996-2010. All Rights Reserved.
  5. *
  6. * The contents of this file are subject to the Erlang Public License,
  7. * Version 1.1, (the "License"); you may not use this file except in
  8. * compliance with the License. You should have received a copy of the
  9. * Erlang Public License along with this software. If not, it can be
  10. * retrieved online at http://www.erlang.org/.
  11. *
  12. * Software distributed under the License is distributed on an "AS IS"
  13. * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
  14. * the License for the specific language governing rights and limitations
  15. * under the License.
  16. *
  17. * %CopyrightEnd%
  18. */
  19. #define ERL_PROCESS_C__
  20. #ifdef HAVE_CONFIG_H
  21. # include "config.h"
  22. #endif
  23. #include <stddef.h> /* offsetof() */
  24. #include "sys.h"
  25. #include "erl_vm.h"
  26. #include "global.h"
  27. #include "erl_process.h"
  28. #include "erl_nmgc.h"
  29. #include "error.h"
  30. #include "bif.h"
  31. #include "erl_db.h"
  32. #include "dist.h"
  33. #include "beam_catches.h"
  34. #include "erl_instrument.h"
  35. #include "erl_threads.h"
  36. #include "erl_binary.h"
  37. #include "beam_bp.h"
  38. #include "erl_cpu_topology.h"
  39. #define ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED (2000*CONTEXT_REDS)
  40. #define ERTS_RUNQ_CALL_CHECK_BALANCE_REDS \
  41. (ERTS_RUNQ_CHECK_BALANCE_REDS_PER_SCHED/2)
  42. #define ERTS_PROC_MIN_CONTEXT_SWITCH_REDS_COST (CONTEXT_REDS/10)
  43. #define ERTS_SCHED_SPIN_UNTIL_YIELD 100
  44. #define ERTS_SCHED_SYS_SLEEP_SPINCOUNT 10
  45. #define ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT 1000
  46. #define ERTS_SCHED_TSE_SLEEP_SPINCOUNT \
  47. (ERTS_SCHED_SYS_SLEEP_SPINCOUNT*ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT)
  48. #define ERTS_SCHED_SUSPEND_SLEEP_SPINCOUNT 0
  49. #define ERTS_WAKEUP_OTHER_LIMIT_VERY_HIGH (200*CONTEXT_REDS)
  50. #define ERTS_WAKEUP_OTHER_LIMIT_HIGH (50*CONTEXT_REDS)
  51. #define ERTS_WAKEUP_OTHER_LIMIT_MEDIUM (10*CONTEXT_REDS)
  52. #define ERTS_WAKEUP_OTHER_LIMIT_LOW (CONTEXT_REDS)
  53. #define ERTS_WAKEUP_OTHER_LIMIT_VERY_LOW (CONTEXT_REDS/10)
  54. #define ERTS_WAKEUP_OTHER_DEC 10
  55. #define ERTS_WAKEUP_OTHER_FIXED_INC (CONTEXT_REDS/10)
  56. #if 0 || defined(DEBUG)
  57. #define ERTS_FAKE_SCHED_BIND_PRINT_SORTED_CPU_DATA
  58. #endif
  59. #if defined(DEBUG) && 0
  60. #define HARDDEBUG
  61. #else
  62. #undef HARDDEBUG
  63. #endif
  64. #ifdef HARDDEBUG
  65. #define HARDDEBUG_RUNQS
  66. #endif
  67. #ifdef HIPE
  68. #include "hipe_mode_switch.h" /* for hipe_init_process() */
  69. #include "hipe_signal.h" /* for hipe_thread_signal_init() */
  70. #endif
  71. #ifdef ERTS_ENABLE_LOCK_COUNT
  72. #include "erl_lock_count.h"
  73. #endif
  74. #define MAX_BIT (1 << PRIORITY_MAX)
  75. #define HIGH_BIT (1 << PRIORITY_HIGH)
  76. #define NORMAL_BIT (1 << PRIORITY_NORMAL)
  77. #define LOW_BIT (1 << PRIORITY_LOW)
  78. #define ERTS_MAYBE_SAVE_TERMINATING_PROCESS(P) \
  79. do { \
  80. ERTS_SMP_LC_ASSERT(erts_lc_mtx_is_locked(&proc_tab_mtx)); \
  81. if (saved_term_procs.end) \
  82. save_terminating_process((P)); \
  83. } while (0)
  84. #define ERTS_EMPTY_RUNQ(RQ) \
  85. ((RQ)->len == 0 && (RQ)->misc.start == NULL)
  86. extern BeamInstr beam_apply[];
  87. extern BeamInstr beam_exit[];
  88. extern BeamInstr beam_continue_exit[];
  89. static Sint p_last;
  90. static Sint p_next;
  91. static Sint p_serial;
  92. static Uint p_serial_mask;
  93. static Uint p_serial_shift;
  94. Uint erts_no_schedulers;
  95. Uint erts_max_processes = ERTS_DEFAULT_MAX_PROCESSES;
  96. Uint erts_process_tab_index_mask;
  97. static int wakeup_other_limit;
  98. int erts_sched_thread_suggested_stack_size = -1;
  99. #ifdef ERTS_ENABLE_LOCK_CHECK
  100. ErtsLcPSDLocks erts_psd_required_locks[ERTS_PSD_SIZE];
  101. #endif
  102. #ifdef ERTS_SMP
  103. int erts_disable_proc_not_running_opt;
  104. #define ERTS_SCHDLR_SSPND_CHNG_WAITER (((erts_aint32_t) 1) << 0)
  105. #define ERTS_SCHDLR_SSPND_CHNG_MSB (((erts_aint32_t) 1) << 1)
  106. #define ERTS_SCHDLR_SSPND_CHNG_ONLN (((erts_aint32_t) 1) << 2)
  107. #ifndef DEBUG
  108. #define ERTS_SCHDLR_SSPND_CHNG_SET(VAL, OLD_VAL) \
  109. erts_smp_atomic32_set(&schdlr_sspnd.changing, (VAL))
  110. #else
  111. #define ERTS_SCHDLR_SSPND_CHNG_SET(VAL, OLD_VAL) \
  112. do { \
  113. erts_aint32_t old_val__; \
  114. old_val__ = erts_smp_atomic32_xchg(&schdlr_sspnd.changing, \
  115. (VAL)); \
  116. ASSERT(old_val__ == (OLD_VAL)); \
  117. } while (0)
  118. #endif
  119. static struct {
  120. erts_smp_mtx_t mtx;
  121. erts_smp_cnd_t cnd;
  122. int online;
  123. int curr_online;
  124. int wait_curr_online;
  125. erts_smp_atomic32_t changing;
  126. erts_smp_atomic32_t active;
  127. struct {
  128. erts_smp_atomic32_t ongoing;
  129. long wait_active;
  130. ErtsProcList *procs;
  131. } msb; /* Multi Scheduling Block */
  132. } schdlr_sspnd;
  133. static struct {
  134. erts_smp_mtx_t update_mtx;
  135. erts_smp_atomic32_t active_runqs;
  136. int last_active_runqs;
  137. erts_smp_atomic32_t used_runqs;
  138. int forced_check_balance;
  139. erts_smp_atomic32_t checking_balance;
  140. int halftime;
  141. int full_reds_history_index;
  142. struct {
  143. int active_runqs;
  144. int reds;
  145. int max_len;
  146. } prev_rise;
  147. Uint n;
  148. } balance_info;
  149. #define ERTS_BLNCE_SAVE_RISE(ACTIVE, MAX_LEN, REDS) \
  150. do { \
  151. balance_info.prev_rise.active_runqs = (ACTIVE); \
  152. balance_info.prev_rise.max_len = (MAX_LEN); \
  153. balance_info.prev_rise.reds = (REDS); \
  154. } while (0)
  155. #endif
  156. erts_sched_stat_t erts_sched_stat;
  157. ErtsRunQueue *erts_common_run_queue;
  158. #ifdef USE_THREADS
  159. static erts_tsd_key_t sched_data_key;
  160. #endif
  161. static erts_smp_mtx_t proc_tab_mtx;
  162. static erts_smp_atomic32_t function_calls;
  163. #ifdef ERTS_SMP
  164. static erts_smp_atomic32_t doing_sys_schedule;
  165. static erts_smp_atomic32_t no_empty_run_queues;
  166. #else /* !ERTS_SMP */
  167. ErtsSchedulerData *erts_scheduler_data;
  168. #endif
  169. ErtsAlignedRunQueue *erts_aligned_run_queues;
  170. Uint erts_no_run_queues;
  171. ErtsAlignedSchedulerData *erts_aligned_scheduler_data;
  172. #ifdef ERTS_SMP
  173. typedef union {
  174. ErtsSchedulerSleepInfo ssi;
  175. char align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(ErtsSchedulerSleepInfo))];
  176. } ErtsAlignedSchedulerSleepInfo;
  177. static ErtsAlignedSchedulerSleepInfo *aligned_sched_sleep_info;
  178. #endif
  179. #ifndef BM_COUNTERS
  180. static int processes_busy;
  181. #endif
  182. Process** process_tab;
  183. static Uint last_reductions;
  184. static Uint last_exact_reductions;
  185. Uint erts_default_process_flags;
  186. Eterm erts_system_monitor;
  187. Eterm erts_system_monitor_msg_queue_len;
  188. Eterm erts_system_monitor_long_gc;
  189. Eterm erts_system_monitor_large_heap;
  190. struct erts_system_monitor_flags_t erts_system_monitor_flags;
  191. /* system performance monitor */
  192. Eterm erts_system_profile;
  193. struct erts_system_profile_flags_t erts_system_profile_flags;
  194. #ifdef HYBRID
  195. Uint erts_num_active_procs;
  196. Process** erts_active_procs;
  197. #endif
  198. #if ERTS_MAX_PROCESSES > 0x7fffffff
  199. #error "Need to store process_count in another type"
  200. #endif
  201. static erts_smp_atomic32_t process_count;
  202. typedef struct ErtsTermProcElement_ ErtsTermProcElement;
  203. struct ErtsTermProcElement_ {
  204. ErtsTermProcElement *next;
  205. ErtsTermProcElement *prev;
  206. int ix;
  207. union {
  208. struct {
  209. Eterm pid;
  210. SysTimeval spawned;
  211. SysTimeval exited;
  212. } process;
  213. struct {
  214. SysTimeval time;
  215. } bif_invocation;
  216. } u;
  217. };
  218. static struct {
  219. ErtsTermProcElement *start;
  220. ErtsTermProcElement *end;
  221. } saved_term_procs;
  222. ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(misc_op_list,
  223. ErtsMiscOpList,
  224. 10,
  225. ERTS_ALC_T_MISC_OP_LIST)
  226. ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(proclist,
  227. ErtsProcList,
  228. 200,
  229. ERTS_ALC_T_PROC_LIST)
  230. #define ERTS_SCHED_SLEEP_INFO_IX(IX) \
  231. (ASSERT_EXPR(0 <= (IX) && (IX) < erts_no_schedulers), \
  232. &aligned_sched_sleep_info[(IX)].ssi)
  233. #define ERTS_FOREACH_RUNQ(RQVAR, DO) \
  234. do { \
  235. ErtsRunQueue *RQVAR; \
  236. int ix__; \
  237. for (ix__ = 0; ix__ < erts_no_run_queues; ix__++) { \
  238. RQVAR = ERTS_RUNQ_IX(ix__); \
  239. erts_smp_runq_lock(RQVAR); \
  240. { DO; } \
  241. erts_smp_runq_unlock(RQVAR); \
  242. } \
  243. } while (0)
  244. #define ERTS_FOREACH_OP_RUNQ(RQVAR, DO) \
  245. do { \
  246. ErtsRunQueue *RQVAR; \
  247. int ix__; \
  248. ERTS_SMP_LC_ASSERT(erts_smp_lc_mtx_is_locked(&schdlr_sspnd.mtx)); \
  249. for (ix__ = 0; ix__ < schdlr_sspnd.online; ix__++) { \
  250. RQVAR = ERTS_RUNQ_IX(ix__); \
  251. erts_smp_runq_lock(RQVAR); \
  252. { DO; } \
  253. erts_smp_runq_unlock(RQVAR); \
  254. } \
  255. } while (0)
  256. #define ERTS_ATOMIC_FOREACH_RUNQ_X(RQVAR, DO, DOX) \
  257. do { \
  258. ErtsRunQueue *RQVAR; \
  259. int ix__; \
  260. for (ix__ = 0; ix__ < erts_no_run_queues; ix__++) { \
  261. RQVAR = ERTS_RUNQ_IX(ix__); \
  262. erts_smp_runq_lock(RQVAR); \
  263. { DO; } \
  264. } \
  265. { DOX; } \
  266. for (ix__ = 0; ix__ < erts_no_run_queues; ix__++) \
  267. erts_smp_runq_unlock(ERTS_RUNQ_IX(ix__)); \
  268. } while (0)
  269. #define ERTS_ATOMIC_FOREACH_RUNQ(RQVAR, DO) \
  270. ERTS_ATOMIC_FOREACH_RUNQ_X(RQVAR, DO, )
  271. /*
  272. * Local functions.
  273. */
  274. static void init_processes_bif(void);
  275. static void save_terminating_process(Process *p);
  276. static void exec_misc_ops(ErtsRunQueue *);
  277. static void print_function_from_pc(int to, void *to_arg, BeamInstr* x);
  278. static int stack_element_dump(int to, void *to_arg, Process* p, Eterm* sp,
  279. int yreg);
  280. #ifdef ERTS_SMP
  281. static void handle_pending_exiters(ErtsProcList *);
  282. #endif
  283. #if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK)
  284. int
  285. erts_smp_lc_runq_is_locked(ErtsRunQueue *runq)
  286. {
  287. return erts_smp_lc_mtx_is_locked(&runq->mtx);
  288. }
  289. #endif
  290. void
  291. erts_pre_init_process(void)
  292. {
  293. #ifdef USE_THREADS
  294. erts_tsd_key_create(&sched_data_key);
  295. #endif
  296. #ifdef ERTS_ENABLE_LOCK_CHECK
  297. {
  298. int ix;
  299. erts_psd_required_locks[ERTS_PSD_ERROR_HANDLER].get_locks
  300. = ERTS_PSD_ERROR_HANDLER_BUF_GET_LOCKS;
  301. erts_psd_required_locks[ERTS_PSD_ERROR_HANDLER].set_locks
  302. = ERTS_PSD_ERROR_HANDLER_BUF_SET_LOCKS;
  303. erts_psd_required_locks[ERTS_PSD_SAVED_CALLS_BUF].get_locks
  304. = ERTS_PSD_SAVED_CALLS_BUF_GET_LOCKS;
  305. erts_psd_required_locks[ERTS_PSD_SAVED_CALLS_BUF].set_locks
  306. = ERTS_PSD_SAVED_CALLS_BUF_SET_LOCKS;
  307. erts_psd_required_locks[ERTS_PSD_SCHED_ID].get_locks
  308. = ERTS_PSD_SCHED_ID_GET_LOCKS;
  309. erts_psd_required_locks[ERTS_PSD_SCHED_ID].set_locks
  310. = ERTS_PSD_SCHED_ID_SET_LOCKS;
  311. erts_psd_required_locks[ERTS_PSD_DIST_ENTRY].get_locks
  312. = ERTS_PSD_DIST_ENTRY_GET_LOCKS;
  313. erts_psd_required_locks[ERTS_PSD_DIST_ENTRY].set_locks
  314. = ERTS_PSD_DIST_ENTRY_SET_LOCKS;
  315. erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].get_locks
  316. = ERTS_PSD_CALL_TIME_BP_GET_LOCKS;
  317. erts_psd_required_locks[ERTS_PSD_CALL_TIME_BP].set_locks
  318. = ERTS_PSD_CALL_TIME_BP_SET_LOCKS;
  319. /* Check that we have locks for all entries */
  320. for (ix = 0; ix < ERTS_PSD_SIZE; ix++) {
  321. ERTS_SMP_LC_ASSERT(erts_psd_required_locks[ix].get_locks);
  322. ERTS_SMP_LC_ASSERT(erts_psd_required_locks[ix].set_locks);
  323. }
  324. }
  325. #endif
  326. }
  327. /* initialize the scheduler */
  328. void
  329. erts_init_process(int ncpu)
  330. {
  331. Uint proc_bits = ERTS_PROC_BITS;
  332. #ifdef ERTS_SMP
  333. erts_disable_proc_not_running_opt = 0;
  334. erts_init_proc_lock(ncpu);
  335. #endif
  336. init_proclist_alloc();
  337. erts_smp_atomic32_init(&process_count, 0);
  338. if (erts_use_r9_pids_ports) {
  339. proc_bits = ERTS_R9_PROC_BITS;
  340. ASSERT(erts_max_processes <= (1 << ERTS_R9_PROC_BITS));
  341. }
  342. process_tab = (Process**) erts_alloc(ERTS_ALC_T_PROC_TABLE,
  343. erts_max_processes*sizeof(Process*));
  344. sys_memzero(process_tab, erts_max_processes * sizeof(Process*));
  345. #ifdef HYBRID
  346. erts_active_procs = (Process**)
  347. erts_alloc(ERTS_ALC_T_ACTIVE_PROCS,
  348. erts_max_processes * sizeof(Process*));
  349. erts_num_active_procs = 0;
  350. #endif
  351. erts_smp_mtx_init(&proc_tab_mtx, "proc_tab");
  352. p_last = -1;
  353. p_next = 0;
  354. p_serial = 0;
  355. p_serial_shift = erts_fit_in_bits(erts_max_processes - 1);
  356. p_serial_mask = ((~(~((Uint) 0) << proc_bits)) >> p_serial_shift);
  357. erts_process_tab_index_mask = ~(~((Uint) 0) << p_serial_shift);
  358. #ifndef BM_COUNTERS
  359. processes_busy = 0;
  360. #endif
  361. last_reductions = 0;
  362. last_exact_reductions = 0;
  363. erts_default_process_flags = 0;
  364. }
  365. void
  366. erts_late_init_process(void)
  367. {
  368. int ix;
  369. init_processes_bif();
  370. erts_smp_spinlock_init(&erts_sched_stat.lock, "sched_stat");
  371. for (ix = 0; ix < ERTS_NO_PRIO_LEVELS; ix++) {
  372. Eterm atom;
  373. char *atom_str;
  374. switch (ix) {
  375. case PRIORITY_MAX:
  376. atom_str = "process_max";
  377. break;
  378. case PRIORITY_HIGH:
  379. atom_str = "process_high";
  380. break;
  381. case PRIORITY_NORMAL:
  382. atom_str = "process_normal";
  383. break;
  384. case PRIORITY_LOW:
  385. atom_str = "process_low";
  386. break;
  387. case ERTS_PORT_PRIO_LEVEL:
  388. atom_str = "port";
  389. break;
  390. default:
  391. atom_str = "bad_prio";
  392. ASSERT(!"bad prio");
  393. break;
  394. }
  395. atom = am_atom_put(atom_str, sys_strlen(atom_str));
  396. erts_sched_stat.prio[ix].name = atom;
  397. erts_sched_stat.prio[ix].total_executed = 0;
  398. erts_sched_stat.prio[ix].executed = 0;
  399. erts_sched_stat.prio[ix].total_migrated = 0;
  400. erts_sched_stat.prio[ix].migrated = 0;
  401. }
  402. }
  403. static ERTS_INLINE ErtsProcList *
  404. proclist_create(Process *p)
  405. {
  406. ErtsProcList *plp = proclist_alloc();
  407. plp->pid = p->id;
  408. plp->started = p->started;
  409. return plp;
  410. }
  411. static ERTS_INLINE void
  412. proclist_destroy(ErtsProcList *plp)
  413. {
  414. proclist_free(plp);
  415. }
  416. static ERTS_INLINE int
  417. proclist_same(ErtsProcList *plp, Process *p)
  418. {
  419. return (plp->pid == p->id
  420. && erts_cmp_timeval(&plp->started, &p->started) == 0);
  421. }
  422. ErtsProcList *
  423. erts_proclist_create(Process *p)
  424. {
  425. return proclist_create(p);
  426. }
  427. void
  428. erts_proclist_destroy(ErtsProcList *plp)
  429. {
  430. proclist_destroy(plp);
  431. }
  432. int
  433. erts_proclist_same(ErtsProcList *plp, Process *p)
  434. {
  435. return proclist_same(plp, p);
  436. }
  437. void *
  438. erts_psd_set_init(Process *p, ErtsProcLocks plocks, int ix, void *data)
  439. {
  440. void *old;
  441. ErtsProcLocks xplocks;
  442. int refc = 0;
  443. ErtsPSD *psd = erts_alloc(ERTS_ALC_T_PSD, sizeof(ErtsPSD));
  444. int i;
  445. for (i = 0; i < ERTS_PSD_SIZE; i++)
  446. psd->data[i] = NULL;
  447. ERTS_SMP_LC_ASSERT(plocks);
  448. ERTS_SMP_LC_ASSERT(plocks == erts_proc_lc_my_proc_locks(p));
  449. xplocks = ERTS_PROC_LOCKS_ALL;
  450. xplocks &= ~plocks;
  451. if (xplocks && erts_smp_proc_trylock(p, xplocks) == EBUSY) {
  452. if (xplocks & ERTS_PROC_LOCK_MAIN) {
  453. erts_smp_proc_inc_refc(p);
  454. erts_smp_proc_unlock(p, plocks);
  455. erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL);
  456. refc = 1;
  457. }
  458. else {
  459. if (plocks & ERTS_PROC_LOCKS_ALL_MINOR)
  460. erts_smp_proc_unlock(p, plocks & ERTS_PROC_LOCKS_ALL_MINOR);
  461. erts_smp_proc_lock(p, ERTS_PROC_LOCKS_ALL_MINOR);
  462. }
  463. }
  464. if (!p->psd)
  465. p->psd = psd;
  466. if (xplocks)
  467. erts_smp_proc_unlock(p, xplocks);
  468. if (refc)
  469. erts_smp_proc_dec_refc(p);
  470. ASSERT(p->psd);
  471. if (p->psd != psd)
  472. erts_free(ERTS_ALC_T_PSD, psd);
  473. old = p->psd->data[ix];
  474. p->psd->data[ix] = data;
  475. ERTS_SMP_LC_ASSERT(plocks == erts_proc_lc_my_proc_locks(p));
  476. return old;
  477. }
  478. #ifdef ERTS_SMP
  479. void
  480. erts_sched_finish_poke(ErtsSchedulerSleepInfo *ssi, erts_aint32_t flags)
  481. {
  482. switch (flags & ERTS_SSI_FLGS_SLEEP_TYPE) {
  483. case ERTS_SSI_FLG_POLL_SLEEPING:
  484. erts_sys_schedule_interrupt(1);
  485. break;
  486. case ERTS_SSI_FLG_TSE_SLEEPING:
  487. erts_tse_set(ssi->event);
  488. break;
  489. case 0:
  490. break;
  491. default:
  492. erl_exit(ERTS_ABORT_EXIT, "%s:%d: Internal error\n",
  493. __FILE__, __LINE__);
  494. break;
  495. }
  496. }
  497. typedef struct erts_misc_aux_work_t_ erts_misc_aux_work_t;
  498. struct erts_misc_aux_work_t_ {
  499. erts_misc_aux_work_t *next;
  500. void (*func)(void *);
  501. void *arg;
  502. };
  503. typedef struct {
  504. erts_smp_mtx_t mtx;
  505. erts_misc_aux_work_t *first;
  506. erts_misc_aux_work_t *last;
  507. } erts_misc_aux_work_q_t;
  508. typedef union {
  509. erts_misc_aux_work_q_t data;
  510. char align[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_misc_aux_work_q_t))];
  511. } erts_algnd_misc_aux_work_q_t;
  512. static erts_algnd_misc_aux_work_q_t *misc_aux_work_queues;
  513. ERTS_SCHED_PREF_QUICK_ALLOC_IMPL(misc_aux_work,
  514. erts_misc_aux_work_t,
  515. 200,
  516. ERTS_ALC_T_MISC_AUX_WORK)
  517. static void
  518. init_misc_aux_work(void)
  519. {
  520. int ix;
  521. init_misc_aux_work_alloc();
  522. misc_aux_work_queues = erts_alloc(ERTS_ALC_T_MISC_AUX_WORK_Q,
  523. (sizeof(erts_algnd_misc_aux_work_q_t)
  524. *(erts_no_schedulers+1)));
  525. if ((((UWord) misc_aux_work_queues) & ERTS_CACHE_LINE_MASK) != 0)
  526. misc_aux_work_queues = ((erts_algnd_misc_aux_work_q_t *)
  527. ((((UWord) misc_aux_work_queues)
  528. & ~ERTS_CACHE_LINE_MASK)
  529. + ERTS_CACHE_LINE_SIZE));
  530. for (ix = 0; ix < erts_no_schedulers; ix++) {
  531. erts_smp_mtx_init_x(&misc_aux_work_queues[ix].data.mtx,
  532. "misc_aux_work_queue",
  533. make_small(ix + 1));
  534. misc_aux_work_queues[ix].data.first = NULL;
  535. misc_aux_work_queues[ix].data.last = NULL;
  536. }
  537. }
  538. static void
  539. handle_misc_aux_work(ErtsSchedulerData *esdp)
  540. {
  541. int ix = (int) esdp->no - 1;
  542. erts_misc_aux_work_t *mawp;
  543. erts_smp_mtx_lock(&misc_aux_work_queues[ix].data.mtx);
  544. mawp = misc_aux_work_queues[ix].data.first;
  545. misc_aux_work_queues[ix].data.first = NULL;
  546. misc_aux_work_queues[ix].data.last = NULL;
  547. erts_smp_mtx_unlock(&misc_aux_work_queues[ix].data.mtx);
  548. while (mawp) {
  549. erts_misc_aux_work_t *free_mawp;
  550. mawp->func(mawp->arg);
  551. free_mawp = mawp;
  552. mawp = mawp->next;
  553. misc_aux_work_free(free_mawp);
  554. }
  555. }
  556. void
  557. erts_smp_schedule_misc_aux_work(int ignore_self,
  558. int max_sched,
  559. void (*func)(void *),
  560. void *arg)
  561. {
  562. int ix, ignore_ix = -1;
  563. if (ignore_self) {
  564. ErtsSchedulerData *esdp = erts_get_scheduler_data();
  565. if (esdp)
  566. ignore_ix = (int) esdp->no - 1;
  567. }
  568. ASSERT(0 <= max_sched && max_sched <= erts_no_schedulers);
  569. for (ix = 0; ix < max_sched; ix++) {
  570. erts_aint32_t aux_work;
  571. erts_misc_aux_work_t *mawp;
  572. ErtsSchedulerSleepInfo *ssi;
  573. if (ix == ignore_ix)
  574. continue;
  575. mawp = misc_aux_work_alloc();
  576. mawp->func = func;
  577. mawp->arg = arg;
  578. mawp->next = NULL;
  579. erts_smp_mtx_lock(&misc_aux_work_queues[ix].data.mtx);
  580. if (!misc_aux_work_queues[ix].data.last)
  581. misc_aux_work_queues[ix].data.first = mawp;
  582. else
  583. misc_aux_work_queues[ix].data.last->next = mawp;
  584. misc_aux_work_queues[ix].data.last = mawp;
  585. erts_smp_mtx_unlock(&misc_aux_work_queues[ix].data.mtx);
  586. ssi = ERTS_SCHED_SLEEP_INFO_IX(ix);
  587. aux_work = erts_smp_atomic32_bor(&ssi->aux_work,
  588. ERTS_SSI_AUX_WORK_MISC);
  589. if ((aux_work & ERTS_SSI_AUX_WORK_MISC) == 0)
  590. erts_sched_poke(ssi);
  591. }
  592. }
  593. #ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
  594. void
  595. erts_smp_notify_check_children_needed(void)
  596. {
  597. int i;
  598. for (i = 0; i < erts_no_schedulers; i++) {
  599. erts_aint32_t aux_work;
  600. ErtsSchedulerSleepInfo *ssi;
  601. ssi = ERTS_SCHED_SLEEP_INFO_IX(i);
  602. aux_work = erts_smp_atomic32_bor(&ssi->aux_work,
  603. ERTS_SSI_AUX_WORK_CHECK_CHILDREN);
  604. if (!(aux_work & ERTS_SSI_AUX_WORK_CHECK_CHILDREN))
  605. erts_sched_poke(ssi);
  606. }
  607. }
  608. #endif
  609. #ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  610. static ERTS_INLINE erts_aint32_t
  611. blockable_aux_work(ErtsSchedulerData *esdp,
  612. ErtsSchedulerSleepInfo *ssi,
  613. erts_aint32_t aux_work)
  614. {
  615. if (aux_work & ERTS_SSI_BLOCKABLE_AUX_WORK_MASK) {
  616. if (aux_work & ERTS_SSI_AUX_WORK_MISC) {
  617. aux_work = erts_smp_atomic32_band(&ssi->aux_work,
  618. ~ERTS_SSI_AUX_WORK_MISC);
  619. aux_work &= ~ERTS_SSI_AUX_WORK_MISC;
  620. handle_misc_aux_work(esdp);
  621. }
  622. #ifdef ERTS_SMP_SCHEDULERS_NEED_TO_CHECK_CHILDREN
  623. if (aux_work & ERTS_SSI_AUX_WORK_CHECK_CHILDREN) {
  624. aux_work = erts_smp_atomic32_band(&ssi->aux_work,
  625. ~ERTS_SSI_AUX_WORK_CHECK_CHILDREN);
  626. aux_work &= ~ERTS_SSI_AUX_WORK_CHECK_CHILDREN;
  627. erts_check_children();
  628. }
  629. #endif
  630. }
  631. return aux_work;
  632. }
  633. #endif
  634. #ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
  635. static ERTS_INLINE erts_aint32_t
  636. nonblockable_aux_work(ErtsSchedulerData *esdp,
  637. ErtsSchedulerSleepInfo *ssi,
  638. erts_aint32_t aux_work)
  639. {
  640. if (aux_work & ERTS_SSI_NONBLOCKABLE_AUX_WORK_MASK) {
  641. }
  642. }
  643. #endif
  644. static void
  645. prepare_for_block(void *vrq)
  646. {
  647. erts_smp_runq_unlock((ErtsRunQueue *) vrq);
  648. }
  649. static void
  650. resume_after_block(void *vrq)
  651. {
  652. erts_smp_runq_lock((ErtsRunQueue *) vrq);
  653. }
  654. #endif
  655. static ERTS_INLINE void
  656. sched_waiting_sys(Uint no, ErtsRunQueue *rq)
  657. {
  658. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  659. ASSERT(rq->waiting >= 0);
  660. rq->flags |= (ERTS_RUNQ_FLG_OUT_OF_WORK
  661. | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK);
  662. rq->waiting++;
  663. rq->waiting *= -1;
  664. rq->woken = 0;
  665. if (erts_system_profile_flags.scheduler)
  666. profile_scheduler(make_small(no), am_inactive);
  667. }
  668. static ERTS_INLINE void
  669. sched_active_sys(Uint no, ErtsRunQueue *rq)
  670. {
  671. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  672. ASSERT(rq->waiting < 0);
  673. rq->waiting *= -1;
  674. rq->waiting--;
  675. if (erts_system_profile_flags.scheduler)
  676. profile_scheduler(make_small(no), am_active);
  677. }
  678. Uint
  679. erts_active_schedulers(void)
  680. {
  681. /* RRRRRRRRR */
  682. Uint as = erts_no_schedulers;
  683. ERTS_ATOMIC_FOREACH_RUNQ(rq, as -= abs(rq->waiting));
  684. ASSERT(as >= 0);
  685. return as;
  686. }
  687. static ERTS_INLINE int
  688. prepare_for_sys_schedule(void)
  689. {
  690. #ifdef ERTS_SMP
  691. while (!erts_port_task_have_outstanding_io_tasks()
  692. && !erts_smp_atomic32_xchg(&doing_sys_schedule, 1)) {
  693. if (!erts_port_task_have_outstanding_io_tasks())
  694. return 1;
  695. erts_smp_atomic32_set(&doing_sys_schedule, 0);
  696. }
  697. return 0;
  698. #else
  699. return !erts_port_task_have_outstanding_io_tasks();
  700. #endif
  701. }
  702. #ifdef ERTS_SMP
  703. static ERTS_INLINE void
  704. sched_change_waiting_sys_to_waiting(Uint no, ErtsRunQueue *rq)
  705. {
  706. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  707. ASSERT(rq->waiting < 0);
  708. rq->waiting *= -1;
  709. }
  710. static ERTS_INLINE void
  711. sched_waiting(Uint no, ErtsRunQueue *rq)
  712. {
  713. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  714. rq->flags |= (ERTS_RUNQ_FLG_OUT_OF_WORK
  715. | ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK);
  716. if (rq->waiting < 0)
  717. rq->waiting--;
  718. else
  719. rq->waiting++;
  720. rq->woken = 0;
  721. if (erts_system_profile_flags.scheduler)
  722. profile_scheduler(make_small(no), am_inactive);
  723. }
  724. static ERTS_INLINE void
  725. sched_active(Uint no, ErtsRunQueue *rq)
  726. {
  727. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  728. if (rq->waiting < 0)
  729. rq->waiting++;
  730. else
  731. rq->waiting--;
  732. if (erts_system_profile_flags.scheduler)
  733. profile_scheduler(make_small(no), am_active);
  734. }
  735. static int ERTS_INLINE
  736. ongoing_multi_scheduling_block(void)
  737. {
  738. return erts_smp_atomic32_read(&schdlr_sspnd.msb.ongoing) != 0;
  739. }
  740. static ERTS_INLINE void
  741. empty_runq(ErtsRunQueue *rq)
  742. {
  743. erts_aint32_t oifls = erts_smp_atomic32_band(&rq->info_flags,
  744. ~ERTS_RUNQ_IFLG_NONEMPTY);
  745. if (oifls & ERTS_RUNQ_IFLG_NONEMPTY) {
  746. #ifdef DEBUG
  747. erts_aint32_t empty = erts_smp_atomic32_read(&no_empty_run_queues);
  748. /*
  749. * For a short period of time no_empty_run_queues may have
  750. * been increased twice for a specific run queue.
  751. */
  752. ASSERT(0 <= empty && empty < 2*erts_no_run_queues);
  753. #endif
  754. erts_smp_atomic32_inc(&no_empty_run_queues);
  755. }
  756. }
  757. static ERTS_INLINE void
  758. non_empty_runq(ErtsRunQueue *rq)
  759. {
  760. erts_aint32_t oifls = erts_smp_atomic32_bor(&rq->info_flags,
  761. ERTS_RUNQ_IFLG_NONEMPTY);
  762. if (!(oifls & ERTS_RUNQ_IFLG_NONEMPTY)) {
  763. #ifdef DEBUG
  764. erts_aint32_t empty = erts_smp_atomic32_read(&no_empty_run_queues);
  765. /*
  766. * For a short period of time no_empty_run_queues may have
  767. * been increased twice for a specific run queue.
  768. */
  769. ASSERT(0 < empty && empty <= 2*erts_no_run_queues);
  770. #endif
  771. erts_smp_atomic32_dec(&no_empty_run_queues);
  772. }
  773. }
  774. static erts_aint32_t
  775. sched_prep_spin_wait(ErtsSchedulerSleepInfo *ssi)
  776. {
  777. erts_aint32_t oflgs;
  778. erts_aint32_t nflgs = (ERTS_SSI_FLG_SLEEPING
  779. | ERTS_SSI_FLG_WAITING);
  780. erts_aint32_t xflgs = 0;
  781. do {
  782. oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
  783. if (oflgs == xflgs)
  784. return nflgs;
  785. xflgs = oflgs;
  786. } while (!(oflgs & ERTS_SSI_FLG_SUSPENDED));
  787. return oflgs;
  788. }
  789. static erts_aint32_t
  790. sched_prep_cont_spin_wait(ErtsSchedulerSleepInfo *ssi)
  791. {
  792. erts_aint32_t oflgs;
  793. erts_aint32_t nflgs = (ERTS_SSI_FLG_SLEEPING
  794. | ERTS_SSI_FLG_WAITING);
  795. erts_aint32_t xflgs = ERTS_SSI_FLG_WAITING;
  796. do {
  797. oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
  798. if (oflgs == xflgs)
  799. return nflgs;
  800. xflgs = oflgs;
  801. nflgs |= oflgs & ERTS_SSI_FLG_SUSPENDED;
  802. } while (oflgs & ERTS_SSI_FLG_WAITING);
  803. return oflgs;
  804. }
  805. static erts_aint32_t
  806. sched_spin_wait(ErtsSchedulerSleepInfo *ssi, int spincount)
  807. {
  808. int until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
  809. int sc = spincount;
  810. erts_aint32_t flgs;
  811. do {
  812. flgs = erts_smp_atomic32_read(&ssi->flags);
  813. if ((flgs & (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING))
  814. != (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING)) {
  815. break;
  816. }
  817. ERTS_SPIN_BODY;
  818. if (--until_yield == 0) {
  819. until_yield = ERTS_SCHED_SPIN_UNTIL_YIELD;
  820. erts_thr_yield();
  821. }
  822. } while (--sc > 0);
  823. return flgs;
  824. }
  825. static erts_aint32_t
  826. sched_set_sleeptype(ErtsSchedulerSleepInfo *ssi, erts_aint32_t sleep_type)
  827. {
  828. erts_aint32_t oflgs;
  829. erts_aint32_t nflgs = ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING|sleep_type;
  830. erts_aint32_t xflgs = ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING;
  831. if (sleep_type == ERTS_SSI_FLG_TSE_SLEEPING)
  832. erts_tse_reset(ssi->event);
  833. while (1) {
  834. oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
  835. if (oflgs == xflgs)
  836. return nflgs;
  837. if ((oflgs & (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING))
  838. != (ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING)) {
  839. return oflgs;
  840. }
  841. xflgs = oflgs;
  842. nflgs |= oflgs & ERTS_SSI_FLG_SUSPENDED;
  843. }
  844. }
  845. #define ERTS_SCHED_WAIT_WOKEN(FLGS) \
  846. (((FLGS) & (ERTS_SSI_FLG_WAITING|ERTS_SSI_FLG_SUSPENDED)) \
  847. != ERTS_SSI_FLG_WAITING)
  848. static void
  849. scheduler_wait(int *fcalls, ErtsSchedulerData *esdp, ErtsRunQueue *rq)
  850. {
  851. ErtsSchedulerSleepInfo *ssi = esdp->ssi;
  852. int spincount;
  853. erts_aint32_t flgs;
  854. #if defined(ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK) \
  855. || defined(ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK)
  856. erts_aint32_t aux_work;
  857. #endif
  858. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  859. erts_smp_spin_lock(&rq->sleepers.lock);
  860. flgs = sched_prep_spin_wait(ssi);
  861. if (flgs & ERTS_SSI_FLG_SUSPENDED) {
  862. /* Go suspend instead... */
  863. erts_smp_spin_unlock(&rq->sleepers.lock);
  864. return;
  865. }
  866. ssi->prev = NULL;
  867. ssi->next = rq->sleepers.list;
  868. if (rq->sleepers.list)
  869. rq->sleepers.list->prev = ssi;
  870. rq->sleepers.list = ssi;
  871. erts_smp_spin_unlock(&rq->sleepers.lock);
  872. /*
  873. * If all schedulers are waiting, one of them *should*
  874. * be waiting in erl_sys_schedule()
  875. */
  876. if (!prepare_for_sys_schedule()) {
  877. sched_waiting(esdp->no, rq);
  878. erts_smp_runq_unlock(rq);
  879. spincount = ERTS_SCHED_TSE_SLEEP_SPINCOUNT;
  880. tse_wait:
  881. #ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  882. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  883. tse_blockable_aux_work:
  884. aux_work = blockable_aux_work(esdp, ssi, aux_work);
  885. #endif
  886. erts_smp_activity_begin(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
  887. while (1) {
  888. #ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
  889. #ifndef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  890. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  891. #endif
  892. nonblockable_aux_work(esdp, ssi, aux_work);
  893. #endif
  894. flgs = sched_spin_wait(ssi, spincount);
  895. if (flgs & ERTS_SSI_FLG_SLEEPING) {
  896. ASSERT(flgs & ERTS_SSI_FLG_WAITING);
  897. flgs = sched_set_sleeptype(ssi, ERTS_SSI_FLG_TSE_SLEEPING);
  898. if (flgs & ERTS_SSI_FLG_SLEEPING) {
  899. int res;
  900. ASSERT(flgs & ERTS_SSI_FLG_TSE_SLEEPING);
  901. ASSERT(flgs & ERTS_SSI_FLG_WAITING);
  902. do {
  903. res = erts_tse_wait(ssi->event);
  904. } while (res == EINTR);
  905. }
  906. }
  907. if (!(flgs & ERTS_SSI_FLG_WAITING)) {
  908. ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
  909. break;
  910. }
  911. flgs = sched_prep_cont_spin_wait(ssi);
  912. spincount = ERTS_SCHED_TSE_SLEEP_SPINCOUNT;
  913. if (!(flgs & ERTS_SSI_FLG_WAITING)) {
  914. ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
  915. break;
  916. }
  917. #ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  918. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  919. if (aux_work & ERTS_SSI_BLOCKABLE_AUX_WORK_MASK) {
  920. erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
  921. goto tse_blockable_aux_work;
  922. }
  923. #endif
  924. }
  925. erts_smp_activity_end(ERTS_ACTIVITY_WAIT, NULL, NULL, NULL);
  926. if (flgs & ~ERTS_SSI_FLG_SUSPENDED)
  927. erts_smp_atomic32_band(&ssi->flags, ERTS_SSI_FLG_SUSPENDED);
  928. erts_smp_runq_lock(rq);
  929. sched_active(esdp->no, rq);
  930. }
  931. else {
  932. erts_aint_t dt;
  933. erts_smp_atomic32_set(&function_calls, 0);
  934. *fcalls = 0;
  935. sched_waiting_sys(esdp->no, rq);
  936. erts_smp_runq_unlock(rq);
  937. spincount = ERTS_SCHED_SYS_SLEEP_SPINCOUNT;
  938. while (spincount-- > 0) {
  939. sys_poll_aux_work:
  940. ASSERT(!erts_port_task_have_outstanding_io_tasks());
  941. erl_sys_schedule(1); /* Might give us something to do */
  942. dt = erts_do_time_read_and_reset();
  943. if (dt) erts_bump_timer(dt);
  944. sys_aux_work:
  945. #ifdef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  946. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  947. aux_work = blockable_aux_work(esdp, ssi, aux_work);
  948. #endif
  949. #ifdef ERTS_SCHED_NEED_NONBLOCKABLE_AUX_WORK
  950. #ifndef ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK
  951. aux_work = erts_smp_atomic32_read(&ssi->aux_work);
  952. #endif
  953. nonblockable_aux_work(esdp, ssi, aux_work);
  954. #endif
  955. flgs = erts_smp_atomic32_read(&ssi->flags);
  956. if (!(flgs & ERTS_SSI_FLG_WAITING)) {
  957. ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
  958. goto sys_woken;
  959. }
  960. if (!(flgs & ERTS_SSI_FLG_SLEEPING)) {
  961. flgs = sched_prep_cont_spin_wait(ssi);
  962. if (!(flgs & ERTS_SSI_FLG_WAITING)) {
  963. ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
  964. goto sys_woken;
  965. }
  966. }
  967. /*
  968. * If we got new I/O tasks we aren't allowed to
  969. * call erl_sys_schedule() until it is handled.
  970. */
  971. if (erts_port_task_have_outstanding_io_tasks()) {
  972. erts_smp_atomic32_set(&doing_sys_schedule, 0);
  973. /*
  974. * Got to check that we still got I/O tasks; otherwise
  975. * we have to continue checking for I/O...
  976. */
  977. if (!prepare_for_sys_schedule()) {
  978. spincount *= ERTS_SCHED_TSE_SLEEP_SPINCOUNT_FACT;
  979. goto tse_wait;
  980. }
  981. }
  982. }
  983. erts_smp_runq_lock(rq);
  984. /*
  985. * If we got new I/O tasks we aren't allowed to
  986. * sleep in erl_sys_schedule().
  987. */
  988. if (erts_port_task_have_outstanding_io_tasks()) {
  989. erts_smp_atomic32_set(&doing_sys_schedule, 0);
  990. /*
  991. * Got to check that we still got I/O tasks; otherwise
  992. * we have to wait in erl_sys_schedule() after all...
  993. */
  994. if (prepare_for_sys_schedule())
  995. goto do_sys_schedule;
  996. /*
  997. * Not allowed to wait in erl_sys_schedule;
  998. * do tse wait instead...
  999. */
  1000. sched_change_waiting_sys_to_waiting(esdp->no, rq);
  1001. erts_smp_runq_unlock(rq);
  1002. spincount = 0;
  1003. goto tse_wait;
  1004. }
  1005. else {
  1006. do_sys_schedule:
  1007. erts_sys_schedule_interrupt(0);
  1008. flgs = sched_set_sleeptype(ssi, ERTS_SSI_FLG_POLL_SLEEPING);
  1009. if (!(flgs & ERTS_SSI_FLG_SLEEPING)) {
  1010. if (!(flgs & ERTS_SSI_FLG_WAITING))
  1011. goto sys_locked_woken;
  1012. erts_smp_runq_unlock(rq);
  1013. flgs = sched_prep_cont_spin_wait(ssi);
  1014. if (!(flgs & ERTS_SSI_FLG_WAITING)) {
  1015. ASSERT(!(flgs & ERTS_SSI_FLG_SLEEPING));
  1016. goto sys_woken;
  1017. }
  1018. ASSERT(!erts_port_task_have_outstanding_io_tasks());
  1019. goto sys_poll_aux_work;
  1020. }
  1021. ASSERT(flgs & ERTS_SSI_FLG_POLL_SLEEPING);
  1022. ASSERT(flgs & ERTS_SSI_FLG_WAITING);
  1023. erts_smp_runq_unlock(rq);
  1024. ASSERT(!erts_port_task_have_outstanding_io_tasks());
  1025. erl_sys_schedule(0);
  1026. dt = erts_do_time_read_and_reset();
  1027. if (dt) erts_bump_timer(dt);
  1028. flgs = sched_prep_cont_spin_wait(ssi);
  1029. if (flgs & ERTS_SSI_FLG_WAITING)
  1030. goto sys_aux_work;
  1031. sys_woken:
  1032. erts_smp_runq_lock(rq);
  1033. sys_locked_woken:
  1034. erts_smp_atomic32_set(&doing_sys_schedule, 0);
  1035. if (flgs & ~ERTS_SSI_FLG_SUSPENDED)
  1036. erts_smp_atomic32_band(&ssi->flags, ERTS_SSI_FLG_SUSPENDED);
  1037. sched_active_sys(esdp->no, rq);
  1038. }
  1039. }
  1040. ERTS_SMP_LC_ASSERT(erts_smp_lc_runq_is_locked(rq));
  1041. }
  1042. static ERTS_INLINE erts_aint32_t
  1043. ssi_flags_set_wake(ErtsSchedulerSleepInfo *ssi)
  1044. {
  1045. /* reset all flags but suspended */
  1046. erts_aint32_t oflgs;
  1047. erts_aint32_t nflgs = 0;
  1048. erts_aint32_t xflgs = ERTS_SSI_FLG_SLEEPING|ERTS_SSI_FLG_WAITING;
  1049. while (1) {
  1050. oflgs = erts_smp_atomic32_cmpxchg(&ssi->flags, nflgs, xflgs);
  1051. if (oflgs == xflgs)
  1052. return oflgs;
  1053. nflgs = oflgs & ERTS_SSI_FLG_SUSPENDED;
  1054. xflgs = oflgs;
  1055. }
  1056. }
  1057. static void
  1058. wake_scheduler(ErtsRunQueue *rq, int incq, int one)
  1059. {
  1060. int res;
  1061. ErtsSchedulerSleepInfo *ssi;
  1062. ErtsSchedulerSleepList *sl;
  1063. /*
  1064. * The unlocked run queue is not strictly necessary
  1065. * from a thread safety or deadlock prevention
  1066. * perspective. It will, however, cost us performance
  1067. * if it is locked during wakup of another scheduler,
  1068. * so all code *should* handle this without having
  1069. * the lock on the run queue.
  1070. */
  1071. ERTS_SMP_LC_ASSERT(!erts_smp_lc_runq_is_locked(rq));
  1072. sl = &rq->sleepers;
  1073. erts_smp_spin_lock(&sl->lock);
  1074. ssi = sl->list;
  1075. if (!ssi)
  1076. erts_smp_spin_unlock(&sl->lock);
  1077. else if (one) {
  1078. erts_aint32_t flgs;
  1079. if (ssi->prev)
  1080. ssi->prev->next = ssi->next;
  1081. else {
  1082. ASSERT(sl->list == ssi);
  1083. sl->list = ssi->next;
  1084. }
  1085. if (ssi->next)
  1086. ssi->next->prev = ssi->prev;
  1087. res = sl->list != NULL;
  1088. erts_smp_spin_unlock(&sl->lock);
  1089. flgs = ssi_flags_set_wake(ssi);
  1090. erts_sched_finish_poke(ssi, flgs);
  1091. if (incq && !erts_common_run_queue && (flgs & ERTS_SSI_FLG_WAITING))
  1092. non_empty_runq(rq);
  1093. }
  1094. else {
  1095. sl->list = NULL;
  1096. erts_smp_spin_unlock(&sl->lock);
  1097. do {
  1098. ErtsSchedulerSleepInfo *wake_ssi = ssi;
  1099. ssi = ssi->next;
  1100. erts_sched_finish_poke(wake_ssi, ssi_flags_set_wake(wake_ssi));
  1101. } while (ssi);
  1102. }
  1103. }
  1104. static void
  1105. wake_all_schedulers(void)
  1106. {
  1107. if (erts_common_run_queue)
  1108. wake_scheduler(erts_common_run_queue, 0, 0);
  1109. else {
  1110. int ix;
  1111. for (ix = 0; ix < erts_no_run_queues; ix++) {
  1112. ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
  1113. wake_scheduler(rq, 0, 1);
  1114. }
  1115. }
  1116. }
  1117. static ERTS_INLINE int
  1118. chk_wake_sched(ErtsRunQueue *crq, int ix, int activate)
  1119. {
  1120. erts_aint32_t iflgs;
  1121. ErtsRunQueue *wrq;
  1122. if (crq->ix == ix)
  1123. return 0;
  1124. wrq = ERTS_RUNQ_IX(ix);
  1125. iflgs = erts_smp_atomic32_read(&wrq->info_flags);
  1126. if (!(iflgs & (ERTS_RUNQ_IFLG_SUSPENDED|ERTS_RUNQ_IFLG_NONEMPTY))) {
  1127. if (activate) {
  1128. if (ix == erts_smp_atomic32_cmpxchg(&balance_info.active_runqs,
  1129. ix+1,
  1130. ix)) {
  1131. erts_smp_xrunq_lock(crq, wrq);
  1132. wrq->flags &= ~ERTS_RUNQ_FLG_INACTIVE;
  1133. erts_smp_xrunq_unlock(crq, wrq);
  1134. }
  1135. }
  1136. wake_scheduler(wrq, 0, 1);
  1137. return 1;
  1138. }
  1139. return 0;
  1140. }
  1141. static void
  1142. wake_scheduler_on_empty_runq(ErtsRunQueue *crq)
  1143. {
  1144. int ix = crq->ix;
  1145. int stop_ix = ix;
  1146. int active_ix = erts_smp_atomic32_read(&balance_info.active_runqs);
  1147. int balance_ix = erts_smp_atomic32_read(&balance_info.used_runqs);
  1148. if (active_ix > balance_ix)
  1149. active_ix = balance_ix;
  1150. if (ix >= active_ix)
  1151. stop_ix = ix = active_ix;
  1152. /* Try to wake a scheduler on an active run queue */
  1153. while (1) {
  1154. ix--;
  1155. if (ix < 0) {
  1156. if (active_ix == stop_ix)
  1157. break;
  1158. ix = active_ix - 1;
  1159. }
  1160. if (ix == stop_ix)
  1161. break;
  1162. if (chk_wake_sched(crq, ix, 0))
  1163. return;
  1164. }
  1165. if (active_ix < balance_ix) {
  1166. /* Try to activate a new run queue and wake its scheduler */
  1167. (void) chk_wake_sched(crq, active_ix, 1);
  1168. }
  1169. }
  1170. #endif /* ERTS_SMP */
  1171. static ERTS_INLINE void
  1172. smp_notify_inc_runq(ErtsRunQueue *runq)
  1173. {
  1174. #ifdef ERTS_SMP
  1175. if (runq)
  1176. wake_scheduler(runq, 1, 1);
  1177. #endif
  1178. }
  1179. void
  1180. erts_smp_notify_inc_runq(ErtsRunQueue *runq)
  1181. {
  1182. smp_notify_inc_runq(runq);
  1183. }
  1184. void
  1185. erts_sched_notify_check_cpu_bind(void)
  1186. {
  1187. #ifdef ERTS_SMP
  1188. int ix;
  1189. if (erts_common_run_queue) {
  1190. for (ix = 0; ix < erts_no_schedulers; ix++)
  1191. erts_smp_atomic32_set(&ERTS_SCHEDULER_IX(ix)->chk_cpu_bind, 1);
  1192. wake_all_schedulers();
  1193. }
  1194. else {
  1195. for (ix = 0; ix < erts_no_run_queues; ix++) {
  1196. ErtsRunQueue *rq = ERTS_RUNQ_IX(ix);
  1197. erts_smp_runq_lock(rq);
  1198. rq->flags |= ERTS_RUNQ_FLG_CHK_CPU_BIND;
  1199. erts_smp_runq_unlock(rq);
  1200. wake_scheduler(rq, 0, 1);
  1201. };
  1202. }
  1203. #else
  1204. erts_sched_check_cpu_bind(erts_get_scheduler_data());
  1205. #endif
  1206. }
  1207. #ifdef ERTS_SMP
  1208. ErtsRunQueue *
  1209. erts_prepare_emigrate(ErtsRunQueue *c_rq, ErtsRunQueueInfo *c_rqi, int prio)
  1210. {
  1211. ASSERT(ERTS_CHK_RUNQ_FLG_EMIGRATE(c_rq->flags, prio));
  1212. ASSERT(ERTS_CHK_RUNQ_FLG_EVACUATE(c_rq->flags, prio)
  1213. || c_rqi->len >= c_rqi->migrate.limit.this);
  1214. while (1) {
  1215. ErtsRunQueue *n_rq = c_rqi->migrate.runq;
  1216. ERTS_DBG_VERIFY_VALID_RUNQP(n_rq);
  1217. erts_smp_xrunq_lock(c_rq, n_rq);
  1218. /*
  1219. * erts_smp_xrunq_lock() may release lock on c_rq! We have
  1220. * to check that we still want to emigrate and emigrate
  1221. * to the same run queue as before.
  1222. */
  1223. if (ERTS_CHK_RUNQ_FLG_EMIGRATE(c_rq->flags, prio)) {
  1224. Uint32 force = (ERTS_CHK_RUNQ_FLG_EVACUATE(c_rq->flags, prio)
  1225. | (c_rq->flags & ERTS_RUNQ_FLG_INACTIVE));
  1226. if (force || c_rqi->len > c_rqi->migrate.limit.this) {
  1227. ErtsRunQueueInfo *n_rqi;
  1228. /* We still want to emigrate */
  1229. if (n_rq != c_rqi->migrate.runq) {
  1230. /* Ahh... run queue changed; need to do it all over again... */
  1231. erts_smp_runq_unlock(n_rq);
  1232. continue;
  1233. }
  1234. else {
  1235. if (prio == ERTS_PORT_PRIO_LEVEL)
  1236. n_rqi = &n_rq->ports.info;
  1237. else
  1238. n_rqi = &n_rq->procs.prio_info[prio];
  1239. if (force || (n_rqi->len < c_rqi->migrate.limit.other)) {
  1240. /* emigrate ... */
  1241. return n_rq;
  1242. }
  1243. }
  1244. }
  1245. }
  1246. ASSERT(n_rq != c_rq);
  1247. erts_smp_runq_unlock(n_rq);
  1248. if (!(c_rq->flags & ERTS_RUNQ_FLG_INACTIVE)) {
  1249. /* No more emigrations to this runq */
  1250. ERTS_UNSET_RUNQ_FLG_EMIGRATE(c_rq->flags, prio);
  1251. ERTS_DBG_SET_INVALID_RUNQP(c_rqi->migrate.runq, 0x3);
  1252. }
  1253. return NULL;
  1254. }
  1255. }
  1256. static void
  1257. immigrate(ErtsRunQueue *rq)
  1258. {
  1259. int prio;
  1260. ASSERT(rq->flags & ERTS_RUNQ_FLGS_IMMIGRATE_QMASK);
  1261. for (prio = 0; prio < ERTS_NO_PRIO_LEVELS; prio++) {
  1262. if (ERTS_CHK_RUNQ_FLG_IMMIGRATE(rq->flags, prio)) {
  1263. ErtsRunQueueInfo *rqi = (prio == ERTS_PORT_PRIO_LEVEL
  1264. ? &rq->ports.info
  1265. : &rq->procs.prio_info[prio]);
  1266. ErtsRunQueue *from_rq = rqi->migrate.runq;
  1267. int rq_locked, from_rq_locked;
  1268. ERTS_DBG_VERIFY_VALID_RUNQP(from_rq);
  1269. rq_locked = 1;
  1270. from_rq_locked = 1;
  1271. erts_smp_xrunq_lock(rq, from_rq);
  1272. /*
  1273. * erts_smp_xrunq_lock() may release lock on rq! We have
  1274. * to check that we still want to immigrate from the same
  1275. * run queue as before.
  1276. */
  1277. if (ERTS_CHK_RUNQ_FLG_IMMIGRATE(rq->flags, prio)
  1278. && from_rq == rqi->migrate.runq) {
  1279. ErtsRunQueueInfo *from_rqi = (prio == ERTS_PORT_PRIO_LEVEL
  1280. ? &from_rq->ports.info
  1281. : &from_rq->procs.prio_info[prio]);
  1282. if ((ERTS_CHK_RUNQ_FLG_EVACUATE(rq->flags, prio)
  1283. && ERTS_CHK_RUNQ_FLG_EVACUATE(from_rq->flags, prio)
  1284. && from_rqi->len)
  1285. || (from_rqi->len > rqi->migrate.limit.other
  1286. && rqi->len < rqi->migrate.limit.this)) {
  1287. if (prio == ERTS_PORT_PRIO_LEVEL) {
  1288. Port *prt = from_rq->ports.start;
  1289. if (prt) {
  1290. int prt_locked = 0;
  1291. (void) erts_port_migrate(prt, &prt_locked,
  1292. from_rq, &from_rq_locked,
  1293. rq, &rq_locked);
  1294. if (prt_locked)
  1295. erts_smp_port_unlock(prt);
  1296. }
  1297. }
  1298. else {
  1299. Process *proc;
  1300. ErtsRunPrioQueue *from_rpq;
  1301. from_rpq = (prio == PRIORITY_LOW
  1302. ? &from_rq->procs.prio[PRIORITY_NORMAL]
  1303. : &from_rq->procs.prio[prio]);
  1304. for (proc = from_rpq->first; proc; proc = proc->next)
  1305. if (proc->prio == prio && !proc->bound_runq)
  1306. break;
  1307. if (proc) {
  1308. ErtsProcLocks proc_locks = 0;
  1309. (void) erts_proc_migrate(proc, &proc_locks,
  1310. from_rq, &from_rq_locked,
  1311. rq, &rq_locked);
  1312. if (proc_locks)
  1313. erts_smp_proc_unlock(proc, proc_locks);
  1314. }
  1315. }
  1316. }
  1317. else {
  1318. ERTS_UNSET_RUNQ_FLG_IMMIGRATE(rq->flags, prio);
  1319. ERTS_DBG_SET_INVALID_RUNQP(rqi->migrate.runq, 0x1);
  1320. }
  1321. }
  1322. if (from_rq_locked)
  1323. erts_smp_runq_unlock(from_rq);
  1324. if (!rq_locked)
  1325. erts_smp_runq_lock(rq);
  1326. }
  1327. }
  1328. }
  1329. static void
  1330. evacuate_run_queue(ErtsRunQueue *evac_rq, ErtsRunQueue *rq)
  1331. {
  1332. Port *prt;
  1333. int notify_to_rq = 0;
  1334. int prio;
  1335. int prt_locked = 0;
  1336. int rq_locked = 0;
  1337. int evac_rq_locked = 1;
  1338. ErtsMigrateResult mres;
  1339. erts_smp_runq_lock(evac_rq);
  1340. erts_smp_atomic32_bor(&evac_rq->scheduler->ssi->flags,
  1341. ERTS_SSI_FLG_SUSPENDED);
  1342. evac_rq->flags &= ~ERTS_RUNQ_FLGS_IMMIGRATE_QMASK;
  1343. evac_rq->flags |= (ERTS_RUNQ_FLGS_EMIGRATE_QMASK
  1344. | ERTS_RUNQ_FLGS_EVACUATE_QMASK
  1345. | ERTS_RUNQ_FLG_SUSPENDED);
  1346. erts_smp_atomic32_bor(&evac_rq->info_flags, ERTS_RUNQ_IFLG_SUSPENDED);
  1347. /*
  1348. * Need to set up evacuation paths first since we
  1349. * may release the run queue lock on evac_rq
  1350. * when evacuating.
  1351. */
  1352. evac_rq->misc.evac_runq = rq;
  1353. evac_rq->ports.info.migrate.runq = rq;
  1354. for (prio = 0; prio < ERTS_NO_PROC_PRIO_LEVELS; prio++)
  1355. evac_rq->procs.prio_info[prio].migrate.runq = rq;
  1356. /* Evacuate scheduled misc ops */
  1357. if (evac_rq->misc.start) {
  1358. rq_locked = 1;
  1359. erts_smp_xrunq_lock(evac_rq, rq);
  1360. if (rq->misc.end)
  1361. rq->misc.end->next = evac_rq->misc.start;
  1362. else
  1363. rq->misc.start = evac_rq->misc.start;
  1364. rq->misc.end = evac_rq->misc.end;
  1365. evac_rq->misc.start = NULL;
  1366. evac_rq->misc.end = NULL;
  1367. }
  1368. /* Evacuate scheduled ports */
  1369. prt = evac_rq->ports.start;
  1370. while (prt) {
  1371. mres = erts_port_migrate(prt, &prt_locked,
  1372. evac_rq, &evac_rq_locked,
  1373. rq, &rq_locked);
  1374. if (mres == ERTS_MIGRATE_SUCCESS)
  1375. notify_to_rq = 1;
  1376. if (prt_locked)
  1377. erts_smp_port_unlock(prt);
  1378. if (!evac_rq_locked) {
  1379. evac_rq_locked = 1;
  1380. erts_smp_runq_lock(evac_rq);
  1381. }
  1382. prt = evac_rq->ports.start;
  1383. }
  1384. /* Evacuate scheduled processes */
  1385. for (prio = 0; prio < ERTS_NO_PROC_PRIO_LEVELS; prio++) {
  1386. Process *proc;
  1387. switch (prio) {
  1388. case PRIORITY_MAX:
  1389. case PRIORITY_HIGH:
  1390. case PRIORITY_NORMAL:
  1391. proc = evac_rq->procs.prio[prio].first;
  1392. while (proc) {
  1393. ErtsProcLocks proc_locks = 0;
  1394. /* Bound processes are stuck... */
  1395. while (proc->bound_runq) {
  1396. proc = proc->next;
  1397. if (!proc)
  1398. goto end_of_proc;
  1399. }
  1400. mres = erts_proc_migrate(proc, &proc_locks,
  1401. evac_rq, &evac_rq_locked,
  1402. rq, &rq_locked);
  1403. if (mres == ERTS_MIGRATE_SUCCESS)
  1404. notify_to_rq = 1;
  1405. if (proc_locks)
  1406. erts_smp_proc_unlock(proc, proc_locks);
  1407. if (!evac_rq_locked) {
  1408. erts_smp_runq_lock(evac_rq);
  1409. evac_rq_locked = 1;
  1410. }
  1411. proc = evac_rq->procs.prio[prio].first;
  1412. }
  1413. end_of_proc:
  1414. #ifdef DEBUG
  1415. for (proc = evac_rq->procs.prio[prio].first;
  1416. proc;
  1417. proc = proc->next) {
  1418. ASSERT(proc->bound_runq);
  1419. }
  1420. #endif
  1421. break;
  1422. case PRIORITY_LOW:
  1423. break;
  1424. default:
  1425. ASSERT(!"Invalid process priority");
  1426. break;
  1427. }
  1428. }
  1429. if (rq_locked)
  1430. erts_smp_runq_unlock(rq);
  1431. if (evac_rq_locked)
  1432. erts_smp_runq_unlock(evac_rq);
  1433. if (notify_to_rq)
  1434. smp_notify_inc_runq(rq);
  1435. wake_scheduler(evac_rq, 0, 1);
  1436. }
  1437. static int
  1438. try_steal_task_from_victim(ErtsRunQueue *rq, int *rq_lockedp, ErtsRunQueue *vrq)
  1439. {
  1440. Process *proc;
  1441. int vrq_locked;
  1442. if (*rq_lockedp)
  1443. erts_smp_xrunq_lock(rq, vrq);
  1444. else
  1445. erts_smp_runq_lock(vrq);
  1446. vrq_locked = 1;
  1447. ERTS_SMP_LC_CHK_RUNQ_LOCK(rq, *rq_lockedp);
  1448. ERTS_SMP_LC_CHK_RUNQ_LOCK(vrq, vrq_locked);
  1449. /*
  1450. * Check for a runnable process to steal...
  1451. */
  1452. switch (vrq->flags & ERTS_RUNQ_FLGS_PROCS_QMASK) {
  1453. case MAX_BIT:
  1454. case MAX_BIT|HIGH_BIT:
  1455. case MAX_BIT|NORMAL_BIT:
  1456. case MAX_BIT|LOW_BIT:
  1457. case MAX_BIT|HIGH_BIT|NORMAL_BIT:
  1458. case MAX_BIT|HIGH_BIT|LOW_BIT:
  1459. case MAX_BIT|NORMAL_BIT|LOW_BIT:
  1460. case MAX_BIT|HIGH_BIT|NORMAL_BIT|LOW_BIT:
  1461. for (proc = vrq->procs.prio[PRIORITY_MAX].last;
  1462. proc;
  1463. proc = proc->prev) {
  1464. if (!proc->bound_runq)
  1465. break;
  1466. }
  1467. if (proc)
  1468. break;
  1469. case HIGH_BIT:
  1470. case HIGH_BIT|NORMAL_BIT:
  1471. case HIGH_BIT|LOW_BIT:
  1472. case HIGH_BIT|NORMAL_BIT|LOW_BIT:
  1473. for (proc = vrq->procs.prio[PRIORITY_HIGH].last;
  1474. proc;
  1475. proc = proc->prev) {
  1476. if (!proc->bound_runq)
  1477. break;
  1478. }
  1479. if (proc)
  1480. break;
  1481. case NORMAL_BIT:
  1482. case LOW_BIT:
  1483. case NORMAL_BIT|LOW_BIT:
  1484. for (proc = vrq->procs.prio[PRIORITY_NORMAL].last;
  1485. proc;
  1486. proc = proc->prev) {
  1487. if (!proc->bound_runq)
  1488. break;
  1489. }
  1490. if (proc)
  1491. break;
  1492. case 0:
  1493. proc = NULL;
  1494. break;
  1495. default:
  1496. ASSERT(!"Invalid queue mask");
  1497. proc = NULL;
  1498. break;
  1499. }
  1500. if (proc) {
  1501. ErtsProcLocks proc_locks = 0;
  1502. int res;
  1503. ErtsMigrateResult mres;
  1504. mres = erts_proc_migrate(proc, &proc_locks,
  1505. vrq, &vrq_locked,
  1506. rq, rq_lockedp);
  1507. if (proc_locks)
  1508. erts_smp_proc_unlock(proc, proc_locks);
  1509. res = !0;
  1510. switch (mres) {
  1511. case ERTS_MIGRATE_FAILED_RUNQ_SUSPENDED:
  1512. res = 0;
  1513. case ERTS_MIGRATE_SUCCESS:
  1514. if (vrq_locked)
  1515. erts_smp_runq_unlock(vrq);
  1516. return res;
  1517. default: /* Other failures */
  1518. break;
  1519. }
  1520. }
  1521. ERTS_SMP_LC_CHK_RUNQ_LOCK(rq, *rq_lockedp);
  1522. ERTS_SMP_LC_CHK_RUNQ_LOCK(vrq, vrq_locked);
  1523. if (!vrq_locked) {
  1524. if (*rq_lockedp)
  1525. erts_smp_xrunq_lock(rq, vrq);
  1526. else
  1527. erts_smp_runq_lock(vrq);
  1528. vrq_locked = 1;
  1529. }
  1530. ERTS_SMP_LC_CHK_RUNQ_LOCK(rq, *rq_lockedp);
  1531. ERTS_SMP_LC_CHK_RUNQ_LOCK(vrq, vrq_locked);
  1532. /*
  1533. * Check for a runnable port to steal...
  1534. */
  1535. if (vrq->ports.info.len) {
  1536. Port *prt = vrq->ports.end;
  1537. int prt_locked = 0;
  1538. int res;
  1539. ErtsMigrateResult mres;
  1540. mres = erts_port_migrate(prt, &prt_locked,
  1541. vrq, &vrq_locked,
  1542. rq, rq_lockedp);
  1543. if (prt_locked)
  1544. erts_smp_port_unlock(prt);
  1545. res = !0;
  1546. switch (mres) {
  1547. case ERTS_MIGRATE_FAILED_RUNQ_SUSPENDED:
  1548. res = 0;
  1549. case ERTS_MIGRATE_SUCCESS:
  1550. if (vrq_locked)
  1551. erts_smp_runq_unlock(vrq);
  1552. return res;
  1553. default: /* Other failures */
  1554. break;
  1555. }
  1556. }
  1557. if (vrq_locked)
  1558. erts_smp_runq_unlock(vrq);
  1559. return 0;
  1560. }
  1561. static ERTS_INLINE int
  1562. check_possible_steal_victim(ErtsRunQueue *rq, int *rq_lockedp, int vix)
  1563. {
  1564. ErtsRunQueue *vrq = ERTS_RUNQ_IX(vix);
  1565. erts_aint32_t iflgs = erts_smp_atomic32_read(&vrq->info_flags);
  1566. if (iflgs & ERTS_RUNQ_IFLG_NONEMPTY)
  1567. return try_steal_task_from_victim(rq, rq_lockedp, vrq);
  1568. else
  1569. return 0;
  1570. }
  1571. static int
  1572. try_steal_task(ErtsRunQueue *rq)
  1573. {
  1574. int res, rq_locked, vix, active_rqs, blnc_rqs;
  1575. if (erts_common_run_queue)
  1576. return 0;
  1577. /*
  1578. * We are not allowed to steal jobs to this run queue
  1579. * if it is suspended. Note that it might get suspended
  1580. * at any time when we don't have the lock on the run
  1581. * queue.
  1582. */
  1583. if (rq->flags & ERTS_RUNQ_FLG_SUSPENDED)
  1584. return 0;
  1585. res = 0;
  1586. rq_locked = 1;
  1587. ERTS_SMP_LC_CHK_RUNQ_LOCK(rq, rq_locked);
  1588. active_rqs = erts_smp_atomic32_read(&balance_info.active_runqs);
  1589. blnc_rqs = erts_smp_atomic32_read(&balance_info.used_runqs);
  1590. if (active_rqs > blnc_rqs)
  1591. active_rqs = blnc_rqs;
  1592. if (rq->ix < active_rqs) {
  1593. /* First try to steal from an inactive run queue... */
  1594. if (active_rqs < blnc_rqs) {
  1595. int no = blnc_rqs - active_rqs;
  1596. int stop_ix = vix = active_rqs + rq->ix % no;
  1597. while (erts_smp_atomic32_read(&no_empty_run_queues) < blnc_rqs) {
  1598. res = check_possible_steal_victim(rq, &rq_locked, vix);
  1599. if (res)
  1600. goto done;
  1601. vix++;
  1602. if (vix >= blnc_rqs)
  1603. vix = active_rqs;
  1604. if (vix == stop_ix)
  1605. break;
  1606. }
  1607. }
  1608. vix = rq->ix;
  1609. /* ... then try to steal a job from another active queue... */
  1610. while (erts_smp_atomic32_read(&no_empty_run_queues) < blnc_rqs) {
  1611. vix++;
  1612. if (vix >= active_rqs)
  1613. vix = 0;
  1614. if (vix == rq->ix)
  1615. break;
  1616. res = check_possible_steal_victim(rq, &rq_locked, vix);
  1617. if (res)
  1618. goto done;
  1619. }
  1620. }
  1621. done:
  1622. if (!rq_locked)
  1623. erts_smp_runq_lock(rq);
  1624. if (!res)
  1625. res = !ERTS_EMPTY_RUNQ(rq);
  1626. return res;
  1627. }
  1628. /* Run queue balancing */
  1629. typedef struct {
  1630. Uint32 flags;
  1631. struct {
  1632. int max_len;
  1633. int avail;
  1634. int reds;
  1635. int migration_limit;
  1636. int emigrate_to;
  1637. int immigrate_from;
  1638. } prio[ERTS_NO_PRIO_LEVELS];
  1639. int reds;
  1640. int full_reds;
  1641. int full_reds_history_sum;
  1642. int full_reds_history_change;
  1643. int oowc;
  1644. int max_len;
  1645. } ErtsRunQueueBalance;
  1646. static ErtsRunQueueBalance *run_queue_info;
  1647. typedef struct {
  1648. int qix;
  1649. int len;
  1650. } ErtsRunQueueCompare;
  1651. static ErtsRunQueueCompare *run_queue_compare;
  1652. static int
  1653. rqc_len_cmp(const void *x, const void *y)
  1654. {
  1655. return ((ErtsRunQueueCompare *) x)->len - ((ErtsRunQueueCompare *) y)->len;
  1656. }
  1657. #define ERTS_PERCENT(X, Y) \
  1658. ((Y) == 0 \
  1659. ? ((X) == 0 ? 100 : INT_MAX) \
  1660. : ((100*(X))/(Y)))
  1661. #define ERTS_UPDATE_FULL_REDS(QIX, LAST_REDS) \
  1662. do { \
  1663. run_queue_info[(QIX)].full_reds \
  1664. = run_queue_info[(QIX)].full_reds_history_sum; \
  1665. run_queue_info[(QIX)].full_reds += (LAST_REDS); \
  1666. run_queue_info[(QIX)].full_reds \
  1667. >>= ERTS_FULL_REDS_HISTORY_AVG_SHFT; \
  1668. run_queue_info[(QIX)].full_reds_history_sum \
  1669. -= run_queue_info[(QIX)].full_reds_history_change; \
  1670. run_queue_info[(QIX)].full_reds_history_sum += (LAST_REDS); \
  1671. run_queue_info[(QIX)].full_reds_history_change = (LAST_REDS); \
  1672. } while (0)
  1673. #define ERTS_DBG_CHK_FULL_REDS_HISTORY(RQ) \
  1674. do { \
  1675. int sum__ = 0; \
  1676. int rix__; \
  1677. for (rix__ = 0; rix__ < ERTS_FULL_REDS_HISTORY_SIZE; rix__++) \
  1678. sum__ += (RQ)->full_reds_history[rix__]; \
  1679. ASSERT(sum__ == (RQ)->full_reds_history_sum); \
  1680. } while (0);
  1681. static void
  1682. check_balance(ErtsRunQueue *c_rq)
  1683. {
  1684. #if ERTS_MAX_PROCESSES >= (1 << 27)
  1685. # error check_balance() assumes ERTS_MAX_PROCESS < (1 << 27)
  1686. #endif
  1687. ErtsRunQueueBalance avg = {0};
  1688. Sint64 scheds_reds, full_scheds_reds;
  1689. int forced, active, current_active, oowc, half_full_scheds, full_scheds,
  1690. mmax_len, blnc_no_rqs, qix, pix, freds_hist_ix;
  1691. if (erts_smp_atomic32_xchg(&balance_info.checking_balance, 1)) {
  1692. c_rq->check_balance_reds = INT_MAX;
  1693. return;
  1694. }
  1695. blnc_no_rqs = (int) erts_smp_atomic32_read(&balance_info.used_runqs);
  1696. if (blnc_no_rqs == 1) {
  1697. c_rq->check_balance_reds = INT_MAX;
  1698. erts_smp_atomic32_set(&balance_info.checking_balance, 0);
  1699. return;
  1700. }
  1701. erts_smp_runq_unlock(c_rq);
  1702. if (balance_info.halftime) {
  1703. balance_info.halftime = 0;
  1704. erts_smp_atomic32_set(&balance_info.checking_balance, 0);
  1705. ERTS_FOREACH_RUNQ(rq,
  1706. {
  1707. if (rq->waiting)
  1708. rq->flags |= ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK;
  1709. else
  1710. rq->flags &= ~ERTS_RUNQ_FLG_HALFTIME_OUT_OF_WORK;
  1711. rq->check_balance_reds = ERTS_RUNQ_CALL_CHECK_BALANCE_REDS;
  1712. });
  1713. erts_smp_runq_lock(c_rq);
  1714. return;

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