confusing code....whats the point of this construct ?

Nicholas Mc Guire der.herr at hofr.at
Wed Mar 11 12:46:56 EDT 2015


On Wed, 11 Mar 2015, Bj??rn Mork wrote:

> Valdis.Kletnieks at vt.edu writes:
> 
> > On Wed, 11 Mar 2015 15:17:44 +0100, Nicholas Mc Guire said:
> >
> >> So the wait_event_timeout condition here ends up being (empty || skip)
> >> but what is the point of puting this code into the parameter list of
> >> wait_event_timeout() ?
> >>
> >> Would it not be equivalent to:
> >>
> >> 	bool empty;
> >> 	...
> >>
> >> 	spin_lock_bh(&ar->htt.tx_lock);
> >> 	empty = (ar->htt.num_pending_tx == 0);
> >> 	spin_unlock_bh(&ar->htt.tx_lock);
> >>
> >> 	skip = (ar->state == ATH10K_STATE_WEDGED) ||
> >> 		test_bit(ATH10K_FLAG_CRASH_FLUSH,
> >> 		&ar->dev_flags);
> >>
> >> 	ret = wait_event_timeout(ar->htt.empty_tx_wq, (empty || skip),
> >> 				 ATH10K_FLUSH_TIMEOUT_HZ);
> >>
> >> What am I missing here ?
> >
> > Umm... a Signed-off-by: and formatting it as an actual patch? :)
> >
> > Seriously - you're right, it's ugly code that needs fixing...
> 
> Huh?
> 
> The condition needs to be re-evaluated every time the process wakes up.
> Evaluating it once and then reusing that result is not the same.
> Something elseis supposed to modify ar->htt.num_pending_tx, ar->state or
> ar->dev_flags while we are waiting.
>
after picking appart the mac.i file I see what you mean
(a bit reformated to make it kind of readable)
 
ret = ({ long __ret = (5*250); 
        do { _cond_resched(); } while (0);
 	if (!({ 
		bool __cond = (({ 
			bool empty; 
			spin_lock_bh(&ar->htt.tx_lock); 
			empty = (ar->htt.num_pending_tx == 0); 
			spin_unlock_bh(&ar->htt.tx_lock); 
			skip = (ar->state == ATH10K_STATE_WEDGED) || 
			    (__builtin_constant_p((ATH10K_FLAG_CRASH_FLUSH)) ? 
				constant_test_bit((ATH10K_FLAG_CRASH_FLUSH), 
				(&ar->dev_flags)) : 
			    variable_test_bit((ATH10K_FLAG_CRASH_FLUSH), 
				(&ar->dev_flags))); 
			(empty || skip); 
		})); 
		if (__cond && !__ret) 
			__ret = 1; 
		__cond || !__ret; 
	})) 
	__ret = ({ __label__ __out; 
		 wait_queue_t __wait; 
		 long __ret = (5*250); 
		 INIT_LIST_HEAD(&__wait.task_list); 
		 if (0) 
			__wait.flags = 0x01; 
		 else 
			__wait.flags = 0; 
		 for (;;) { 
			long __int = prepare_to_wait_event(&ar->htt.empty_tx_wq,
							   &__wait, 2); 
			if (({ 
				bool __cond = (({ 
					bool empty; 
					spin_lock_bh(&ar->htt.tx_lock); 
					empty = (ar->htt.num_pending_tx == 0); 
					spin_unlock_bh(&ar->htt.tx_lock); 
					skip = (ar->state == ATH10K_STATE_WEDGED) || (__builtin_constant_p((ATH10K_FLAG_CRASH_FLUSH)) ? constant_test_bit((ATH10K_FLAG_CRASH_FLUSH), (&ar->dev_flags)) : variable_test_bit((ATH10K_FLAG_CRASH_FLUSH), (&ar->dev_flags))); 
					(empty || skip); 
				})); 
i				if (__cond && !__ret) 
					__ret = 1; 
				__cond || !__ret; 
			})) 
			break; 
			if ((!__builtin_constant_p(2) || 2 == 1 || 2 == (128 | 2)) && __int) { 
				__ret = __int; 
				if (0) { 
					abort_exclusive_wait(&ar->htt.empty_tx_wq, &__wait, 2, ((void *)0)); 
					goto __out; 
				} 
				break; 
			} 
			__ret = schedule_timeout(__ret); 
		} 
		finish_wait(&ar->htt.empty_tx_wq, &__wait); 
__out: 
		__ret; 
	}); 
	__ret; 
})


