qemu/docs/aio_notify_bug.promela
<<
>>
Prefs
   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
  24int notify_me;
  25bool event;
  26bool req;
  27bool notifier_done;
  28
  29#ifdef CHECK_REQ
  30#define USE_NOTIFY_ME 1
  31#else
  32#define USE_NOTIFY_ME 0
  33#endif
  34
  35active proctype notifier()
  36{
  37    do
  38        :: true -> {
  39            req = 1;
  40            if
  41               :: !USE_NOTIFY_ME || notify_me -> event = 1;
  42               :: else -> skip;
  43            fi
  44        }
  45        :: true -> break;
  46    od;
  47    notifier_done = 1;
  48}
  49
  50#ifdef BUG
  51#define AIO_POLL                                                    \
  52    notify_me++;                                                    \
  53    if                                                              \
  54        :: !req -> {                                                \
  55            if                                                      \
  56                :: event -> skip;                                   \
  57            fi;                                                     \
  58        }                                                           \
  59        :: else -> skip;                                            \
  60    fi;                                                             \
  61    notify_me--;                                                    \
  62                                                                    \
  63    req = 0;                                                        \
  64    event = 0;
  65#else
  66#define AIO_POLL                                                    \
  67    notify_me++;                                                    \
  68    if                                                              \
  69        :: !req -> {                                                \
  70            if                                                      \
  71                :: event -> skip;                                   \
  72            fi;                                                     \
  73        }                                                           \
  74        :: else -> skip;                                            \
  75    fi;                                                             \
  76    notify_me--;                                                    \
  77                                                                    \
  78    event = 0;                                                      \
  79    req = 0;
  80#endif
  81
  82active proctype waiter()
  83{
  84    do
  85       :: true -> AIO_POLL;
  86    od;
  87}
  88
  89/* Same as waiter(), but disappears after a while.  */
  90active proctype temporary_waiter()
  91{
  92    do
  93       :: true -> AIO_POLL;
  94       :: true -> break;
  95    od;
  96}
  97
  98#ifdef CHECK_REQ
  99never {
 100    do
 101        :: req -> goto accept_if_req_not_eventually_false;
 102        :: true -> skip;
 103    od;
 104
 105accept_if_req_not_eventually_false:
 106    if
 107        :: req -> goto accept_if_req_not_eventually_false;
 108    fi;
 109    assert(0);
 110}
 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 */
 120never {
 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
 127accept_if_event_not_eventually_true:
 128    if
 129        :: !event && notifier_done  -> do :: true -> skip; od;
 130        :: !event && !notifier_done -> goto accept_if_event_not_eventually_true;
 131    fi;
 132    assert(0);
 133
 134accept_if_event_not_eventually_false:
 135    if
 136        :: event     -> goto accept_if_event_not_eventually_false;
 137    fi;
 138    assert(0);
 139}
 140#endif
 141