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