aio_notify_accept.promela 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. /*
  2. * This model describes the interaction between ctx->notified
  3. * and ctx->notifier.
  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 the buggy version:
  11. * spin -a -DBUG1 docs/aio_notify_bug.promela
  12. * gcc -O2 pan.c
  13. * ./a.out -a -f
  14. * (or -DBUG2)
  15. *
  16. * To verify the fixed version:
  17. * spin -a docs/aio_notify_bug.promela
  18. * gcc -O2 pan.c
  19. * ./a.out -a -f
  20. *
  21. * Add -DCHECK_REQ to test an alternative invariant and the
  22. * "notify_me" optimization.
  23. */
  24. int notify_me;
  25. bool notified;
  26. bool event;
  27. bool req;
  28. bool notifier_done;
  29. #ifdef CHECK_REQ
  30. #define USE_NOTIFY_ME 1
  31. #else
  32. #define USE_NOTIFY_ME 0
  33. #endif
  34. #ifdef BUG
  35. #error Please define BUG1 or BUG2 instead.
  36. #endif
  37. active proctype notifier()
  38. {
  39. do
  40. :: true -> {
  41. req = 1;
  42. if
  43. :: !USE_NOTIFY_ME || notify_me ->
  44. #if defined BUG1
  45. /* CHECK_REQ does not detect this bug! */
  46. notified = 1;
  47. event = 1;
  48. #elif defined BUG2
  49. if
  50. :: !notified -> event = 1;
  51. :: else -> skip;
  52. fi;
  53. notified = 1;
  54. #else
  55. event = 1;
  56. notified = 1;
  57. #endif
  58. :: else -> skip;
  59. fi
  60. }
  61. :: true -> break;
  62. od;
  63. notifier_done = 1;
  64. }
  65. #define AIO_POLL \
  66. notify_me++; \
  67. if \
  68. :: !req -> { \
  69. if \
  70. :: event -> skip; \
  71. fi; \
  72. } \
  73. :: else -> skip; \
  74. fi; \
  75. notify_me--; \
  76. \
  77. atomic { old = notified; notified = 0; } \
  78. if \
  79. :: old -> event = 0; \
  80. :: else -> skip; \
  81. fi; \
  82. \
  83. req = 0;
  84. active proctype waiter()
  85. {
  86. bool old;
  87. do
  88. :: true -> AIO_POLL;
  89. od;
  90. }
  91. /* Same as waiter(), but disappears after a while. */
  92. active proctype temporary_waiter()
  93. {
  94. bool old;
  95. do
  96. :: true -> AIO_POLL;
  97. :: true -> break;
  98. od;
  99. }
  100. #ifdef CHECK_REQ
  101. never {
  102. do
  103. :: req -> goto accept_if_req_not_eventually_false;
  104. :: true -> skip;
  105. od;
  106. accept_if_req_not_eventually_false:
  107. if
  108. :: req -> goto accept_if_req_not_eventually_false;
  109. fi;
  110. assert(0);
  111. }
  112. #else
  113. /* There must be infinitely many transitions of event as long
  114. * as the notifier does not exit.
  115. *
  116. * If event stayed always true, the waiters would be busy looping.
  117. * If event stayed always false, the waiters would be sleeping
  118. * forever.
  119. */
  120. never {
  121. do
  122. :: !event -> goto accept_if_event_not_eventually_true;
  123. :: event -> goto accept_if_event_not_eventually_false;
  124. :: true -> skip;
  125. od;
  126. accept_if_event_not_eventually_true:
  127. if
  128. :: !event && notifier_done -> do :: true -> skip; od;
  129. :: !event && !notifier_done -> goto accept_if_event_not_eventually_true;
  130. fi;
  131. assert(0);
  132. accept_if_event_not_eventually_false:
  133. if
  134. :: event -> goto accept_if_event_not_eventually_false;
  135. fi;
  136. assert(0);
  137. }
  138. #endif