So the for(;;){ ... } is the part I missed at first.

but never the less the code should then pack up the inner block into a 
static function and pass it to wait_event_timeout rather than
putting the basic block into the parameter list e.g. like in
drivers/gpu/drm/drm_dp_mst_topology.c:drm_dp_mst_wait_tx_reply()

static bool check_txmsg_state(struct drm_dp_mst_topology_mgr *mgr,
                              struct drm_dp_sideband_msg_tx *txmsg)
{
        bool ret;
        mutex_lock(&mgr->qlock);
        ret = (txmsg->state == DRM_DP_SIDEBAND_TX_RX ||
               txmsg->state == DRM_DP_SIDEBAND_TX_TIMEOUT);
        mutex_unlock(&mgr->qlock);
        return ret;
}

drm_dp_mst_wait_tx_reply()
<snip>
        ret = wait_event_timeout(mgr->tx_waitq,
                                 check_txmsg_state(mgr, txmsg),
                                 (4 * HZ));
<snip>


which is readable and achieves the same purpose. something like
the below quick shot:


diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c
index e8cc19f..7b27d99 100644
--- a/drivers/net/wireless/ath/ath10k/mac.c
+++ b/drivers/net/wireless/ath/ath10k/mac.c
@@ -4463,11 +4463,25 @@ static int ath10k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
 	return ret;
 }
 
+static bool check_htt_state (struct ath10k *ar, bool skip)
+{
+	bool empty; 
+
+	spin_lock_bh(&ar->htt.tx_lock); 
+	empty = (ar->htt.num_pending_tx == 0); 
+	spin_unlock_bh(&ar->htt.tx_lock); 
+
+	skip = (ar->state == ATH10K_STATE_WEDGED) ||
+		test_bit(ATH10K_FLAG_CRASH_FLUSH,
+			&ar->dev_flags);
+	return (empty || skip);
+}
+
 static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 			 u32 queues, bool drop)
 {
 	struct ath10k *ar = hw->priv;
-	bool skip;
+	bool skip = false;
 	int ret;
 
 	/* mac80211 doesn't care if we really xmit queued frames or not
@@ -4480,19 +4494,9 @@ static void ath10k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
 	if (ar->state == ATH10K_STATE_WEDGED)
 		goto skip;
 
-	ret = wait_event_timeout(ar->htt.empty_tx_wq, ({
-			bool empty;
-
-			spin_lock_bh(&ar->htt.tx_lock);
-			empty = (ar->htt.num_pending_tx == 0);
-			spin_unlock_bh(&ar->htt.tx_lock);
-
-			skip = (ar->state == ATH10K_STATE_WEDGED) ||
-			       test_bit(ATH10K_FLAG_CRASH_FLUSH,
-					&ar->dev_flags);
-
-			(empty || skip);
-		}), ATH10K_FLUSH_TIMEOUT_HZ);
+	ret = wait_event_timeout(ar->htt.empty_tx_wq, 
+				 check_htt_state(ar, skip),
+				 ATH10K_FLUSH_TIMEOUT_HZ);
 
 	if (ret <= 0 || skip)
 		ath10k_warn(ar, "failed to flush transmit queue (skip %i ar-state %i): %i\n",
-- 
1.7.10.4

 
not yet sure if its correct though just wrapped it into a function and 
compile checked it... and the if (ret <= 0 ... also needs fixing as 
wait_event_timeout returns >= 0 always.

thanks for the clarification - think I got it this time.

thx!
hofrat



More information about the Kernelnewbies mailing list