18c2ecf20Sopenharmony_ciLemma 1:
28c2ecf20Sopenharmony_ci	If ps_tq is scheduled, ps_tq_active is 1.  ps_tq_int() can be called
38c2ecf20Sopenharmony_ci	only when ps_tq_active is 1.
48c2ecf20Sopenharmony_ciProof:	All assignments to ps_tq_active and all scheduling of ps_tq happen
58c2ecf20Sopenharmony_ci	under ps_spinlock.  There are three places where that can happen:
68c2ecf20Sopenharmony_ci	one in ps_set_intr() (A) and two in ps_tq_int() (B and C).
78c2ecf20Sopenharmony_ci	Consider the sequnce of these events.  A can not be preceded by
88c2ecf20Sopenharmony_ci	anything except B, since it is under if (!ps_tq_active) under
98c2ecf20Sopenharmony_ci	ps_spinlock.  C is always preceded by B, since we can't reach it
108c2ecf20Sopenharmony_ci	other than through B and we don't drop ps_spinlock between them.
118c2ecf20Sopenharmony_ci	IOW, the sequence is A?(BA|BC|B)*.  OTOH, number of B can not exceed
128c2ecf20Sopenharmony_ci	the sum of numbers of A and C, since each call of ps_tq_int() is
138c2ecf20Sopenharmony_ci	the result of ps_tq execution.  Therefore, the sequence starts with
148c2ecf20Sopenharmony_ci	A and each B is preceded by either A or C.  Moments when we enter
158c2ecf20Sopenharmony_ci	ps_tq_int() are sandwiched between {A,C} and B in that sequence,
168c2ecf20Sopenharmony_ci	since at any time number of B can not exceed the number of these
178c2ecf20Sopenharmony_ci	moments which, in turn, can not exceed the number of A and C.
188c2ecf20Sopenharmony_ci	In other words, the sequence of events is (A or C set ps_tq_active to
198c2ecf20Sopenharmony_ci	1 and schedule ps_tq, ps_tq is executed, ps_tq_int() is entered,
208c2ecf20Sopenharmony_ci	B resets ps_tq_active)*.
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ciconsider the following area:
248c2ecf20Sopenharmony_ci	* in do_pd_request1(): to calls of pi_do_claimed() and return in
258c2ecf20Sopenharmony_ci	  case when pd_req is NULL.
268c2ecf20Sopenharmony_ci	* in next_request(): to call of do_pd_request1()
278c2ecf20Sopenharmony_ci	* in do_pd_read(): to call of ps_set_intr()
288c2ecf20Sopenharmony_ci	* in do_pd_read_start(): to calls of pi_do_claimed(), next_request()
298c2ecf20Sopenharmony_ciand ps_set_intr()
308c2ecf20Sopenharmony_ci	* in do_pd_read_drq(): to calls of pi_do_claimed() and next_request()
318c2ecf20Sopenharmony_ci	* in do_pd_write(): to call of ps_set_intr()
328c2ecf20Sopenharmony_ci	* in do_pd_write_start(): to calls of pi_do_claimed(), next_request()
338c2ecf20Sopenharmony_ciand ps_set_intr()
348c2ecf20Sopenharmony_ci	* in do_pd_write_done(): to calls of pi_do_claimed() and next_request()
358c2ecf20Sopenharmony_ci	* in ps_set_intr(): to check for ps_tq_active and to scheduling
368c2ecf20Sopenharmony_ci	  ps_tq if ps_tq_active was 0.
378c2ecf20Sopenharmony_ci	* in ps_tq_int(): from the moment when we get ps_spinlock() to the
388c2ecf20Sopenharmony_ci	  return, call of con() or scheduling ps_tq.
398c2ecf20Sopenharmony_ci	* in pi_schedule_claimed() when called from pi_do_claimed() called from
408c2ecf20Sopenharmony_ci	  pd.c, everything until returning 1 or setting or setting ->claim_cont
418c2ecf20Sopenharmony_ci	  on the path that returns 0
428c2ecf20Sopenharmony_ci	* in pi_do_claimed() when called from pd.c, everything until the call
438c2ecf20Sopenharmony_ci	  of pi_do_claimed() plus the everything until the call of cont() if
448c2ecf20Sopenharmony_ci	  pi_do_claimed() has returned 1.
458c2ecf20Sopenharmony_ci	* in pi_wake_up() called for PIA that belongs to pd.c, everything from
468c2ecf20Sopenharmony_ci	  the moment when pi_spinlock has been acquired.
478c2ecf20Sopenharmony_ci
488c2ecf20Sopenharmony_ciLemma 2:
498c2ecf20Sopenharmony_ci	1) at any time at most one thread of execution can be in that area or
508c2ecf20Sopenharmony_ci	be preempted there.
518c2ecf20Sopenharmony_ci	2) When there is such a thread, pd_busy is set or pd_lock is held by
528c2ecf20Sopenharmony_ci	that thread.
538c2ecf20Sopenharmony_ci	3) When there is such a thread, ps_tq_active is 0 or ps_spinlock is
548c2ecf20Sopenharmony_ci	held by that thread.
558c2ecf20Sopenharmony_ci	4) When there is such a thread, all PIA belonging to pd.c have NULL
568c2ecf20Sopenharmony_ci	->claim_cont or pi_spinlock is held by thread in question.
578c2ecf20Sopenharmony_ci
588c2ecf20Sopenharmony_ciProof:	consider the first moment when the above is not true.
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci(1) can become not true if some thread enters that area while another is there.
618c2ecf20Sopenharmony_ci	a) do_pd_request1() can be called from next_request() or do_pd_request()
628c2ecf20Sopenharmony_ci	   In the first case the thread was already in the area.  In the second,
638c2ecf20Sopenharmony_ci	   the thread was holding pd_lock and found pd_busy not set, which would
648c2ecf20Sopenharmony_ci	   mean that (2) was already not true.
658c2ecf20Sopenharmony_ci	b) ps_set_intr() and pi_schedule_claimed() can be called only from the
668c2ecf20Sopenharmony_ci	   area.
678c2ecf20Sopenharmony_ci	c) pi_do_claimed() is called by pd.c only from the area.
688c2ecf20Sopenharmony_ci	d) ps_tq_int() can enter the area only when the thread is holding
698c2ecf20Sopenharmony_ci	   ps_spinlock and ps_tq_active is 1 (due to Lemma 1).  It means that
708c2ecf20Sopenharmony_ci	   (3) was already not true.
718c2ecf20Sopenharmony_ci	e) do_pd_{read,write}* could be called only from the area.  The only
728c2ecf20Sopenharmony_ci	   case that needs consideration is call from pi_wake_up() and there
738c2ecf20Sopenharmony_ci	   we would have to be called for the PIA that got ->claimed_cont
748c2ecf20Sopenharmony_ci	   from pd.c.  That could happen only if pi_do_claimed() had been
758c2ecf20Sopenharmony_ci	   called from pd.c for that PIA, which happens only for PIA belonging
768c2ecf20Sopenharmony_ci	   to pd.c.
778c2ecf20Sopenharmony_ci	f) pi_wake_up() can enter the area only when the thread is holding
788c2ecf20Sopenharmony_ci	   pi_spinlock and ->claimed_cont is non-NULL for PIA belonging to
798c2ecf20Sopenharmony_ci	   pd.c.  It means that (4) was already not true.
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_ci(2) can become not true only when pd_lock is released by the thread in question.
828c2ecf20Sopenharmony_ci	Indeed, pd_busy is reset only in the area and thread that resets
838c2ecf20Sopenharmony_ci	it is holding pd_lock.	The only place within the area where we
848c2ecf20Sopenharmony_ci	release pd_lock is in pd_next_buf() (called from within the area).
858c2ecf20Sopenharmony_ci	But that code does not reset pd_busy, so pd_busy would have to be
868c2ecf20Sopenharmony_ci	0 when pd_next_buf() had acquired pd_lock.  If it become 0 while
878c2ecf20Sopenharmony_ci	we were acquiring the lock, (1) would be already false, since
888c2ecf20Sopenharmony_ci	the thread that had reset it would be in the area simulateously.
898c2ecf20Sopenharmony_ci	If it was 0 before we tried to acquire pd_lock, (2) would be
908c2ecf20Sopenharmony_ci	already false.
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ciFor similar reasons, (3) can become not true only when ps_spinlock is released
938c2ecf20Sopenharmony_ciby the thread in question.  However, all such places within the area are right
948c2ecf20Sopenharmony_ciafter resetting ps_tq_active to 0.
958c2ecf20Sopenharmony_ci
968c2ecf20Sopenharmony_ci(4) is done the same way - all places where we release pi_spinlock within
978c2ecf20Sopenharmony_cithe area are either after resetting ->claimed_cont to NULL while holding
988c2ecf20Sopenharmony_cipi_spinlock, or after not tocuhing ->claimed_cont since acquiring pi_spinlock
998c2ecf20Sopenharmony_cialso in the area.  The only place where ->claimed_cont is made non-NULL is
1008c2ecf20Sopenharmony_ciin the area, under pi_spinlock and we do not release it until after leaving
1018c2ecf20Sopenharmony_cithe area.
1028c2ecf20Sopenharmony_ci
1038c2ecf20Sopenharmony_ciQED.
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ciCorollary 1: ps_tq_active can be killed.  Indeed, the only place where we
1078c2ecf20Sopenharmony_cicheck its value is in ps_set_intr() and if it had been non-zero at that
1088c2ecf20Sopenharmony_cipoint, we would have violated either (2.1) (if it was set while ps_set_intr()
1098c2ecf20Sopenharmony_ciwas acquiring ps_spinlock) or (2.3) (if it was set when we started to
1108c2ecf20Sopenharmony_ciacquire ps_spinlock).
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_ciCorollary 2: ps_spinlock can be killed.  Indeed, Lemma 1 and Lemma 2 show
1138c2ecf20Sopenharmony_cithat the only possible contention is between scheduling ps_tq followed by
1148c2ecf20Sopenharmony_ciimmediate release of spinlock and beginning of execution of ps_tq on
1158c2ecf20Sopenharmony_cianother CPU.
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ciCorollary 3: assignment to pd_busy in do_pd_read_start() and do_pd_write_start()
1188c2ecf20Sopenharmony_cican be killed.  Indeed, we are not holding pd_lock and thus pd_busy is already
1198c2ecf20Sopenharmony_ci1 here.
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ciCorollary 4: in ps_tq_int() uses of con can be replaced with uses of
1228c2ecf20Sopenharmony_cips_continuation, since the latter is changed only from the area.
1238c2ecf20Sopenharmony_ciWe don't need to reset it to NULL, since we are guaranteed that there
1248c2ecf20Sopenharmony_ciwill be a call of ps_set_intr() before we look at ps_continuation again.
1258c2ecf20Sopenharmony_ciWe can remove the check for ps_continuation being NULL for the same
1268c2ecf20Sopenharmony_cireason - the value is guaranteed to be set by the last ps_set_intr() and
1278c2ecf20Sopenharmony_ciwe never pass it NULL.  Assignements in the beginning of ps_set_intr()
1288c2ecf20Sopenharmony_cican be taken to callers as long as they remain within the area.
129