180 likes | 242 Views
Bugs in the Wires or, An Exercise in Language Design. David Gay Intel Research Berkeley. Introduction. Observation 1: debugging sensor network programs is hard Observation 2: nesC makes wiring , i.e., connecting components of a nesC program, easy; this also means that it’s easy to miswire
E N D
Bugs in the Wiresor, An Exercise in Language Design David Gay Intel Research Berkeley
Introduction • Observation 1: debugging sensor network programs is hard • Observation 2:nesC makes wiring, i.e., connecting components of a nesC program, easy; this also means that it’s easy to miswire • example 1: forgetting to wire initialisation code • example 2: mistakenly wiring components together twice • Goal: add a simple language extension to catch these kinds of errors
Background: Modules and Wiring Init.init BlinkM Timer.setRate C functions function calls Timer.fired • interface Init { • command init(); • } • module BlinkM { • provides interface Init; • uses interface Timer; • } • implementation { • command Init.init() { • call Timer.setRate(); • } • event Timer.fired() { } • } • interface Timer { • command setRate(); • event fired(); • } Interfaces are bi-directional. BlinkM can call setRate and must implement init and fired.
Background: Configurations Init.init BlinkM Timer.setRate Timer.fired TimerM Timer.fired Timer.setRate • interface Init { • command init(); • } • configuration Blink { • provides interface Init; • } • implementation { • components TimerM, BlinkM; • Init = BlinkM.Init; • BlinkM.Timer -> TimerM.Timer; • } • interface Timer { • command setRate(); • event fired(); • } Blink Init.init
Wiring Graph is Very Flexible • Can build nearly arbitrary graphs, except: • module function nodes have 0-outdegree • module call nodes have 0-indegree
Wiring Bug Examples • BlinkM’s provided Init interface not wired • BlinkM never gets initialised • BlinkM’s provided Init interface wired twice • possible incorrect behaviour • provided Timer interface non-shareable, wired twice • incorrect behaviour (wrong rate in one user) • used split-phase interface wired twice • ex: interface Send { command send(); event sendDone(); } • two responses on every request, will misbehave
Wiring Bugs: The Fix • BlinkM’s provided Init interface not wired • BlinkM never gets initialised • BlinkM’s provided Init interface wired twice • possible incorrect behaviour • provided Timer interface non-shareable, wired twice • incorrect behaviour (wrong rate in one user) • used split-phase interface wired twice • ex: interface Send { command send(); event sendDone(); } • two responses on every request, will misbehave • Fixes: restrict wiring cardinality ≥ 1 = 1 ≤ 1 = 1
Wiring Bugs: The Fix • module BlinkM { • provides interface Init @atleastonce; • uses interface Timer @exactlyonce; • } • implementation { • command Init.init() { • call Timer.setRate(); • } • event Timer.fired() { } • } • @<attribute>: new syntax for annotations (see Java 1.5) • atmostonce, atleastonce, exactlyonce: • wiring annotations on provided, used interfaces • apply to each function in an interface • imply a global check on program’s wiring graph
Bugs in Language Design ≤1 • What do the annotations mean? • Obvious proposal: node in/out degree
Bugs in Language Design • What do the annotations mean? • Obvious proposal: node in/out degree • “Correct” answer appears to be: • provided functions: number of paths to this function • used functions: number of paths from this function call ≤1
Another Problem • What does this mean in a configuration? • Is this program right? wrong? provides interface Init @≤1
Another Problem • What does this mean in a configuration? • Is this program right? wrong? • Proposal: correct rule is: • provided function: check number of paths to this node • used function: check number of paths from this node • note: for bi-directional interfaces, this means that you check both the paths to and from the node provides interface Init @≤1
Does this do all we want? • module Simple { • uses interface Send; • } • implementation { • int state; • void somefn() { • state = SENDING; • call Send.send(); • } • event Send.sendDone() { • if (state == SENDING) … • } • } • Matched request/reply makes split-phase programs simpler • Let’s use exactlyonce! • interface Send { • command send(); • event sendDone(); • }
Does this do all we want? • module Simple { • uses interface Send • @exactlyonce; • } • implementation { • void somefn() { • call Send.send(); • } • event Send.sendDone() { • … • } • } • Matched request/reply makes split-phase programs simpler • Let’s use exactlyonce! • Code is simpler • interface Send { • command send(); • event sendDone(); • }
Does this do all we want? =1 Simple send =1 sendDone • module Simple { • uses interface Send • @exactlyonce; • } • implementation { • void somefn() { • call Send.send(); • } • event Send.sendDone() { • … • } • } • Matched request/reply makes split-phase programs simpler • Let’s use exactlyonce! • Code is simpler • Check is insufficient • interface Send { • command send(); • event sendDone(); • }
Conclusion • Wiring bugs are hard to find • Some of these bugs can be caught with annotations that restrict paths in the wiring graph: • atleastonce: at least one path to/from here • atmostonce: at most one path to/from here • exactlyonce: exactly one path to/from here • Does not cover all needs • could add singlepath: all nodes in path have in/out degree at most one • The annotation syntax will be in nesC 1.2, and will be user-extensible (see Java 1.5 specification for general idea)