| /* |
| * This model describes the implementation of QemuEvent in |
| * util/qemu-thread-win32.c. |
| * |
| * Author: Paolo Bonzini <pbonzini@redhat.com> |
| * |
| * This file is in the public domain. If you really want a license, |
| * the WTFPL will do. |
| * |
| * To verify it: |
| * spin -a docs/event.promela |
| * gcc -O2 pan.c -DSAFETY |
| * ./a.out |
| */ |
| |
| bool event; |
| int value; |
| |
| /* Primitives for a Win32 event */ |
| #define RAW_RESET event = false |
| #define RAW_SET event = true |
| #define RAW_WAIT do :: event -> break; od |
| |
| #if 0 |
| /* Basic sanity checking: test the Win32 event primitives */ |
| #define RESET RAW_RESET |
| #define SET RAW_SET |
| #define WAIT RAW_WAIT |
| #else |
| /* Full model: layer a userspace-only fast path on top of the RAW_* |
| * primitives. SET/RESET/WAIT have exactly the same semantics as |
| * RAW_SET/RAW_RESET/RAW_WAIT, but try to avoid invoking them. |
| */ |
| #define EV_SET 0 |
| #define EV_FREE 1 |
| #define EV_BUSY -1 |
| |
| int state = EV_FREE; |
| |
| int xchg_result; |
| #define SET if :: state != EV_SET -> \ |
| atomic { /* xchg_result=xchg(state, EV_SET) */ \ |
| xchg_result = state; \ |
| state = EV_SET; \ |
| } \ |
| if :: xchg_result == EV_BUSY -> RAW_SET; \ |
| :: else -> skip; \ |
| fi; \ |
| :: else -> skip; \ |
| fi |
| |
| #define RESET if :: state == EV_SET -> atomic { state = state | EV_FREE; } \ |
| :: else -> skip; \ |
| fi |
| |
| int tmp1, tmp2; |
| #define WAIT tmp1 = state; \ |
| if :: tmp1 != EV_SET -> \ |
| if :: tmp1 == EV_FREE -> \ |
| RAW_RESET; \ |
| atomic { /* tmp2=cas(state, EV_FREE, EV_BUSY) */ \ |
| tmp2 = state; \ |
| if :: tmp2 == EV_FREE -> state = EV_BUSY; \ |
| :: else -> skip; \ |
| fi; \ |
| } \ |
| if :: tmp2 == EV_SET -> tmp1 = EV_SET; \ |
| :: else -> tmp1 = EV_BUSY; \ |
| fi; \ |
| :: else -> skip; \ |
| fi; \ |
| assert(tmp1 != EV_FREE); \ |
| if :: tmp1 == EV_BUSY -> RAW_WAIT; \ |
| :: else -> skip; \ |
| fi; \ |
| :: else -> skip; \ |
| fi |
| #endif |
| |
| active proctype waiter() |
| { |
| if |
| :: !value -> |
| RESET; |
| if |
| :: !value -> WAIT; |
| :: else -> skip; |
| fi; |
| :: else -> skip; |
| fi; |
| assert(value); |
| } |
| |
| active proctype notifier() |
| { |
| value = true; |
| SET; |
| } |