Module Primus.System

An instance of the Primus Machine

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.

System's timeline

A system consequently passes through the following main phases of its life:

The initialization phase

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

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 running phase

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.

The post-running phase

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.

The stopped phase

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.

Non-determinism and machine stopping

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

type component_specification

designates some component

type system_specification

designates a system

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.

  • parameter desc

    a human-readable description of the system, its task and purposes

  • parameter components

    a list of component specifications that this system includes.

  • parameter depends_on

    a list of system specifications on which this system depends.

val add_component : ?package:string -> t -> string -> t

add_component ?package system name adds a component to the system.

Adds the component designated by the given package and name to the system.

val add_dependency : ?package:string -> t -> string -> t

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.

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.

  • parameter envp

    an array of environment variables that are passed to the program.

  • parameter args

    an array of program parameters, with the first element of array being the program name.

  • parameter init

    is called after all components are initialized but before the init observations is made.

  • parameter start

    is called after the the system is started (after the system-start observation is made).

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.

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.

  • parameter package

    defaults to user.

val depends_on : ?package:string -> string -> system_specification

depends_on ?package name specifies a dependency on a system with the given designator.

type parse_error

a parsing error description

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 Generic (Machine : Machine.S) : sig ... end
module Repository : sig ... end

The systems repository.