diff options
author | Richard Braun <rbraun@sceen.net> | 2013-11-06 01:44:09 +0100 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2013-11-06 01:44:09 +0100 |
commit | 218cae5a714342b5d82a5b004d58f0a9ebbbfe5e (patch) | |
tree | 620c7d730f94bf66e28b21a9a5d96b2426d2f05d /pfinet | |
parent | 880dd56f468b57a198ab2136767d03ddaa586eef (diff) |
pfinet: fix emission on the loopback device
Unlike other devices, sending packets on the loopback device causes the
netif_rx() function to be called from the net_bh worker thread. Since
the thread is already running, it can't wake itself up when calling
mark_bh(). Use a new variable to indicate when net_bh work is pending.
* glue-include/linux/interrupt.h (net_bh_raised): Declare new global
variable.
(mark_bh): Set net_bh_raised to 1 before waking up net_bh worker thread.
* loopback.c (loopback_xmit): Add comment giving details about locking.
* sched.c (net_bh_raised): Define new global variable.
(net_bh_worker): Wait for net_bh_raised to become true and reset it
before processing net_bh work.
Diffstat (limited to 'pfinet')
-rw-r--r-- | pfinet/glue-include/linux/interrupt.h | 2 | ||||
-rw-r--r-- | pfinet/loopback.c | 7 | ||||
-rw-r--r-- | pfinet/sched.c | 7 |
3 files changed, 15 insertions, 1 deletions
diff --git a/pfinet/glue-include/linux/interrupt.h b/pfinet/glue-include/linux/interrupt.h index df58d2f4..22312ba4 100644 --- a/pfinet/glue-include/linux/interrupt.h +++ b/pfinet/glue-include/linux/interrupt.h @@ -21,6 +21,7 @@ extern pthread_mutex_t net_bh_lock; /* See sched.c::net_bh_worker comments. */ extern pthread_cond_t net_bh_wakeup; +extern int net_bh_raised; #define NET_BH 0xb00bee51 @@ -30,6 +31,7 @@ static inline void mark_bh (int bh) { assert (bh == NET_BH); + net_bh_raised = 1; pthread_cond_broadcast (&net_bh_wakeup); } diff --git a/pfinet/loopback.c b/pfinet/loopback.c index 068cf3c8..e15e4265 100644 --- a/pfinet/loopback.c +++ b/pfinet/loopback.c @@ -71,6 +71,13 @@ static int loopback_xmit(struct sk_buff *skb, struct device *dev) #ifndef LOOPBACK_MUST_CHECKSUM skb->ip_summed = CHECKSUM_UNNECESSARY; #endif + + /* + * Calling netif_rx() requires locking net_bh_lock, which + * has already been done since this function is called by + * the net_bh worker thread. + */ + netif_rx(skb); stats->rx_bytes+=skb->len; diff --git a/pfinet/sched.c b/pfinet/sched.c index 89927741..af03ab49 100644 --- a/pfinet/sched.c +++ b/pfinet/sched.c @@ -26,6 +26,7 @@ pthread_mutex_t global_lock = PTHREAD_MUTEX_INITIALIZER; pthread_mutex_t net_bh_lock = PTHREAD_MUTEX_INITIALIZER; pthread_cond_t net_bh_wakeup = PTHREAD_COND_INITIALIZER; +int net_bh_raised = 0; struct task_struct current_contents; /* zeros are right default values */ @@ -61,7 +62,11 @@ net_bh_worker (void *arg) pthread_mutex_lock (&net_bh_lock); while (1) { - pthread_cond_wait (&net_bh_wakeup, &net_bh_lock); + while (!net_bh_raised) + pthread_cond_wait (&net_bh_wakeup, &net_bh_lock); + + net_bh_raised = 0; + pthread_mutex_lock (&global_lock); net_bh (); pthread_mutex_unlock (&global_lock); |