| /* |
| * This model describes the interaction between aio_set_dispatching() |
| * and aio_notify(). |
| * |
| * Author: Paolo Bonzini <pbonzini@redhat.com> |
| * |
| * This file is in the public domain. If you really want a license, |
| * the WTFPL will do. |
| * |
| * To simulate it: |
| * spin -p docs/aio_notify.promela |
| * |
| * To verify it: |
| * spin -a docs/aio_notify.promela |
| * gcc -O2 pan.c |
| * ./a.out -a |
| */ |
| |
| #define MAX 4 |
| #define LAST (1 << (MAX - 1)) |
| #define FINAL ((LAST << 1) - 1) |
| |
| bool dispatching; |
| bool event; |
| |
| int req, done; |
| |
| active proctype waiter() |
| { |
| int fetch, blocking; |
| |
| do |
| :: done != FINAL -> { |
| // Computing "blocking" is separate from execution of the |
| // "bottom half" |
| blocking = (req == 0); |
| |
| // This is our "bottom half" |
| atomic { fetch = req; req = 0; } |
| done = done | fetch; |
| |
| // Wait for a nudge from the other side |
| do |
| :: event == 1 -> { event = 0; break; } |
| :: !blocking -> break; |
| od; |
| |
| dispatching = 1; |
| |
| // If you are simulating this model, you may want to add |
| // something like this here: |
| // |
| // int foo; foo++; foo++; foo++; |
| // |
| // This only wastes some time and makes it more likely |
| // that the notifier process hits the "fast path". |
| |
| dispatching = 0; |
| } |
| :: else -> break; |
| od |
| } |
| |
| active proctype notifier() |
| { |
| int next = 1; |
| int sets = 0; |
| |
| do |
| :: next <= LAST -> { |
| // generate a request |
| req = req | next; |
| next = next << 1; |
| |
| // aio_notify |
| if |
| :: dispatching == 0 -> sets++; event = 1; |
| :: else -> skip; |
| fi; |
| |
| // Test both synchronous and asynchronous delivery |
| if |
| :: 1 -> do |
| :: req == 0 -> break; |
| od; |
| :: 1 -> skip; |
| fi; |
| } |
| :: else -> break; |
| od; |
| printf("Skipped %d event_notifier_set\n", MAX - sets); |
| } |
| |
| #define p (done == FINAL) |
| |
| never { |
| do |
| :: 1 // after an arbitrarily long prefix |
| :: p -> break // p becomes true |
| od; |
| do |
| :: !p -> accept: break // it then must remains true forever after |
| od |
| } |