Verification Challenges

"Analyze This" II

Verify that the following implementation of a non-blocking queue algorithm is correct. This non-blocking queue is taken from Simple, Fast, and Practical Non-Blocking and Blocking Concurrent Queue Algorithms by Maged M. Michael and Michael L. Scott (PODC'96).

The first (easier) challenge is to verify that the implementation satisfies some structural properties (taken from the manual proof in the PODC'96 paper). The properties to be verified are:

P1 The linked list is always connected.

P2 Nodes are only inserted after the last node of the linked list.

P3 Nodes are only deleted from the beginning of the linked list.

P4 Head always points to the first node in the linked list.

P5 Tail always points to a node in the linked list.

The next challenge is to verify that the implementation is linearizable.

// Non Blocking Queue

class NonBlockingQueue {
  private QueueItem Head;
  private QueueItem Tail;
  ...

NonBlockingQueue() {
     node = new QueueItem()
     node.next.ref = NULL
     this.Head = this.Tail = node
}

public void enqueue(Object value) {
e_1   node = new QueueItem()
e_2   node.value = value
e_3   node.next.ref = NULL
e_4   while(true) { // Keep trying until done
e_5    tail = this.Tail
e_6    next = tail.ref.next
e_7    if (tail == this.Tail) {
e_8     if (next.ref == NULL) {
e_9      if CAS(tail.ref.next, next, <node, next.count+1>) {
e_10       break // Enqueue is done. Exit loop
e_11      }
e_12     } else {
e_13       CAS(this.Tail, tail, <next.ref, tail.count+1>)
e_14     }
e_15    }
e_16   }
e_17   CAS(this.Tail, tail, <node, tail.count+1>)
e_18 }

public Object dequeue() {
  Object result = null
d_1   while(true) {
d_2    head = this.Head
d_3    tail = this.Tail
d_4    next = head.next
d_5    if (head == this.Head) {
d_6     if (head.ref == tail.ref) {
d_7      if (next.ref == NULL) { // is empty?
d_8       return result
d_9      }
d_10      CAS(this.Tail, tail, <next.ref, tail.count+1>)
d_11     } else { // No need to deal with Tail
d_12      result = next.ref.value
d_13      if CAS(this.Head, head, <next.ref, head.count+1>) {
d_14       break // dequeue done
d_15      }
d_16     }
d_17    }
d_18   }
d_19 free(head.ref) // safe to free old dummy node
d_20 return result
d_21
} }

Where the implementation of QueueItem is given below


// QueueItem.java
class QueueItem {
    public QueueItem next;
    public Object value;
    ...
}
    


We showed some version of verification of the structural properties in Automatically Verifying Concurrent Queue Algorithms, Yahav E. and Sagiv M., SoftMC 2003, [bib][abstract][ps][pdf][slides]

We investigated verification of linearizability for such algorithms in Comparison under Abstraction for Verifying Linearizability, Amit D., Rinetzky N. , Reps T., Sagiv M. and Yahav E., CAV'07: Computer Aided Verification 2007, [bib] [abstract] [ps] [pdf] [slides]

We also showed how to systematically derive linearizable concurrent data-structures from a sequential implementation in Deriving Linearizable Fine-Grained Concurrent Objects, Vechev M., Yahav E., PLDI '08: ACM SIGPLAN 2008 Conference on Programming Language Design and Implementation., [bib] [abstract] [pdf] [slides]