-
Notifications
You must be signed in to change notification settings - Fork 10
Add events, event history, and transition history to runtime interface #66
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This is a significant refactor of the runtime interface. It makes several code quality and consistency improvements, and sets up work on monitoring more kinds of events and storing event and transition history. All tests that depend on the runtime system are disabled since the code generator has not been updated to use the new interface.
This is a mostly complete implementation of the codegen for the refactored state context and event representations, needed to support the extended runtime interface. Most of the codegen for the new runtime interface itself is also done, but there are likely still gaps there. Unfortunately, I realized that my refactoring of how domain variables are represented is going to break almost all existing code and make the interface for simple cases worse... so I'm going to back those changes out, which is the reason for this WIP commit. Essentially all end-to-end tests are disabled in this commit due to the problem described above and since there are likely other issues still lurking in the new codegen stuff.
More work on the codegen for the new state context/event representation. All tests with runtime_support disabled now pass.
More work on codegen to get the runtime interface working again for the basic tests.
Everything else is assuming single-threaded, so this is overly restrictive and prevents useful applications, e.g. saving events which are wrapped in Rc<..>.
This makes the history reflect the more natural event ordering. Since the history stores a reference to the event, the return value will be set in the history when the event is fully handled.
Also adds getters for the history capacities.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR adds a bunch of new functionality to the runtime interface related to events and transitions. It also includes several refactorings, both in the runtime interface and in the generated code, which supports these new features while also simplifying the interface and setting up future work.
The rest of this post describes these changes in a bit more detail.
New callback interface for events
Frame events include interface method calls and state enter/exit events--basically, anything that can be handled in Frame by defining a corresponding handler associated with a state.
You can now register callbacks to be notified of Frame events. Callbacks can be registered via two methods, both associated with the
EventMonitor
obtainable via the runtime interface from a state machine instance:add_event_sent_callback
-- Adds a callback that will be invoked whenever an event is sent.add_event_handled_callback
-- Adds a callback that will be invoked whenever an event has been completely handled.The sent callbacks will be invoked for events in the more intuitive order. For example, if calling method m triggers a transition from state A to state B, then the callbacks will be invoked for events "m" (the method call), "A:<" (old state exit event), and "B:>" (new state enter event), in that order. However, because the handler for m will not have terminated yet until the transition is complete, the event "m" received by the callback will not yet contain the return value of m (since it hasn't been computed yet).
The handled callbacks will be invoked when the handlers for each event have completed. So, for the scenario above, the callbacks will be invoked in the order "A:<", "B:>", "m", since the handler for m doesn't terminate until after the transition. However, in this case, the event "m" received by the callback will contain the return value.
In all cases, the events received by the callback are references wrapped in
Rc<..>
, so they can be freely saved. The return value for an event received via a sent callback will be updated when the handler terminates, so if this event is saved, it's return value will be accessible later.I suspect that usually clients will want to be notified of events in the more intuitive order provided by
add_event_sent_callback
. However,add_event_handled_callback
is provided in case the return value is needed at the time the callback is invoked.Configurable event and transition history
The runtime interface (again via the
EventMonitor
) now maintains a history of recent events and transitions. The histories can be obtained viaget_event_history
andget_transition_history
.The length of history maintained can be configured via
set_event_history_capacity
andset_transition_history_capacity
, which take values of typeOption<usize>
. ANone
value indicates an unbounded history, whileSome(n)
indicates a history bounded to sizen
. The history feature can be disabled by setting the capacity toSome(0)
.By default, the history capacities are set to
Some(0)
(disabled) for the event history andSome(1)
(maintain the last transition only) for the transition history. This minimizes memory impact if these features are not needed.The default values can be configured via the new Framec configuration options
codegen.rust.runtime.event_history_capacity
andcodegen.rust.runtime.transition_history_capacity
, configurable via YAML or the attribute system, as usual. As with the built-in defaults, these can be overridden at runtime using theset_
methods listed above.Events in the event history are listed in the order the events were sent. The history stores
Rc<..>
references to each event, which will be updated as the event is handled. In particular, the return value of an event (if any) will be set once the event has been fully handled.Fixes #61
Fixes #62
Runtime interface refactoring
Several of the
*Info
types that were previously traits are now structs, standardizing and simplifying the interface.The main reason these were previously traits is that there was a cyclic reference, which causes problems for the struct-based representation, but not for the trait-based one. This is now resolved via a OnceCell.
The drawback of this solution is that the
once_cell
crate must now be included whenever the runtime interface is used. This must appear as a dependency in the host project since we're generating code that uses the crate, not just using it in theframe_runtime
library itself. I decided that the better interface was worth this cost...Perhaps more significantly, almost all
Environment
values (of which there are several) are now returned asRc<dyn Environment>
rather than&dyn Environment
. This enables significant improvements in the generated code, and also enables saving references to environments, as needed by the history mechanisms described above.Framec's Rust backend refactoring
The ability to save a history of references to events and states required refactoring of the generated Rust code. Mostly this refactoring involved shuffling where various
Rc<..>
andRefCell<..>
types occur.There are multiple side benefits of these refactorings, however, aside from supporting the history feature.
First and most importantly, it makes working with state contexts much more flexible. This should make it significantly easier to resolve #59, which is our most critical outstanding issue. (And resolving that would provide a workaround for #60.)
Second, it enabled removing explicit lifetime annotations from event and argument structs, which were previously needed when
runtime_support
was enabled. These complicated the code generator and were hard to reason about.Third, it should make it trivial to extend the callback interface to include actions in the future.