#ifndef _RV_DA_MONITOR_H
#define _RV_DA_MONITOR_H
#include <rv/automata.h>
#include <linux/rv.h>
#include <linux/stringify.h>
#include <linux/bug.h>
#include <linux/sched.h>
static struct rv_monitor rv_this;
static void react(enum states curr_state, enum events event)
{
rv_react(&rv_this,
"rv: monitor %s does not allow event %s on state %s\n",
__stringify(MONITOR_NAME),
model_get_event_name(event),
model_get_state_name(curr_state));
}
static inline void da_monitor_reset(struct da_monitor *da_mon)
{
da_mon->monitoring = 0;
da_mon->curr_state = model_get_initial_state();
}
static inline void da_monitor_start(struct da_monitor *da_mon)
{
da_mon->curr_state = model_get_initial_state();
da_mon->monitoring = 1;
}
static inline bool da_monitoring(struct da_monitor *da_mon)
{
return da_mon->monitoring;
}
static inline bool da_monitor_enabled(void)
{
if (unlikely(!rv_monitoring_on()))
return 0;
if (unlikely(!rv_this.enabled))
return 0;
return 1;
}
static inline bool da_monitor_handling_event(struct da_monitor *da_mon)
{
if (!da_monitor_enabled())
return 0;
if (unlikely(!da_monitoring(da_mon)))
return 0;
return 1;
}
#if RV_MON_TYPE == RV_MON_GLOBAL || RV_MON_TYPE == RV_MON_PER_CPU
static inline bool da_event(struct da_monitor *da_mon, enum events event)
{
enum states curr_state, next_state;
curr_state = READ_ONCE(da_mon->curr_state);
for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) {
next_state = model_get_next_state(curr_state, event);
if (next_state == INVALID_STATE) {
react(curr_state, event);
CONCATENATE(trace_error_, MONITOR_NAME)(
model_get_state_name(curr_state),
model_get_event_name(event));
return false;
}
if (likely(try_cmpxchg(&da_mon->curr_state, &curr_state, next_state))) {
CONCATENATE(trace_event_, MONITOR_NAME)(
model_get_state_name(curr_state),
model_get_event_name(event),
model_get_state_name(next_state),
model_is_final_state(next_state));
return true;
}
}
trace_rv_retries_error(__stringify(MONITOR_NAME), model_get_event_name(event));
pr_warn("rv: " __stringify(MAX_DA_RETRY_RACING_EVENTS)
" retries reached for event %s, resetting monitor %s",
model_get_event_name(event), __stringify(MONITOR_NAME));
return false;
}
#elif RV_MON_TYPE == RV_MON_PER_TASK
static inline bool da_event(struct da_monitor *da_mon, struct task_struct *tsk,
enum events event)
{
enum states curr_state, next_state;
curr_state = READ_ONCE(da_mon->curr_state);
for (int i = 0; i < MAX_DA_RETRY_RACING_EVENTS; i++) {
next_state = model_get_next_state(curr_state, event);
if (next_state == INVALID_STATE) {
react(curr_state, event);
CONCATENATE(trace_error_, MONITOR_NAME)(tsk->pid,
model_get_state_name(curr_state),
model_get_event_name(event));
return false;
}
if (likely(try_cmpxchg(&da_mon->curr_state, &curr_state, next_state))) {
CONCATENATE(trace_event_, MONITOR_NAME)(tsk->pid,
model_get_state_name(curr_state),
model_get_event_name(event),
model_get_state_name(next_state),
model_is_final_state(next_state));
return true;
}
}
trace_rv_retries_error(__stringify(MONITOR_NAME), model_get_event_name(event));
pr_warn("rv: " __stringify(MAX_DA_RETRY_RACING_EVENTS)
" retries reached for event %s, resetting monitor %s",
model_get_event_name(event), __stringify(MONITOR_NAME));
return false;
}
#endif
#if RV_MON_TYPE == RV_MON_GLOBAL
static struct da_monitor da_mon_this;
static struct da_monitor *da_get_monitor(void)
{
return &da_mon_this;
}
static void da_monitor_reset_all(void)
{
da_monitor_reset(da_get_monitor());
}
static inline int da_monitor_init(void)
{
da_monitor_reset_all();
return 0;
}
static inline void da_monitor_destroy(void) { }
#elif RV_MON_TYPE == RV_MON_PER_CPU
static DEFINE_PER_CPU(struct da_monitor, da_mon_this);
static struct da_monitor *da_get_monitor(void)
{
return this_cpu_ptr(&da_mon_this);
}
static void da_monitor_reset_all(void)
{
struct da_monitor *da_mon;
int cpu;
for_each_cpu(cpu, cpu_online_mask) {
da_mon = per_cpu_ptr(&da_mon_this, cpu);
da_monitor_reset(da_mon);
}
}
static inline int da_monitor_init(void)
{
da_monitor_reset_all();
return 0;
}
static inline void da_monitor_destroy(void) { }
#elif RV_MON_TYPE == RV_MON_PER_TASK
static int task_mon_slot = RV_PER_TASK_MONITOR_INIT;
static inline struct da_monitor *da_get_monitor(struct task_struct *tsk)
{
return &tsk->rv[task_mon_slot].da_mon;
}
static void da_monitor_reset_all(void)
{
struct task_struct *g, *p;
int cpu;
read_lock(&tasklist_lock);
for_each_process_thread(g, p)
da_monitor_reset(da_get_monitor(p));
for_each_present_cpu(cpu)
da_monitor_reset(da_get_monitor(idle_task(cpu)));
read_unlock(&tasklist_lock);
}
static int da_monitor_init(void)
{
int slot;
slot = rv_get_task_monitor_slot();
if (slot < 0 || slot >= RV_PER_TASK_MONITOR_INIT)
return slot;
task_mon_slot = slot;
da_monitor_reset_all();
return 0;
}
static inline void da_monitor_destroy(void)
{
if (task_mon_slot == RV_PER_TASK_MONITOR_INIT) {
WARN_ONCE(1, "Disabling a disabled monitor: " __stringify(MONITOR_NAME));
return;
}
rv_put_task_monitor_slot(task_mon_slot);
task_mon_slot = RV_PER_TASK_MONITOR_INIT;
}
#endif
#if RV_MON_TYPE == RV_MON_GLOBAL || RV_MON_TYPE == RV_MON_PER_CPU
static inline void __da_handle_event(struct da_monitor *da_mon,
enum events event)
{
bool retval;
retval = da_event(da_mon, event);
if (!retval)
da_monitor_reset(da_mon);
}
static inline void da_handle_event(enum events event)
{
struct da_monitor *da_mon = da_get_monitor();
bool retval;
retval = da_monitor_handling_event(da_mon);
if (!retval)
return;
__da_handle_event(da_mon, event);
}
static inline bool da_handle_start_event(enum events event)
{
struct da_monitor *da_mon;
if (!da_monitor_enabled())
return 0;
da_mon = da_get_monitor();
if (unlikely(!da_monitoring(da_mon))) {
da_monitor_start(da_mon);
return 0;
}
__da_handle_event(da_mon, event);
return 1;
}
static inline bool da_handle_start_run_event(enum events event)
{
struct da_monitor *da_mon;
if (!da_monitor_enabled())
return 0;
da_mon = da_get_monitor();
if (unlikely(!da_monitoring(da_mon)))
da_monitor_start(da_mon);
__da_handle_event(da_mon, event);
return 1;
}
#elif RV_MON_TYPE == RV_MON_PER_TASK
static inline void __da_handle_event(struct da_monitor *da_mon,
struct task_struct *tsk, enum events event)
{
bool retval;
retval = da_event(da_mon, tsk, event);
if (!retval)
da_monitor_reset(da_mon);
}
static inline void da_handle_event(struct task_struct *tsk, enum events event)
{
struct da_monitor *da_mon = da_get_monitor(tsk);
bool retval;
retval = da_monitor_handling_event(da_mon);
if (!retval)
return;
__da_handle_event(da_mon, tsk, event);
}
static inline bool da_handle_start_event(struct task_struct *tsk,
enum events event)
{
struct da_monitor *da_mon;
if (!da_monitor_enabled())
return 0;
da_mon = da_get_monitor(tsk);
if (unlikely(!da_monitoring(da_mon))) {
da_monitor_start(da_mon);
return 0;
}
__da_handle_event(da_mon, tsk, event);
return 1;
}
static inline bool da_handle_start_run_event(struct task_struct *tsk,
enum events event)
{
struct da_monitor *da_mon;
if (!da_monitor_enabled())
return 0;
da_mon = da_get_monitor(tsk);
if (unlikely(!da_monitoring(da_mon)))
da_monitor_start(da_mon);
__da_handle_event(da_mon, tsk, event);
return 1;
}
#endif
#endif