diff options
Diffstat (limited to 'erts/emulator/beam/erl_process.h')
-rw-r--r-- | erts/emulator/beam/erl_process.h | 274 |
1 files changed, 181 insertions, 93 deletions
diff --git a/erts/emulator/beam/erl_process.h b/erts/emulator/beam/erl_process.h index c7d89d3bb3..7c481a91dd 100644 --- a/erts/emulator/beam/erl_process.h +++ b/erts/emulator/beam/erl_process.h @@ -1,7 +1,7 @@ /* * %CopyrightBegin% * - * Copyright Ericsson AB 1996-2011. All Rights Reserved. + * Copyright Ericsson AB 1996-2012. All Rights Reserved. * * The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in @@ -53,11 +53,18 @@ typedef struct process Process; #include "erl_time.h" #include "erl_atom_table.h" #include "external.h" +#include "erl_mseg.h" +#include "erl_async.h" #ifdef HIPE #include "hipe_process.h" #endif +#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY +#define ERL_THR_PROGRESS_TSD_TYPE_ONLY +#include "erl_thr_progress.h" +#undef ERL_THR_PROGRESS_TSD_TYPE_ONLY + struct ErtsNodesMonitor_; struct port; @@ -137,12 +144,10 @@ extern int erts_sched_thread_suggested_stack_size; (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 1)) #define ERTS_RUNQ_FLG_SUSPENDED \ (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 2)) -#define ERTS_RUNQ_FLG_SHARED_RUNQ \ - (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 3)) #define ERTS_RUNQ_FLG_CHK_CPU_BIND \ - (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 4)) + (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 3)) #define ERTS_RUNQ_FLG_INACTIVE \ - (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 5)) + (((Uint32) 1) << (ERTS_RUNQ_FLG_BASE2 + 4)) #define ERTS_RUNQ_FLGS_MIGRATION_QMASKS \ (ERTS_RUNQ_FLGS_EMIGRATE_QMASK \ @@ -243,30 +248,35 @@ typedef enum { | ERTS_SSI_FLG_WAITING \ | ERTS_SSI_FLG_SUSPENDED) -#define ERTS_SCHED_NEED_BLOCKABLE_AUX_WORK - -#define ERTS_SSI_AUX_WORK_CHECK_CHILDREN (((erts_aint32_t) 1) << 0) -#define ERTS_SSI_AUX_WORK_MISC (((erts_aint32_t) 1) << 1) +/* + * Keep ERTS_SSI_AUX_WORK flags in expected frequency order relative + * eachother. Most frequent - lowest bit number. + */ -#define ERTS_SSI_BLOCKABLE_AUX_WORK_MASK \ - (ERTS_SSI_AUX_WORK_CHECK_CHILDREN \ - | ERTS_SSI_AUX_WORK_MISC) -#define ERTS_SSI_NONBLOCKABLE_AUX_WORK_MASK \ - (0) +#define ERTS_SSI_AUX_WORK_DELAYED_AW_WAKEUP (((erts_aint32_t) 1) << 0) +#define ERTS_SSI_AUX_WORK_DD (((erts_aint32_t) 1) << 1) +#define ERTS_SSI_AUX_WORK_DD_THR_PRGR (((erts_aint32_t) 1) << 2) +#define ERTS_SSI_AUX_WORK_FIX_ALLOC_DEALLOC (((erts_aint32_t) 1) << 3) +#define ERTS_SSI_AUX_WORK_FIX_ALLOC_LOWER_LIM (((erts_aint32_t) 1) << 4) +#define ERTS_SSI_AUX_WORK_ASYNC_READY (((erts_aint32_t) 1) << 5) +#define ERTS_SSI_AUX_WORK_ASYNC_READY_CLEAN (((erts_aint32_t) 1) << 6) +#define ERTS_SSI_AUX_WORK_MISC_THR_PRGR (((erts_aint32_t) 1) << 7) +#define ERTS_SSI_AUX_WORK_MISC (((erts_aint32_t) 1) << 8) +#define ERTS_SSI_AUX_WORK_CHECK_CHILDREN (((erts_aint32_t) 1) << 9) +#define ERTS_SSI_AUX_WORK_SET_TMO (((erts_aint32_t) 1) << 10) +#define ERTS_SSI_AUX_WORK_MSEG_CACHE_CHECK (((erts_aint32_t) 1) << 11) +#define ERTS_SSI_AUX_WORK_REAP_PORTS (((erts_aint32_t) 1) << 12) typedef struct ErtsSchedulerSleepInfo_ ErtsSchedulerSleepInfo; -typedef struct { - erts_smp_spinlock_t lock; - ErtsSchedulerSleepInfo *list; -} ErtsSchedulerSleepList; - struct ErtsSchedulerSleepInfo_ { +#ifdef ERTS_SMP ErtsSchedulerSleepInfo *next; ErtsSchedulerSleepInfo *prev; erts_smp_atomic32_t flags; erts_tse_t *event; - erts_smp_atomic32_t aux_work; +#endif + erts_atomic32_t aux_work; }; /* times to reschedule low prio process before running */ @@ -321,10 +331,6 @@ struct ErtsRunQueue_ { erts_smp_mtx_t mtx; erts_smp_cnd_t cnd; -#ifdef ERTS_SMP - ErtsSchedulerSleepList sleepers; -#endif - ErtsSchedulerData *scheduler; int waiting; /* < 0 in sys schedule; > 0 on cnd variable */ int woken; @@ -337,6 +343,7 @@ struct ErtsRunQueue_ { int len; int wakeup_other; int wakeup_other_reds; + int halt_in_progress; struct { int len; @@ -370,7 +377,6 @@ typedef union { } ErtsAlignedRunQueue; extern ErtsAlignedRunQueue *erts_aligned_run_queues; -extern ErtsRunQueue *erts_common_run_queue; #define ERTS_PROC_REDUCTIONS_EXECUTED(RQ, PRIO, REDS, AREDS) \ do { \ @@ -387,25 +393,75 @@ do { \ (RQ)->wakeup_other_reds += (REDS); \ } while (0) -struct ErtsSchedulerData_ { +typedef struct { + int enabled; + Uint64 start; + struct { + Uint64 total; + Uint64 start; + int currently; + } working; +} ErtsSchedWallTime; + +typedef struct { + int sched; + erts_aint32_t aux_work; +} ErtsDelayedAuxWorkWakeupJob; +typedef struct { + int sched_id; + ErtsSchedulerData *esdp; + ErtsSchedulerSleepInfo *ssi; #ifdef ERTS_SMP + ErtsThrPrgrVal current_thr_prgr; +#endif + struct { + int ix; +#ifdef ERTS_SMP + ErtsThrPrgrVal thr_prgr; +#endif + } misc; +#ifdef ERTS_SMP + struct { + ErtsThrPrgrVal thr_prgr; + void (*completed_callback)(void *); + void (*completed_arg)(void *); + } dd; +#endif +#ifdef ERTS_USE_ASYNC_READY_Q + struct { +#ifdef ERTS_SMP + int need_thr_prgr; + ErtsThrPrgrVal thr_prgr; +#endif + void *queue; + } async_ready; +#endif +#ifdef ERTS_SMP + struct { + Uint64 next; + int *sched2jix; + int jix; + ErtsDelayedAuxWorkWakeupJob *job; + } delayed_wakeup; +#endif +} ErtsAuxWorkData; + +struct ErtsSchedulerData_ { /* * Keep X registers first (so we get as many low * numbered registers as possible in the same cache * line). */ -#if !HALFWORD_HEAP - Eterm save_reg[ERTS_X_REGS_ALLOCATED]; /* X registers */ -#else - Eterm *save_reg; -#endif - FloatDef freg[MAX_REG]; /* Floating point registers. */ + Eterm* x_reg_array; /* X registers */ + FloatDef* f_reg_array; /* Floating point registers. */ + +#ifdef ERTS_SMP ethr_tid tid; /* Thread id */ struct erl_bits_state erl_bits_state; /* erl_bits.c state */ void *match_pseudo_process; /* erl_db_util.c:db_prog_match() */ - ErtsSchedulerSleepInfo *ssi; Process *free_process; + ErtsThrPrgrData thr_progress_data; #endif #if !HEAP_ON_C_STACK Eterm tmp_heap[TMP_HEAP_SIZE]; @@ -414,20 +470,20 @@ struct ErtsSchedulerData_ { Eterm cmp_tmp_heap[CMP_TMP_HEAP_SIZE]; Eterm erl_arith_tmp_heap[ERL_ARITH_TMP_HEAP_SIZE]; #endif - + ErtsSchedulerSleepInfo *ssi; Process *current_process; Uint no; /* Scheduler number */ struct port *current_port; ErtsRunQueue *run_queue; int virtual_reds; int cpu_id; /* >= 0 when bound */ - + ErtsAuxWorkData aux_work_data; ErtsAtomCacheMap atom_cache_map; -#ifdef ERTS_SMP - /* NOTE: These fields are modified under held mutexes by other threads */ - erts_smp_atomic32_t chk_cpu_bind; /* Only used when common run queue */ -#endif + ErtsSchedAllocData alloc_data; + + Uint64 reductions; + ErtsSchedWallTime sched_wall_time; #ifdef ERTS_DO_VERIFY_UNUSED_TEMP_ALLOC erts_alloc_verify_func_t verify_unused_temp_alloc; @@ -573,7 +629,7 @@ struct process { Uint min_heap_size; /* Minimum size of heap (in words). */ Uint min_vheap_size; /* Minimum size of virtual heap (in words). */ -#if !defined(NO_FPE_SIGNALS) +#if !defined(NO_FPE_SIGNALS) || defined(HIPE) volatile unsigned long fp_exception; #endif @@ -641,6 +697,10 @@ struct process { Uint seq_trace_lastcnt; Eterm seq_trace_token; /* Sequential trace token (tuple size 5 see below) */ +#ifdef USE_VM_PROBES + Eterm dt_utag; /* Place to store the dynamc trace user tag */ + Uint dt_utag_flags; /* flag field for the dt_utag */ +#endif BeamInstr initial[3]; /* Initial module(0), function(1), arity(2), often used instead of pointer to funcinfo instruction, hence the BeamInstr datatype */ BeamInstr* current; /* Current Erlang function, part of the funcinfo: @@ -703,24 +763,6 @@ struct process { #endif #endif -#ifdef HYBRID - Eterm *rrma; /* Remembered roots to Message Area */ - Eterm **rrsrc; /* The source of the root */ - Uint nrr; /* Number of remembered roots */ - Uint rrsz; /* Size of root array */ -#endif - -#ifdef HYBRID - Uint active; /* Active since last major collection? */ - Uint active_index; /* Index in the active process array */ -#endif - -#ifdef INCREMENTAL - Process *active_next; /* Active processes to scan for roots */ - Process *active_prev; /* in collection of the message area */ - Eterm *scan_top; -#endif - #ifdef CHECK_FOR_HOLES Eterm* last_htop; /* No need to scan the heap below this point. */ ErlHeapFragment* last_mbuf; /* No need to scan beyond this mbuf. */ @@ -842,10 +884,6 @@ Eterm* erts_set_hole_marker(Eterm* ptr, Uint sz); #endif extern Process** process_tab; -#ifdef HYBRID -extern Uint erts_num_active_procs; -extern Process** erts_active_procs; -#endif extern Uint erts_max_processes; extern Uint erts_process_tab_index_mask; extern Uint erts_default_process_flags; @@ -956,6 +994,14 @@ extern struct erts_system_profile_flags_t erts_system_profile_flags; #define SEQ_TRACE_PRINT (1 << 2) #define SEQ_TRACE_TIMESTAMP (1 << 3) +#ifdef USE_VM_PROBES +#define DT_UTAG_PERMANENT (1 << 0) +#define DT_UTAG_SPREADING (1 << 1) +#define DT_UTAG(P) ((P)->dt_utag) +#define DT_UTAG_FLAGS(P) ((P)->dt_utag_flags) +#endif + + #ifdef ERTS_SMP /* Status flags ... */ #define ERTS_PROC_SFLG_PENDADD2SCHEDQ (((Uint32) 1) << 0) /* Pending @@ -1033,15 +1079,22 @@ extern struct erts_system_profile_flags_t erts_system_profile_flags; void erts_pre_init_process(void); void erts_late_init_process(void); -void erts_early_init_scheduling(void); -void erts_init_scheduling(int, int, int); +void erts_early_init_scheduling(int); +void erts_init_scheduling(int, int); + +Eterm erts_sched_wall_time_request(Process *c_p, int set, int enable); ErtsProcList *erts_proclist_create(Process *); void erts_proclist_destroy(ErtsProcList *); int erts_proclist_same(ErtsProcList *, Process *); -int erts_sched_set_wakeup_limit(char *str); +int erts_sched_set_wakeup_other_thresold(char *str); +int erts_sched_set_wakeup_other_type(char *str); +int erts_sched_set_busy_wait_threshold(char *str); +#if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) +int erts_dbg_check_halloc_lock(Process *p); +#endif #ifdef DEBUG void erts_dbg_multi_scheduling_return_trap(Process *, Eterm); #endif @@ -1059,13 +1112,20 @@ erts_block_multi_scheduling(Process *, ErtsProcLocks, int, int); int erts_is_multi_scheduling_blocked(void); Eterm erts_multi_scheduling_blockers(Process *); void erts_start_schedulers(void); +void erts_alloc_notify_delayed_dealloc(int); void erts_smp_notify_check_children_needed(void); -void -erts_smp_schedule_misc_aux_work(int ignore_self, - int max_sched, - void (*func)(void *), - void *arg); #endif +#if ERTS_USE_ASYNC_READY_Q +void erts_notify_check_async_ready_queue(void *); +#endif +void erts_schedule_misc_aux_work(int sched_id, + void (*func)(void *), + void *arg); +void erts_schedule_multi_misc_aux_work(int ignore_self, + int max_sched, + void (*func)(void *), + void *arg); +erts_aint32_t erts_set_aux_work_timeout(int, erts_aint32_t, int); void erts_sched_notify_check_cpu_bind(void); Uint erts_active_schedulers(void); void erts_init_process(int); @@ -1149,6 +1209,7 @@ Sint erts_test_next_pid(int, Uint); Eterm erts_debug_processes(Process *c_p); Eterm erts_debug_processes_bif_info(Process *c_p); Uint erts_debug_nbalance(void); +int erts_debug_wait_deallocations(Process *c_p); #ifdef ERTS_SMP # define ERTS_GET_SCHEDULER_DATA_FROM_PROC(PROC) ((PROC)->scheduler_data) @@ -1219,16 +1280,11 @@ erts_psd_get(Process *p, int ix) #if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) ErtsProcLocks locks = erts_proc_lc_my_proc_locks(p); if (ERTS_LC_PSD_ANY_LOCK == erts_psd_required_locks[ix].get_locks) - ERTS_SMP_LC_ASSERT(locks - || erts_is_system_blocked(0) - || (ERTS_IS_CRASH_DUMPING - && erts_is_system_blocked(ERTS_BS_FLG_ALLOW_GC))); + ERTS_SMP_LC_ASSERT(locks || erts_thr_progress_is_blocking()); else { locks &= erts_psd_required_locks[ix].get_locks; ERTS_SMP_LC_ASSERT(erts_psd_required_locks[ix].get_locks == locks - || erts_is_system_blocked(0) - || (ERTS_IS_CRASH_DUMPING - && erts_is_system_blocked(ERTS_BS_FLG_ALLOW_GC))); + || erts_thr_progress_is_blocking()); } #endif ASSERT(0 <= ix && ix < ERTS_PSD_SIZE); @@ -1245,16 +1301,11 @@ erts_psd_set(Process *p, ErtsProcLocks plocks, int ix, void *data) #if defined(ERTS_SMP) && defined(ERTS_ENABLE_LOCK_CHECK) ErtsProcLocks locks = erts_proc_lc_my_proc_locks(p); if (ERTS_LC_PSD_ANY_LOCK == erts_psd_required_locks[ix].set_locks) - ERTS_SMP_LC_ASSERT(locks - || erts_is_system_blocked(0) - || (ERTS_IS_CRASH_DUMPING - && erts_is_system_blocked(ERTS_BS_FLG_ALLOW_GC))); + ERTS_SMP_LC_ASSERT(locks || erts_thr_progress_is_blocking()); else { locks &= erts_psd_required_locks[ix].set_locks; ERTS_SMP_LC_ASSERT(erts_psd_required_locks[ix].set_locks == locks - || erts_is_system_blocked(0) - || (ERTS_IS_CRASH_DUMPING - && erts_is_system_blocked(ERTS_BS_FLG_ALLOW_GC))); + || erts_thr_progress_is_blocking()); } #endif ASSERT(0 <= ix && ix < ERTS_PSD_SIZE); @@ -1343,10 +1394,14 @@ ERTS_GLB_INLINE Eterm erts_get_current_pid(void); ERTS_GLB_INLINE Uint erts_get_scheduler_id(void); ERTS_GLB_INLINE ErtsRunQueue *erts_get_runq_proc(Process *p); ERTS_GLB_INLINE ErtsRunQueue *erts_get_runq_current(ErtsSchedulerData *esdp); +#ifndef ERTS_ENABLE_LOCK_COUNT ERTS_GLB_INLINE void erts_smp_runq_lock(ErtsRunQueue *rq); +#endif ERTS_GLB_INLINE int erts_smp_runq_trylock(ErtsRunQueue *rq); ERTS_GLB_INLINE void erts_smp_runq_unlock(ErtsRunQueue *rq); +#ifndef ERTS_ENABLE_LOCK_COUNT ERTS_GLB_INLINE void erts_smp_xrunq_lock(ErtsRunQueue *rq, ErtsRunQueue *xrq); +#endif ERTS_GLB_INLINE void erts_smp_xrunq_unlock(ErtsRunQueue *rq, ErtsRunQueue *xrq); ERTS_GLB_INLINE void erts_smp_runqs_lock(ErtsRunQueue *rq1, ErtsRunQueue *rq2); ERTS_GLB_INLINE void erts_smp_runqs_unlock(ErtsRunQueue *rq1, ErtsRunQueue *rq2); @@ -1418,8 +1473,7 @@ erts_get_runq_proc(Process *p) ASSERT(p->run_queue); return p->run_queue; #else - ASSERT(erts_common_run_queue); - return erts_common_run_queue; + return ERTS_RUNQ_IX(0); #endif } @@ -1432,11 +1486,16 @@ erts_get_runq_current(ErtsSchedulerData *esdp) esdp = erts_get_scheduler_data(); return esdp->run_queue; #else - ASSERT(erts_common_run_queue); - return erts_common_run_queue; + return ERTS_RUNQ_IX(0); #endif } +#ifdef ERTS_ENABLE_LOCK_COUNT + +#define erts_smp_runq_lock(rq) erts_smp_mtx_lock_x(&(rq)->mtx, __FILE__, __LINE__) + +#else + ERTS_GLB_INLINE void erts_smp_runq_lock(ErtsRunQueue *rq) { @@ -1445,6 +1504,8 @@ erts_smp_runq_lock(ErtsRunQueue *rq) #endif } +#endif + ERTS_GLB_INLINE int erts_smp_runq_trylock(ErtsRunQueue *rq) { @@ -1463,6 +1524,31 @@ erts_smp_runq_unlock(ErtsRunQueue *rq) #endif } +#ifdef ERTS_ENABLE_LOCK_COUNT + +#define erts_smp_xrunq_lock(rq, xrq) erts_smp_xrunq_lock_x((rq), (xrq), __FILE__, __LINE__) + +ERTS_GLB_INLINE void +erts_smp_xrunq_lock_x(ErtsRunQueue *rq, ErtsRunQueue *xrq, char* file, int line) +{ +#ifdef ERTS_SMP + ERTS_SMP_LC_ASSERT(erts_smp_lc_mtx_is_locked(&rq->mtx)); + if (xrq != rq) { + if (erts_smp_mtx_trylock(&xrq->mtx) == EBUSY) { + if (rq < xrq) + erts_smp_mtx_lock_x(&xrq->mtx, file, line); + else { + erts_smp_mtx_unlock(&rq->mtx); + erts_smp_mtx_lock_x(&xrq->mtx, file, line); + erts_smp_mtx_lock_x(&rq->mtx, file, line); + } + } + } +#endif +} + +#else + ERTS_GLB_INLINE void erts_smp_xrunq_lock(ErtsRunQueue *rq, ErtsRunQueue *xrq) { @@ -1482,6 +1568,8 @@ erts_smp_xrunq_lock(ErtsRunQueue *rq, ErtsRunQueue *xrq) #endif } +#endif + ERTS_GLB_INLINE void erts_smp_xrunq_unlock(ErtsRunQueue *rq, ErtsRunQueue *xrq) { @@ -1600,11 +1688,9 @@ erts_sched_poke(ErtsSchedulerSleepInfo *ssi) { erts_aint32_t flags; ERTS_THR_MEMORY_BARRIER; - flags = erts_smp_atomic32_read(&ssi->flags); - ASSERT(!(flags & ERTS_SSI_FLG_SLEEPING) - || (flags & ERTS_SSI_FLG_WAITING)); + flags = erts_smp_atomic32_read_nob(&ssi->flags); if (flags & ERTS_SSI_FLG_SLEEPING) { - flags = erts_smp_atomic32_band(&ssi->flags, ~ERTS_SSI_FLGS_SLEEP); + flags = erts_smp_atomic32_read_band_nob(&ssi->flags, ~ERTS_SSI_FLGS_SLEEP); erts_sched_finish_poke(ssi, flags); } } @@ -1620,4 +1706,6 @@ erts_sched_poke(ErtsSchedulerSleepInfo *ssi) #endif - +void erl_halt(int code); +extern erts_smp_atomic32_t erts_halt_progress; +extern int erts_halt_code; |