99 lines
3.7 KiB
Promela
99 lines
3.7 KiB
Promela
/*
|
|
* 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;
|
|
}
|