Primus.System
A collection of components defines a runnable instance of Primus Machine. Systems could be defined programmatically, using this interface, or in system description files.
The system definition holds enough information to initialize and run the system.
A system consequently passes through the following main phases of its life:
During the initialization phase, the init
method of all components is run. The observations and non-determism are blocked in this phase and other components might be unitialized in this phase (components are initialized in an unspecified order). Components should subscribe to other observations and register their Lisp primitives in this phase.
Components should minimize the side-effects on the Primus machine and do not use Interpreter, Linker, and/or any observable operations. In this phase the Primus Machine operates in the deterministic mode and fork/switch operators are disabled.
Once this phase is complete, the init
observation is posted and the system enters the post-init phase.
The post-init phase starts after the init
observation is posted. During this phase observation and non-determinism are enabled. This phase is used by the components that would like to change the initial state of the Machine (i.e., initialize variables, possibly non-deterministically, link code, etc).
Components that need this kind of initialization shall subscribe to the init
observation and perform the necessary post-initialization in the handler.
This stage is used to prepare the Machine for the execution. Once it is finished the start
observation is posted.
Any exception that is thrown in this phase will prevent machine from running and terminate the computation immediately.
The start
observation designates the start of the execution and the code that is attached to this observation denotes the main function of the system. It is possible that there is more than one component attach their behavior to the start
event, in that case all the components will be run in an unspecified order.
It is not strictly required that a system should have components that are executed in the running phase, as when a system is run it is possible to provide the code that is run, during the start phase (as well as the code that is run during, the post-init phase), see System.run
below.
After the code attached to the start phase terminates, either normally or via the Primus exception, the fini
observation is posted and the system enters the post-running phase. This is a non-deterministic phase and components of the system might resume running by switching the computation to another fork, therefore, the system can enter this phase multiple times (but exit only once).
Once the post-running phase is finally finished, the machine enters the final stopped
phases.
This is the final phase and, like the initial phase, observations and non-determinism are disabled. This phase could be used to summarize the information that was obtained during the system run.
When the system enters the stopped state it is no longer possible to restart it and all computations that are run during this phase will not be observable.
Since Primus Machine is non-deterministic, for the given system we can observe more than one finalizations of computations. Usually, schedulers use the fini
observation to kill the finished machine and switch to another machine.
When a machine is killed the killed
observation is posted that could be used to summarize the machine. After the killed
observation is posted, the machine (not the system) enters the machine stopped phase in which observations and non-determinism are blocked (it is only possible to update the project data structure or record the information in the knowledge base).
type t = system
the system definition
val define :
?desc:string ->
?depends_on:system_specification list ->
?components:component_specification list ->
?package:string ->
string ->
t
define name
defines a new system.
The system designator is built from package
and name
and could be used to reference this system from the user interface. The designator is not required to be unique and is not registered anywhere in the library.
add_component ?package system name
adds a component to the system.
Adds the component designated by the given package and name to the system
.
add_dependency ?package system name
adds the designated system to the list of the system
depenencies.
Essentially, all components of the dependency are added to the dependent system.
val run :
?envp:string array ->
?args:string array ->
?init:unit Machine.Make(Bap_knowledge.Knowledge).t ->
?fini:unit Machine.Make(Bap_knowledge.Knowledge).t ->
?start:unit Machine.Make(Bap_knowledge.Knowledge).t ->
system ->
Bap.Std.project ->
Bap_knowledge.Knowledge.state ->
(exit_status * Bap.Std.project * Bap_knowledge.Knowledge.state,
Bap_knowledge.Knowledge.conflict)
Core_kernel.result
run system project state
runs the analysis defined by system
.
Initializes all components and triggers the init
observation after that. Once the observation is processed runs the fini
event.
The components that comprise the system
must schedule their evaluation on one of the observations.
The project
and state
are passed as the initial static representation of the program and the initial knowledge. The result of the analysis is either a failure that indicates a conflicting knowledge or a success that includes an updated program representation, computation exit status, and possibly extend knowledge.
See the Job.run
function if you want to run Primus instances in a batch mode.
val init : unit observation
init ()
is posted when all components finished their initializations. It is not posted if components failed to initialize the system.
val start : string observation
start sys
occurs after the system sys
starts.
val fini : unit observation
fini ()
is posted when all computations are finished. This observation is posted only if init
was posted and successfully evaluated all observers.
I.e., if the system wasn't initialized then neither init
nor fini
will happen.
val stop : string observation
stop sys
occurs when the system stops. The observation handlers are called in the restricted mode (with non-determinism and observations disabled).
This observation could be used to summarize the run of the system.
val name : system -> Bap_knowledge.Knowledge.Name.t
name system
is the system designator.
val pp : Stdlib.Format.formatter -> system -> unit
prints the system definition.
val component : ?package:string -> string -> component_specification
component ?package name
specifies the component with the given designator.
val depends_on : ?package:string -> string -> system_specification
depends_on ?package name
specifies a dependency on a system with the given designator.
val from_file : string -> (system list, parse_error) Core_kernel.result
from_file name
parses a list of system descriptions from the file with the given name
.
The file should have the following format (closely follows Common Lisp's asdf format)
systems ::= <system-definition> ... system-definition ::= (defsystem <ident> <option> ...) option ::= | :description <string> | :components (<ident> ...) | :depends-on (<ident> ...)
The primus-systems
plugin will search and load system definition files, see bap --primus-systems-help
for more information.
val pp_parse_error : Stdlib.Format.formatter -> parse_error -> unit
prints the parse error
module Repository : sig ... end
The systems repository.