diff options
author | Zheng Da <zhengda1936@gmail.com> | 2010-02-28 05:24:57 +0100 |
---|---|---|
committer | Zheng Da <zhengda1936@gmail.com> | 2010-02-28 05:24:57 +0100 |
commit | fbb1c9f5d35a8b89bbebb55a4a49c3da2f189c05 (patch) | |
tree | 478fb31c2121ff8b509f1d0b4ccce6c6f047ba58 | |
parent | f36fe67a1ec4914bef96f0bc8003a5ee0dd08c8c (diff) |
implement cli/sti with a lock.
In order to avoid dead lock caused by spin_lock_irq or
spin_lock_irqsave, I remove irq disabling in them. It's really
unnecessary to do spin_lock_irq and spin_lock_irqsave any more because
interrupt isn't handled in a real interrupt context.
-rw-r--r-- | libdde_linux26/include/linux/spinlock.h | 7 | ||||
-rw-r--r-- | libdde_linux26/lib/src/arch/l4/cli_sti.c | 49 | ||||
-rw-r--r-- | libdde_linux26/lib/src/arch/l4/softirq.c | 16 | ||||
-rw-r--r-- | libdde_linux26/lib/src/net/core/dev.c | 9 |
4 files changed, 56 insertions, 25 deletions
diff --git a/libdde_linux26/include/linux/spinlock.h b/libdde_linux26/include/linux/spinlock.h index ab862f99..7fb7a251 100644 --- a/libdde_linux26/include/linux/spinlock.h +++ b/libdde_linux26/include/linux/spinlock.h @@ -394,7 +394,7 @@ extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); #define read_lock(lock) spin_lock(lock) #define write_lock(lock) spin_lock(lock) -#define spin_lock_irq(lock) local_irq_disable(); spin_lock(lock) +#define spin_lock_irq(lock) spin_lock(lock) #define spin_lock_bh(lock) spin_lock(lock) #define read_lock_irq(lock) spin_lock_irq(lock) #define read_lock_bh(lock) spin_lock_bh(lock) @@ -411,7 +411,7 @@ extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); #define read_unlock(lock) spin_unlock(lock) #define write_unlock(lock) spin_unlock(lock) -#define spin_unlock_irq(lock) spin_unlock(lock); local_irq_enable() +#define spin_unlock_irq(lock) spin_unlock(lock) #define spin_unlock_bh(lock) spin_unlock(lock) #define read_unlock_irq(lock) spin_unlock_irq(lock) #define read_unlock_bh(lock) spin_unlock_bh(lock) @@ -420,7 +420,6 @@ extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); #define spin_lock_irqsave(lock, flags) \ do { \ - local_irq_save(flags); \ spin_lock(lock);\ } while (0); @@ -430,7 +429,6 @@ extern int _atomic_dec_and_lock(atomic_t *atomic, spinlock_t *lock); #define spin_unlock_irqrestore(lock, flags) \ do { \ spin_unlock(lock); \ - local_irq_restore(flags); \ } while (0); #define read_unlock_irqrestore(lock, flags) spin_unlock_irqrestore(lock, flags) @@ -448,7 +446,6 @@ static int __lockfunc spin_trylock(spinlock_t *lock) #define spin_trylock_irqsave(lock, flags) \ ({ \ - local_irq_save(flags); \ spin_trylock(lock) ? \ 1 : ({ local_irq_restore(flags); 0; }); \ }) diff --git a/libdde_linux26/lib/src/arch/l4/cli_sti.c b/libdde_linux26/lib/src/arch/l4/cli_sti.c index 81c4feea..3f5ba4cf 100644 --- a/libdde_linux26/lib/src/arch/l4/cli_sti.c +++ b/libdde_linux26/lib/src/arch/l4/cli_sti.c @@ -4,6 +4,7 @@ /* IRQ lock reference counter */ static atomic_t _refcnt = ATOMIC_INIT(0); +static ddekit_lock_t cli_lock; /* Check whether IRQs are currently disabled. * @@ -15,6 +16,29 @@ int raw_irqs_disabled_flags(unsigned long flags) return ((int)flags > 0); } +/* If it does lock operation successfully, return > 0. Otherwise, 0. */ +static int nested_lock(ddekit_lock_t lock) +{ + int do_lock = 0; + + if (ddekit_lock_try_lock(&lock)) { /* if we cannot lock */ + /* check who hold the lock. */ + if (_ddekit_lock_owner(&lock) != (int) ddekit_thread_myself()) { + /* Someone else holds the lock, + * or by the time I try to lock again, + * the person has release the lock. */ + ddekit_lock_lock(&lock); + do_lock = 1; + } + /* If I hold the lock myself, I don't need to worry + * the lock will be released somewhere before I do it. */ + } + else + do_lock = 2; + + return do_lock; +} + /* Store the current flags state. * * This is done by returning the current refcnt. @@ -24,25 +48,48 @@ int raw_irqs_disabled_flags(unsigned long flags) */ unsigned long __raw_local_save_flags(void) { - return (unsigned long)atomic_read(&_refcnt); + unsigned long flags; + int do_lock = 0; + + if (cli_lock == NULL) + ddekit_lock_init_unlocked(&cli_lock); + /* It's important to do lock here. + * Otherwise, a thread might not get correct flags. */ + do_lock = nested_lock(cli_lock); + flags = (unsigned long)atomic_read(&_refcnt); + if (do_lock) + ddekit_lock_unlock(&cli_lock); + return flags; } /* Restore IRQ state. */ void raw_local_irq_restore(unsigned long flags) { + Assert(cli_lock != NULL); atomic_set(&_refcnt, flags); + if (flags == 0) + ddekit_lock_unlock(&cli_lock); } /* Disable IRQs by grabbing the IRQ lock. */ void raw_local_irq_disable(void) { + struct ddekit_thread *helder; + int is_print = 0; + + if (cli_lock == NULL) + ddekit_lock_init_unlocked(&cli_lock); + + nested_lock(cli_lock); atomic_inc(&_refcnt); } /* Unlock the IRQ lock until refcnt is 0. */ void raw_local_irq_enable(void) { + Assert(cli_lock != NULL); atomic_set(&_refcnt, 0); + ddekit_lock_unlock(&cli_lock); } diff --git a/libdde_linux26/lib/src/arch/l4/softirq.c b/libdde_linux26/lib/src/arch/l4/softirq.c index be13422b..67e8f5aa 100644 --- a/libdde_linux26/lib/src/arch/l4/softirq.c +++ b/libdde_linux26/lib/src/arch/l4/softirq.c @@ -172,8 +172,6 @@ static void tasklet_hi_action(struct softirq_action *a) } } -ddekit_lock_t cli_lock; - #define MAX_SOFTIRQ_RETRIES 10 /** Run softirq handlers @@ -187,8 +185,7 @@ void __do_softirq(void) /* reset softirq count */ set_softirq_pending(0); - ddekit_lock_unlock(&cli_lock); -// local_irq_enable(); + local_irq_enable(); /* While we have a softirq pending... */ while (pending) { @@ -200,8 +197,7 @@ void __do_softirq(void) /* remove pending flag for last softirq */ pending >>= 1; } -// local_irq_disable(); - ddekit_lock_lock(&cli_lock); + local_irq_disable(); /* Somebody might have scheduled another softirq in between * (e.g., an IRQ thread or another tasklet). */ @@ -214,14 +210,10 @@ void do_softirq(void) { unsigned long flags; - if (cli_lock == NULL) - ddekit_lock_init_unlocked(&cli_lock); - ddekit_lock_lock(&cli_lock); -// local_irq_save(flags); + local_irq_save(flags); if (local_softirq_pending()) __do_softirq(); -// local_irq_restore(flags); - ddekit_lock_unlock(&cli_lock); + local_irq_restore(flags); } /** Softirq thread function. diff --git a/libdde_linux26/lib/src/net/core/dev.c b/libdde_linux26/lib/src/net/core/dev.c index 128f4d73..64917332 100644 --- a/libdde_linux26/lib/src/net/core/dev.c +++ b/libdde_linux26/lib/src/net/core/dev.c @@ -2611,16 +2611,11 @@ out: void __napi_schedule(struct napi_struct *n) { unsigned long flags; - extern ddekit_lock_t cli_lock; - if (cli_lock == NULL) - ddekit_lock_init_unlocked(&cli_lock); - ddekit_lock_lock(&cli_lock); -// local_irq_save(flags); + local_irq_save(flags); list_add_tail(&n->poll_list, &__get_cpu_var(softnet_data).poll_list); __raise_softirq_irqoff(NET_RX_SOFTIRQ); -// local_irq_restore(flags); - ddekit_lock_unlock(&cli_lock); + local_irq_restore(flags); } EXPORT_SYMBOL(__napi_schedule); |