rely guarantee reasoning for asynchronous programs
play

Rely/Guarantee Reasoning for Asynchronous Programs Ivan Gavran 1 , - PowerPoint PPT Presentation

Rely/Guarantee Reasoning for Asynchronous Programs Ivan Gavran 1 , Filip Niksic 1 , Aditya Kanade 2 , Rupak Majumdar 1 , Viktor Vafeiadis 1 1 Max Planck Institute for Software Systems (MPI-SWS), Germany 2 Indian Institute of Science, Bangalore,


  1. Rely/Guarantee Reasoning for Asynchronous Programs Ivan Gavran 1 , Filip Niksic 1 , Aditya Kanade 2 , Rupak Majumdar 1 , Viktor Vafeiadis 1 1 Max Planck Institute for Software Systems (MPI-SWS), Germany 2 Indian Institute of Science, Bangalore, India

  2. Asynchronous programming is widespread • Web apps : AJAX, jQuery, XMLHttpRequest • Smartphone apps : AsyncTask, dispatch_async • Server-side : node.js, java.nio • Systems : kqueue, epoll, Libevent • Other : async/await in Scala

  3. Common feature: Posting tasks for later execution A pending tasks

  4. Common feature: Posting tasks for later execution A pending tasks B C

  5. Common feature: Posting tasks for later execution A B C pending tasks

  6. Common feature: Posting tasks for later execution A B C Tasks may be executed when pending tasks • triggered by external events (mouse click, response ready, socket ready, …) • dispatched by a scheduler

  7. Drawback: Obscured control-flow A B C

  8. Drawback: Obscured control-flow A C B Multiple pending tasks may be executed in any order .

  9. Drawback: Obscured control-flow A C B precondition P B

  10. Drawback: Obscured control-flow A C B precondition P B postcondition Q A Q A ⇒ P B

  11. Drawback: Obscured control-flow A C B precondition P B postcondition Q A Q A ⇒ P B C might invalidate P B

  12. Adapting rely/guarantee reasoning [Jones83] A C B precondition P B postcondition Q A Q A ⇒ P B

  13. Adapting rely/guarantee reasoning [Jones83] A C B precondition P B postcondition Q A Q A ⇒ P B rely R B : “preserve P B ”

  14. Adapting rely/guarantee reasoning [Jones83] A C B precondition P B postcondition Q A Q A ⇒ P B rely R B : “preserve P B ” guarantee G C G C ⇒ R B

  15. Soundness of rely/guarantee reasoning Given a program with specification in terms of predicates P, Q, R, G, if the predicates satisfy “natural rely/guarantee • conditions” each task meets its rely/guarantee specification • then the program is correct.

  16. Rely/guarantee reasoning is modular Sufficient to verify each task in isolation , using a verifier for sequential software.

  17. Contributions We have: • Identified the “natural rely/guarantee conditions” • Proved soundness of rely/guarantee reasoning • Demonstrated the approach on two C programs that use Libevent (done using Frama-C)

  18. The rest of the talk: Rely/guarantee… … by example … in theory … in practice

  19. The rest of the talk: Rely/guarantee… … by example … in theory … in practice

  20. Modeling asynchronous tasks Extend an imperative language with asynchronous procedures , together with constructs: post f(v 1 , …, v k ) delete f(v 1 , …, v k ) Maintain a set of pending procedure instances . Execute instances atomically in a non-deterministic order .

  21. Example: ROT13 server async main() { int socket = prepare_socket(); post accept(socket); } async accept( int socket) { struct client *c = malloc(…); client_setup(c); c->fd = accept_connection(socket); post read(c); post accept(socket); } async read( struct client *c) { … } async write( struct client *c) { … }

  22. Example: ROT13 server async read( struct client *c) { async write( struct client *c) { if (…) { // c->fd is ready if (…) { // c->fd is ready receive_chunk(c); send_chunk(c); post write(c); if (more_to_send(c)) post read(c); post write(c); } } else { // connection is closed else { // connection is closed delete write(c); delete read(c); free(c); free(c); } } } }

  23. Example: ROT13 server //@ requires valid(c); //@ requires valid(c); async read( struct client *c) { async write( struct client *c) { if (…) { // c->fd is ready if (…) { // c->fd is ready receive_chunk(c); send_chunk(c); post write(c); if (more_to_send(c)) post read(c); post write(c); } } else { // connection is closed else { // connection is closed delete write(c); delete read(c); free(c); free(c); } } } }

  24. Introducing predicate posted f For each asynchronous procedure f(x 1 ,…,x k ) , we introduce a predicate posted f (x 1 , …, x k ) True iff f has been posted with arguments x 1 , …, x k during the execution of the current asynchronous procedure .

  25. Example: ROT13 server /*@ requires valid(c); /*@ requires valid(c); @ ensures ∀ c 1 ; @ ensures ∀ c 1 ; @ posted_read(c 1 ) ⇒ valid(c 1 ); @ posted_write(c 1 ) ⇒ valid(c 1 ); @ ensures ∀ c 1 ; @*/ @ posted_write(c 1 ) ⇒ valid(c 1 ); async write( struct client *c) { if (…) { // c->fd is ready @*/ send_chunk(c); async read( struct client *c) { if (more_to_send(c)) if (…) { // c->fd is ready post write(c); receive_chunk(c); } post write(c); else { // connection is closed post read(c); delete read(c); } free(c); else { // connection is closed } delete write(c); } free(c); } }

  26. Preserving the precondition read(c) write(c) P write ( c ) ≡ valid( c ) P write ( c ) ≡ valid( c ) parent child

  27. Preserving the precondition read(c 1 ) write(c 1 ) read(c) accept(socket) write(c) P write ( c ) ≡ valid( c ) P write ( c ) ≡ valid( c ) parent concurrent siblings child

  28. Preserving the precondition read(c 1 ) write(c 1 ) read(c) accept(socket) write(c) G read ⇒ R write guarantee P write rely on P write G write ⇒ R write is preserved being preserved G accept ⇒ R write parent concurrent siblings child

  29. Introducing predicate pending f For each asynchronous procedure f(x 1 ,…,x k ) , we introduce a predicate pending f (x 1 , …, x k ) True iff f with arguments x 1 , …, x k is pending , i.e. is in the set of pending procedure instances.

  30. write ’s rely predicate R write R write ≡ ∀ c. (pending’ write (c) ∧ pending write (c) ∧ valid’(c)) ⇒ valid(c) (prime means at the beginning of execution)

  31. write ’s global invariant With write ’s parents ensuring: ∀ c. posted write (c) ⇒ valid(c) and write ’s concurrent siblings ensuring: ∀ c. (pending’ write (c) ∧ pending write (c) ∧ valid’(c)) ⇒ valid(c) rely/guarantee ensures a global invariant : ∀ c. pending write (c) ⇒ valid(c)

  32. Final specification of write /*@ requires Precondition: @ valid(c); @ ensures Parent_child_condition: @ ∀ c 1 ; posted_write(c 1 ) ⇒ valid(c 1 ); @ ensures Guarantee: @ ( ∀ c 1 ; (pending_read’(c 1 ) ∧ pending_read(c 1 ) @ ∧ valid’(c 1 )) ⇒ valid(c 1 )) @ ∧ ( ∀ c 1 ; (pending_write’(c 1 ) ∧ pending_write(c 1 ) @ ∧ valid’(c 1 )) ⇒ valid(c 1 )); @*/ async write( struct client *c) { … }

  33. Final specification of write /*@ requires Precondition: @ valid(c); @ ensures Parent_child_condition: @ ∀ c 1 ; posted_write(c 1 ) ⇒ valid(c 1 ); @ ensures Guarantee: @ ( ∀ c 1 ; (pending_read’(c 1 ) ∧ pending_read(c 1 ) } R read @ ∧ valid’(c 1 )) ⇒ valid(c 1 )) @ ∧ ( ∀ c 1 ; (pending_write’(c 1 ) ∧ pending_write(c 1 ) } R write @ ∧ valid’(c 1 )) ⇒ valid(c 1 )); @*/ async write( struct client *c) { … }

  34. Final specification of write /*@ requires Precondition: @ valid(c); @ ensures Parent_child_condition: @ ∀ c 1 ; posted_write(c 1 ) ⇒ valid(c 1 ); @ ensures Guarantee: @ ( ∀ c 1 ; (pending_read’(c 1 ) ∧ pending_read(c 1 ) } R read @ ∧ valid’(c 1 )) ⇒ valid(c 1 )) @ ∧ ( ∀ c 1 ; (pending_write’(c 1 ) ∧ pending_write(c 1 ) } R write @ ∧ valid’(c 1 )) ⇒ valid(c 1 )); @*/ async write( struct client *c) { … } write can now be verified in isolation using a standard verification tool (in our case Frama-C)

  35. The rest of the talk: Rely/guarantee… … by example … in theory … in practice

  36. Rely/guarantee decomposition For each asynchronous procedure f we require: • P f — precondition predicate • R f — rely predicate • G f — guarantee predicate • Q f — postcondition predicate First-order formulas; may include predicates posted g and pending g (in negative positions)

  37. Rely/guarantee conditions Given a rely/guarantee decomposition, for each asynchronous procedure f : (1) Q f ⇒ G f (2) Q g ⇒ (posted f ⇒ P f ), for each g ∈ parents( f ) (3) R f ⇒ ((pending’ f ∧ pending f ∧ P’ f ) ⇒ P f ) (4) G g ⇒ R f , for each g ∈ siblings( f )

  38. Soundness of rely/guarantee reasoning Theorem. Given an asynchronous program with a rely/guarantee decomposition, if • the decomposition satisfies the rely/guarantee conditions • each procedure meets its specification (P and Q) then the program is correct.

  39. Key lemma Lemma. For each asynchronous procedure f , at every schedule point we have pending f ⇒ P f

  40. The rest of the talk: Rely/guarantee… … by example … in theory … in practice

  41. Generic rely/guarantee predicates Given preconditions P f , the weakest predicates that satisfy the rely/guarantee conditions: • R f ≡ (pending’ f ∧ pending f ∧ P’ f ) ⇒ P f • G f ≡ ⋀ R g g ∈ siblings( f ) • Q f ≡ G f ∧ ⋀ posted g ⇒ P g g ∈ children( f )

Recommend


More recommend