@@ -39,16 +39,18 @@ below::
3939RV monitor synthesis
4040--------------------
4141
42- The synthesis of automata-based models into the Linux *RV monitor * abstraction
43- is automated by the rvgen tool and the rv/da_monitor.h header file that
44- contains a set of macros that automatically generate the monitor's code.
42+ The synthesis of a specification into the Linux *RV monitor * abstraction is
43+ automated by the rvgen tool and the header file containing common code for
44+ creating monitors. The header files are:
45+
46+ * rv/da_monitor.h for deterministic automaton monitor.
47+ * rv/ltl_monitor.h for linear temporal logic monitor.
4548
4649rvgen
4750-----
4851
49- The rvgen utility leverages dot2c by converting an automaton model in
50- the DOT format into the C representation [1] and creating the skeleton of
51- a kernel monitor in C.
52+ The rvgen utility converts a specification into the C presentation and creating
53+ the skeleton of a kernel monitor in C.
5254
5355For example, it is possible to transform the wip.dot model present in
5456[1] into a per-cpu monitor with the following command::
@@ -63,18 +65,38 @@ This will create a directory named wip/ with the following files:
6365The wip.c file contains the monitor declaration and the starting point for
6466the system instrumentation.
6567
66- Monitor macros
67- --------------
68+ Similarly, a linear temporal logic monitor can be generated with the following
69+ command::
70+
71+ $ rvgen monitor -c ltl -s pagefault.ltl -t per_task
72+
73+ This generates pagefault/ directory with:
74+
75+ - pagefault.h: The Buchi automaton (the non-deterministic state machine to
76+ verify the specification)
77+ - pagefault.c: The skeleton for the RV monitor
78+
79+ Monitor header files
80+ --------------------
81+
82+ The header files:
83+
84+ - `rv/da_monitor.h ` for deterministic automaton monitor
85+ - `rv/ltl_monitor ` for linear temporal logic monitor
86+
87+ include common macros and static functions for implementing *Monitor
88+ Instance(s) *.
6889
69- The rv/da_monitor.h enables automatic code generation for the * Monitor
70- Instance(s) * using C macros.
90+ The benefits of having all common functionalities in a single header file are
91+ 3-fold:
7192
72- The benefits of the usage of macro for monitor synthesis are 3-fold as it:
93+ - Reduce the code duplication;
94+ - Facilitate the bug fix/improvement;
95+ - Avoid the case of developers changing the core of the monitor code to
96+ manipulate the model in a (let's say) non-standard way.
7397
74- - Reduces the code duplication;
75- - Facilitates the bug fix/improvement;
76- - Avoids the case of developers changing the core of the monitor code
77- to manipulate the model in a (let's say) non-standard way.
98+ rv/da_monitor.h
99+ +++++++++++++++
78100
79101This initial implementation presents three different types of monitor instances:
80102
@@ -130,10 +152,112 @@ While the event "preempt_enabled" will use::
130152To notify the monitor that the system will be returning to the initial state,
131153so the system and the monitor should be in sync.
132154
155+ rv/ltl_monitor.h
156+ ++++++++++++++++
157+ This file must be combined with the $(MODEL_NAME).h file (generated by `rvgen `)
158+ to be complete. For example, for the `pagefault ` monitor, the `pagefault.c `
159+ source file must include::
160+
161+ #include "pagefault.h"
162+ #include <rv/ltl_monitor.h>
163+
164+ (the skeleton monitor file generated by `rvgen ` already does this).
165+
166+ `$(MODEL_NAME).h ` (`pagefault.h ` in the above example) includes the
167+ implementation of the Buchi automaton - a non-deterministic state machine that
168+ verifies the LTL specification. While `rv/ltl_monitor.h ` includes the common
169+ helper functions to interact with the Buchi automaton and to implement an RV
170+ monitor. An important definition in `$(MODEL_NAME).h ` is::
171+
172+ enum ltl_atom {
173+ LTL_$(FIRST_ATOMIC_PROPOSITION),
174+ LTL_$(SECOND_ATOMIC_PROPOSITION),
175+ ...
176+ LTL_NUM_ATOM
177+ };
178+
179+ which is the list of atomic propositions present in the LTL specification
180+ (prefixed with "LTL\_ " to avoid name collision). This `enum ` is passed to the
181+ functions interacting with the Buchi automaton.
182+
183+ While generating code, `rvgen ` cannot understand the meaning of the atomic
184+ propositions. Thus, that task is left for manual work. The recommended pratice
185+ is adding tracepoints to places where the atomic propositions change; and in the
186+ tracepoints' handlers: the Buchi automaton is executed using::
187+
188+ void ltl_atom_update(struct task_struct *task, enum ltl_atom atom, bool value)
189+
190+ which tells the Buchi automaton that the atomic proposition `atom ` is now
191+ `value `. The Buchi automaton checks whether the LTL specification is still
192+ satisfied, and invokes the monitor's error tracepoint and the reactor if
193+ violation is detected.
194+
195+ Tracepoints and `ltl_atom_update() ` should be used whenever possible. However,
196+ it is sometimes not the most convenient. For some atomic propositions which are
197+ changed in multiple places in the kernel, it is cumbersome to trace all those
198+ places. Furthermore, it may not be important that the atomic propositions are
199+ updated at precise times. For example, considering the following linear temporal
200+ logic::
201+
202+ RULE = always (RT imply not PAGEFAULT)
203+
204+ This LTL states that a real-time task does not raise page faults. For this
205+ specification, it is not important when `RT ` changes, as long as it has the
206+ correct value when `PAGEFAULT ` is true. Motivated by this case, another
207+ function is introduced::
208+
209+ void ltl_atom_fetch(struct task_struct *task, struct ltl_monitor *mon)
210+
211+ This function is called whenever the Buchi automaton is triggered. Therefore, it
212+ can be manually implemented to "fetch" `RT `::
213+
214+ void ltl_atom_fetch(struct task_struct *task, struct ltl_monitor *mon)
215+ {
216+ ltl_atom_set(mon, LTL_RT, rt_task(task));
217+ }
218+
219+ Effectively, whenever `PAGEFAULT ` is updated with a call to `ltl_atom_update() `,
220+ `RT ` is also fetched. Thus, the LTL specification can be verified without
221+ tracing `RT ` everywhere.
222+
223+ For atomic propositions which act like events, they usually need to be set (or
224+ cleared) and then immediately cleared (or set). A convenient function is
225+ provided::
226+
227+ void ltl_atom_pulse(struct task_struct *task, enum ltl_atom atom, bool value)
228+
229+ which is equivalent to::
230+
231+ ltl_atom_update(task, atom, value);
232+ ltl_atom_update(task, atom, !value);
233+
234+ To initialize the atomic propositions, the following function must be
235+ implemented::
236+
237+ ltl_atoms_init(struct task_struct *task, struct ltl_monitor *mon, bool task_creation)
238+
239+ This function is called for all running tasks when the monitor is enabled. It is
240+ also called for new tasks created after the enabling the monitor. It should
241+ initialize as many atomic propositions as possible, for example::
242+
243+ void ltl_atom_init(struct task_struct *task, struct ltl_monitor *mon, bool task_creation)
244+ {
245+ ltl_atom_set(mon, LTL_RT, rt_task(task));
246+ if (task_creation)
247+ ltl_atom_set(mon, LTL_PAGEFAULT, false);
248+ }
249+
250+ Atomic propositions not initialized by `ltl_atom_init() ` will stay in the
251+ unknown state until relevant tracepoints are hit, which can take some time. As
252+ monitoring for a task cannot be done until all atomic propositions is known for
253+ the task, the monitor may need some time to start validating tasks which have
254+ been running before the monitor is enabled. Therefore, it is recommended to
255+ start the tasks of interest after enabling the monitor.
256+
133257Final remarks
134258-------------
135259
136- With the monitor synthesis in place using the rv/da_monitor.h and
260+ With the monitor synthesis in place using the header files and
137261rvgen, the developer's work should be limited to the instrumentation
138262of the system, increasing the confidence in the overall approach.
139263
0 commit comments