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