Transition-notes 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. Lemma 1:
  2. If ps_tq is scheduled, ps_tq_active is 1. ps_tq_int() can be called
  3. only when ps_tq_active is 1.
  4. Proof: All assignments to ps_tq_active and all scheduling of ps_tq happen
  5. under ps_spinlock. There are three places where that can happen:
  6. one in ps_set_intr() (A) and two in ps_tq_int() (B and C).
  7. Consider the sequnce of these events. A can not be preceded by
  8. anything except B, since it is under if (!ps_tq_active) under
  9. ps_spinlock. C is always preceded by B, since we can't reach it
  10. other than through B and we don't drop ps_spinlock between them.
  11. IOW, the sequence is A?(BA|BC|B)*. OTOH, number of B can not exceed
  12. the sum of numbers of A and C, since each call of ps_tq_int() is
  13. the result of ps_tq execution. Therefore, the sequence starts with
  14. A and each B is preceded by either A or C. Moments when we enter
  15. ps_tq_int() are sandwiched between {A,C} and B in that sequence,
  16. since at any time number of B can not exceed the number of these
  17. moments which, in turn, can not exceed the number of A and C.
  18. In other words, the sequence of events is (A or C set ps_tq_active to
  19. 1 and schedule ps_tq, ps_tq is executed, ps_tq_int() is entered,
  20. B resets ps_tq_active)*.
  21. consider the following area:
  22. * in do_pd_request1(): to calls of pi_do_claimed() and return in
  23. case when pd_req is NULL.
  24. * in next_request(): to call of do_pd_request1()
  25. * in do_pd_read(): to call of ps_set_intr()
  26. * in do_pd_read_start(): to calls of pi_do_claimed(), next_request()
  27. and ps_set_intr()
  28. * in do_pd_read_drq(): to calls of pi_do_claimed() and next_request()
  29. * in do_pd_write(): to call of ps_set_intr()
  30. * in do_pd_write_start(): to calls of pi_do_claimed(), next_request()
  31. and ps_set_intr()
  32. * in do_pd_write_done(): to calls of pi_do_claimed() and next_request()
  33. * in ps_set_intr(): to check for ps_tq_active and to scheduling
  34. ps_tq if ps_tq_active was 0.
  35. * in ps_tq_int(): from the moment when we get ps_spinlock() to the
  36. return, call of con() or scheduling ps_tq.
  37. * in pi_schedule_claimed() when called from pi_do_claimed() called from
  38. pd.c, everything until returning 1 or setting or setting ->claim_cont
  39. on the path that returns 0
  40. * in pi_do_claimed() when called from pd.c, everything until the call
  41. of pi_do_claimed() plus the everything until the call of cont() if
  42. pi_do_claimed() has returned 1.
  43. * in pi_wake_up() called for PIA that belongs to pd.c, everything from
  44. the moment when pi_spinlock has been acquired.
  45. Lemma 2:
  46. 1) at any time at most one thread of execution can be in that area or
  47. be preempted there.
  48. 2) When there is such a thread, pd_busy is set or pd_lock is held by
  49. that thread.
  50. 3) When there is such a thread, ps_tq_active is 0 or ps_spinlock is
  51. held by that thread.
  52. 4) When there is such a thread, all PIA belonging to pd.c have NULL
  53. ->claim_cont or pi_spinlock is held by thread in question.
  54. Proof: consider the first moment when the above is not true.
  55. (1) can become not true if some thread enters that area while another is there.
  56. a) do_pd_request1() can be called from next_request() or do_pd_request()
  57. In the first case the thread was already in the area. In the second,
  58. the thread was holding pd_lock and found pd_busy not set, which would
  59. mean that (2) was already not true.
  60. b) ps_set_intr() and pi_schedule_claimed() can be called only from the
  61. area.
  62. c) pi_do_claimed() is called by pd.c only from the area.
  63. d) ps_tq_int() can enter the area only when the thread is holding
  64. ps_spinlock and ps_tq_active is 1 (due to Lemma 1). It means that
  65. (3) was already not true.
  66. e) do_pd_{read,write}* could be called only from the area. The only
  67. case that needs consideration is call from pi_wake_up() and there
  68. we would have to be called for the PIA that got ->claimed_cont
  69. from pd.c. That could happen only if pi_do_claimed() had been
  70. called from pd.c for that PIA, which happens only for PIA belonging
  71. to pd.c.
  72. f) pi_wake_up() can enter the area only when the thread is holding
  73. pi_spinlock and ->claimed_cont is non-NULL for PIA belonging to
  74. pd.c. It means that (4) was already not true.
  75. (2) can become not true only when pd_lock is released by the thread in question.
  76. Indeed, pd_busy is reset only in the area and thread that resets
  77. it is holding pd_lock. The only place within the area where we
  78. release pd_lock is in pd_next_buf() (called from within the area).
  79. But that code does not reset pd_busy, so pd_busy would have to be
  80. 0 when pd_next_buf() had acquired pd_lock. If it become 0 while
  81. we were acquiring the lock, (1) would be already false, since
  82. the thread that had reset it would be in the area simulateously.
  83. If it was 0 before we tried to acquire pd_lock, (2) would be
  84. already false.
  85. For similar reasons, (3) can become not true only when ps_spinlock is released
  86. by the thread in question. However, all such places within the area are right
  87. after resetting ps_tq_active to 0.
  88. (4) is done the same way - all places where we release pi_spinlock within
  89. the area are either after resetting ->claimed_cont to NULL while holding
  90. pi_spinlock, or after not tocuhing ->claimed_cont since acquiring pi_spinlock
  91. also in the area. The only place where ->claimed_cont is made non-NULL is
  92. in the area, under pi_spinlock and we do not release it until after leaving
  93. the area.
  94. QED.
  95. Corollary 1: ps_tq_active can be killed. Indeed, the only place where we
  96. check its value is in ps_set_intr() and if it had been non-zero at that
  97. point, we would have violated either (2.1) (if it was set while ps_set_intr()
  98. was acquiring ps_spinlock) or (2.3) (if it was set when we started to
  99. acquire ps_spinlock).
  100. Corollary 2: ps_spinlock can be killed. Indeed, Lemma 1 and Lemma 2 show
  101. that the only possible contention is between scheduling ps_tq followed by
  102. immediate release of spinlock and beginning of execution of ps_tq on
  103. another CPU.
  104. Corollary 3: assignment to pd_busy in do_pd_read_start() and do_pd_write_start()
  105. can be killed. Indeed, we are not holding pd_lock and thus pd_busy is already
  106. 1 here.
  107. Corollary 4: in ps_tq_int() uses of con can be replaced with uses of
  108. ps_continuation, since the latter is changed only from the area.
  109. We don't need to reset it to NULL, since we are guaranteed that there
  110. will be a call of ps_set_intr() before we look at ps_continuation again.
  111. We can remove the check for ps_continuation being NULL for the same
  112. reason - the value is guaranteed to be set by the last ps_set_intr() and
  113. we never pass it NULL. Assignements in the beginning of ps_set_intr()
  114. can be taken to callers as long as they remain within the area.