/* * This model describes the interaction between aio_set_dispatching() * and aio_notify(). * * Author: Paolo Bonzini * * 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 }