summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZheng Da <zhengda1936@gmail.com>2010-02-28 05:24:57 +0100
committerZheng Da <zhengda1936@gmail.com>2010-02-28 05:24:57 +0100
commitfbb1c9f5d35a8b89bbebb55a4a49c3da2f189c05 (patch)
tree478fb31c2121ff8b509f1d0b4ccce6c6f047ba58
parentf36fe67a1ec4914bef96f0bc8003a5ee0dd08c8c (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.h7
-rw-r--r--libdde_linux26/lib/src/arch/l4/cli_sti.c49
-rw-r--r--libdde_linux26/lib/src/arch/l4/softirq.c16
-rw-r--r--libdde_linux26/lib/src/net/core/dev.c9
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);