aio_notify_bug.promela 4.1 KB

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