win32-qemu-event.promela 3.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. /*
  2. * This model describes the implementation of QemuEvent in
  3. * util/qemu-thread-win32.c.
  4. *
  5. * Author: Paolo Bonzini <pbonzini@redhat.com>
  6. *
  7. * This file is in the public domain. If you really want a license,
  8. * the WTFPL will do.
  9. *
  10. * To verify it:
  11. * spin -a docs/event.promela
  12. * gcc -O2 pan.c -DSAFETY
  13. * ./a.out
  14. */
  15. bool event;
  16. int value;
  17. /* Primitives for a Win32 event */
  18. #define RAW_RESET event = false
  19. #define RAW_SET event = true
  20. #define RAW_WAIT do :: event -> break; od
  21. #if 0
  22. /* Basic sanity checking: test the Win32 event primitives */
  23. #define RESET RAW_RESET
  24. #define SET RAW_SET
  25. #define WAIT RAW_WAIT
  26. #else
  27. /* Full model: layer a userspace-only fast path on top of the RAW_*
  28. * primitives. SET/RESET/WAIT have exactly the same semantics as
  29. * RAW_SET/RAW_RESET/RAW_WAIT, but try to avoid invoking them.
  30. */
  31. #define EV_SET 0
  32. #define EV_FREE 1
  33. #define EV_BUSY -1
  34. int state = EV_FREE;
  35. int xchg_result;
  36. #define SET if :: state != EV_SET -> \
  37. atomic { /* xchg_result=xchg(state, EV_SET) */ \
  38. xchg_result = state; \
  39. state = EV_SET; \
  40. } \
  41. if :: xchg_result == EV_BUSY -> RAW_SET; \
  42. :: else -> skip; \
  43. fi; \
  44. :: else -> skip; \
  45. fi
  46. #define RESET if :: state == EV_SET -> atomic { state = state | EV_FREE; } \
  47. :: else -> skip; \
  48. fi
  49. int tmp1, tmp2;
  50. #define WAIT tmp1 = state; \
  51. if :: tmp1 != EV_SET -> \
  52. if :: tmp1 == EV_FREE -> \
  53. RAW_RESET; \
  54. atomic { /* tmp2=cas(state, EV_FREE, EV_BUSY) */ \
  55. tmp2 = state; \
  56. if :: tmp2 == EV_FREE -> state = EV_BUSY; \
  57. :: else -> skip; \
  58. fi; \
  59. } \
  60. if :: tmp2 == EV_SET -> tmp1 = EV_SET; \
  61. :: else -> tmp1 = EV_BUSY; \
  62. fi; \
  63. :: else -> skip; \
  64. fi; \
  65. assert(tmp1 != EV_FREE); \
  66. if :: tmp1 == EV_BUSY -> RAW_WAIT; \
  67. :: else -> skip; \
  68. fi; \
  69. :: else -> skip; \
  70. fi
  71. #endif
  72. active proctype waiter()
  73. {
  74. if
  75. :: !value ->
  76. RESET;
  77. if
  78. :: !value -> WAIT;
  79. :: else -> skip;
  80. fi;
  81. :: else -> skip;
  82. fi;
  83. assert(value);
  84. }
  85. active proctype notifier()
  86. {
  87. value = true;
  88. SET;
  89. }