Argus.Extractors.GenStatem.EventClauses (Panoptes v0.13.0)

Copy Markdown View Source

What event types a gen_statem callback discriminates on, and whether it has a catch-all.

A state function state(EventType, Content, Data) and the handle_event(EventType, Content, State, Data) callback both receive the event type first, in {x, 0}. The clause heads are what the runtime's messages are matched against, so two questions about them are worth answering from the bytecode:

  • which event types does this callback have a clause for at all? A {:timeout, ms, content} action arms an event of type :timeout; a module that arms one and has no clause with :timeout first has a timer that fires into a crash. Postgrex's SimpleConnection wrote the handler as handle_event(:info, :timeout, ...) and pinged nothing.
  • does it accept an :info event with any content? A gen_statem in state_functions mode is only as robust as its least defensive state, and a state without an :info catch-all dies on the first stray message it sees while in that state.

Reading the dispatch

Clause selection compiles to tests whose failure branch is either the next clause's label or the function's own func_info label (raise FunctionClauseError). A catch-all for some register set is a path from the dispatch to a body that passes the success branch only of tests on those registers, and takes failure branches freely — a failed test on the content is just "not this clause", and the clause we are looking for is the one after it.

So: for the :info catch-all, start where a test has just established {x, 0} == :info and allow success on {x, 0} only; for the total catch-all, start at the entry and allow success on nothing. Guards fall out correctly, since a guarded clause tests a register and its failure goes to func_info.

Answers

analyse/1 returns the event types some clause head compares the first argument to (tagged tuples as "{call}", "{timeout}"), whether some clause accepts :info with any content, and whether some clause accepts any event at all. Argus.Extractors.GenStatem emits them as statem_event_clause, statem_info_catchall and statem_event_catchall.

Summary

Functions

Reads one callback's clause heads. The caller turns the answer into facts; this module only walks bytecode, over the function's graph. Without a graph nothing is a catch-all.

Types

t()

@type t() :: %{
  event_types: [String.t()],
  info_catchall?: boolean(),
  event_catchall?: boolean()
}

Functions

analyse(fun, instrs)

@spec analyse(Argus.Cfg.Function.t() | nil, [tuple()]) :: t()

Reads one callback's clause heads. The caller turns the answer into facts; this module only walks bytecode, over the function's graph. Without a graph nothing is a catch-all.