diff options
Diffstat (limited to 'include')
| -rw-r--r-- | include/rv/da_monitor.h | 19 | ||||
| -rw-r--r-- | include/rv/ha_monitor.h | 29 |
2 files changed, 42 insertions, 6 deletions
diff --git a/include/rv/da_monitor.h b/include/rv/da_monitor.h index ec9bc88bd4c4..1f440c7818e6 100644 --- a/include/rv/da_monitor.h +++ b/include/rv/da_monitor.h @@ -58,6 +58,15 @@ static struct rv_monitor rv_this; #endif /* + * Hook to allow the implementation of hybrid automata: define it with a + * function that waits for the termination of all monitors background + * activities (e.g. all timers). This hook can sleep. + */ +#ifndef da_monitor_sync_hook +#define da_monitor_sync_hook() +#endif + +/* * Type for the target id, default to int but can be overridden. * A long type can work as hash table key (PER_OBJ) but will be downgraded to * int in the event tracepoint. @@ -82,7 +91,8 @@ static void react(enum states curr_state, enum events event) static inline void da_monitor_reset_state(struct da_monitor *da_mon) { WRITE_ONCE(da_mon->monitoring, 0); - da_mon->curr_state = model_get_initial_state(); + /* Pair with load in __ha_monitor_timer_callback */ + smp_store_release(&da_mon->curr_state, model_get_initial_state()); } /* @@ -205,6 +215,7 @@ static inline int da_monitor_init(void) static inline void da_monitor_destroy(void) { da_monitor_reset_all(); + da_monitor_sync_hook(); } #elif RV_MON_TYPE == RV_MON_PER_CPU @@ -270,6 +281,7 @@ static inline int da_monitor_init(void) static inline void da_monitor_destroy(void) { da_monitor_reset_all(); + da_monitor_sync_hook(); } #elif RV_MON_TYPE == RV_MON_PER_TASK @@ -367,6 +379,7 @@ static inline void da_monitor_destroy(void) tracepoint_synchronize_unregister(); da_monitor_reset_all(); + da_monitor_sync_hook(); rv_put_task_monitor_slot(task_mon_slot); task_mon_slot = RV_PER_TASK_MONITOR_INIT; @@ -573,13 +586,13 @@ static inline void da_monitor_destroy(void) int bkt; tracepoint_synchronize_unregister(); + da_monitor_reset_all(); + da_monitor_sync_hook(); /* * This function is called after all probes are disabled and no longer * pending, we can safely assume no concurrent user. */ - synchronize_rcu(); hash_for_each_safe(da_monitor_ht, bkt, tmp, mon_storage, node) { - da_monitor_reset_hook(&mon_storage->rv.da_mon); hash_del_rcu(&mon_storage->node); kfree(mon_storage); } diff --git a/include/rv/ha_monitor.h b/include/rv/ha_monitor.h index 4002b5247c46..28d3c74cabfc 100644 --- a/include/rv/ha_monitor.h +++ b/include/rv/ha_monitor.h @@ -37,6 +37,7 @@ static bool ha_monitor_handle_constraint(struct da_monitor *da_mon, #define da_monitor_event_hook ha_monitor_handle_constraint #define da_monitor_init_hook ha_monitor_init_env #define da_monitor_reset_hook ha_monitor_reset_env +#define da_monitor_sync_hook() synchronize_rcu() #if !defined(HA_SKIP_AUTO_CLEANUP) && RV_MON_TYPE == RV_MON_PER_TASK /* @@ -136,10 +137,13 @@ static enum hrtimer_restart ha_monitor_timer_callback(struct hrtimer *hrtimer); #define ha_get_ns() 0 #endif /* HA_CLK_NS */ +static bool ha_mon_destroying; + static int ha_monitor_init(void) { int ret; + WRITE_ONCE(ha_mon_destroying, false); ret = da_monitor_init(); if (ret == 0) ha_monitor_enable_hook(); @@ -148,6 +152,7 @@ static int ha_monitor_init(void) static void ha_monitor_destroy(void) { + WRITE_ONCE(ha_mon_destroying, true); ha_monitor_disable_hook(); da_monitor_destroy(); } @@ -288,12 +293,30 @@ static bool ha_monitor_handle_constraint(struct da_monitor *da_mon, return false; } +/* + * __ha_monitor_timer_callback - generic callback representation + * + * This callback runs in an RCU read-side critical section to allow the + * destruction sequence to easily synchronize_rcu() with all pending timers + * after asynchronously disabling them. The ha_mon_destroying check ensures + * any callback entering the RCU section after synchronize_rcu() completes + * will see the flag and bail out immediately. + */ static inline void __ha_monitor_timer_callback(struct ha_monitor *ha_mon) { - enum states curr_state = READ_ONCE(ha_mon->da_mon.curr_state); DECLARE_SEQ_BUF(env_string, ENV_BUFFER_SIZE); - u64 time_ns = ha_get_ns(); - + enum states curr_state; + u64 time_ns; + + guard(rcu)(); + if (unlikely(READ_ONCE(ha_mon_destroying))) + return; + /* Ensure consistent curr_state if we race with da_monitor_reset */ + curr_state = smp_load_acquire(&ha_mon->da_mon.curr_state); + if (unlikely(!da_monitor_handling_event(&ha_mon->da_mon))) + return; + + time_ns = ha_get_ns(); ha_get_env_string(&env_string, ha_mon, time_ns); ha_react(curr_state, EVENT_NONE, env_string.buffer); ha_trace_error_env(ha_mon, model_get_state_name(curr_state), |
