From 8a6d48c0542876eb3acfc0970c0ab7872db08d5f Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 6 Dec 2009 05:26:23 +0100 Subject: check in the original version of dde linux26. --- libdde_linux26/lib/src/arch/l4/softirq.c | 267 +++++++++++++++++++++++++++++++ 1 file changed, 267 insertions(+) create mode 100644 libdde_linux26/lib/src/arch/l4/softirq.c (limited to 'libdde_linux26/lib/src/arch/l4/softirq.c') diff --git a/libdde_linux26/lib/src/arch/l4/softirq.c b/libdde_linux26/lib/src/arch/l4/softirq.c new file mode 100644 index 00000000..21b36d17 --- /dev/null +++ b/libdde_linux26/lib/src/arch/l4/softirq.c @@ -0,0 +1,267 @@ +#include "local.h" + +#include + +/* There are at most 32 softirqs in Linux, but only 6 are really used. */ +#define NUM_SOFTIRQS 6 + +DECLARE_INITVAR(dde26_softirq); + +/* softirq threads and their wakeup semaphores */ +ddekit_thread_t *dde_softirq_thread; +ddekit_sem_t *dde_softirq_sem; + +/* struct tasklet_head is not defined in a header in Linux 2.6 */ +struct tasklet_head +{ + struct tasklet_struct *list; + ddekit_lock_t lock; /* list lock */ +}; + +/* What to do if a softirq occurs. */ +static struct softirq_action softirq_vec[32]; + +/* tasklet queues for each softirq thread */ +struct tasklet_head tasklet_vec; +struct tasklet_head tasklet_hi_vec; + +void open_softirq(int nr, void (*action)(struct softirq_action*)) +{ + softirq_vec[nr].action = action; +} + +static void raise_softirq_irqoff_cpu(unsigned int nr, unsigned int cpu) +{ + CHECK_INITVAR(dde26_softirq); + + /* mark softirq scheduled */ + __raise_softirq_irqoff(nr); + /* wake softirq thread */ + ddekit_sem_up(dde_softirq_sem); +} + +void raise_softirq_irqoff(unsigned int nr) +{ + raise_softirq_irqoff_cpu(nr, 0); +} + +void raise_softirq(unsigned int nr) +{ + unsigned long flags; + + local_irq_save(flags); + raise_softirq_irqoff(nr); + local_irq_restore(flags); +} + +/** + * Initialize tasklet. + */ +void tasklet_init(struct tasklet_struct *t, + void (*func)(unsigned long), unsigned long data) +{ + t->next = NULL; + t->state = 0; + atomic_set(&t->count, 0); + t->func = func; + t->data = data; +} + +/* enqueue tasklet */ +static void __tasklet_enqueue(struct tasklet_struct *t, + struct tasklet_head *listhead) +{ + ddekit_lock_lock(&listhead->lock); + t->next = listhead->list; + listhead->list = t; + ddekit_lock_unlock(&listhead->lock); +} + +void __tasklet_schedule(struct tasklet_struct *t) +{ + unsigned long flags; + + CHECK_INITVAR(dde26_softirq); + + local_irq_save(flags); + + __tasklet_enqueue(t, &tasklet_vec); + /* raise softirq */ + raise_softirq_irqoff_cpu(TASKLET_SOFTIRQ, 0); + + local_irq_restore(flags); +} + +void __tasklet_hi_schedule(struct tasklet_struct *t) +{ + unsigned long flags; + + CHECK_INITVAR(dde26_softirq); + + local_irq_save(flags); + __tasklet_enqueue(t, &tasklet_hi_vec); + raise_softirq_irqoff_cpu(HI_SOFTIRQ, 0); + local_irq_restore(flags); +} + +/* Execute tasklets */ +static void tasklet_action(struct softirq_action *a) +{ + struct tasklet_struct *list; + + ddekit_lock_lock(&tasklet_vec.lock); + list = tasklet_vec.list; + tasklet_vec.list = NULL; + ddekit_lock_unlock(&tasklet_vec.lock); + + while (list) { + struct tasklet_struct *t = list; + + list = list->next; + + if (tasklet_trylock(t)) { + if (!atomic_read(&t->count)) { + if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) + BUG(); + t->func(t->data); + tasklet_unlock(t); + continue; + } + tasklet_unlock(t); + } + + ddekit_lock_lock(&tasklet_vec.lock); + t->next = tasklet_vec.list; + tasklet_vec.list = t; + raise_softirq_irqoff_cpu(TASKLET_SOFTIRQ, 0); + ddekit_lock_unlock(&tasklet_vec.lock); + } +} + + +static void tasklet_hi_action(struct softirq_action *a) +{ + struct tasklet_struct *list; + + ddekit_lock_lock(&tasklet_hi_vec.lock); + list = tasklet_hi_vec.list; + tasklet_hi_vec.list = NULL; + ddekit_lock_unlock(&tasklet_hi_vec.lock); + + while (list) { + struct tasklet_struct *t = list; + + list = list->next; + + if (tasklet_trylock(t)) { + if (!atomic_read(&t->count)) { + if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) + BUG(); + t->func(t->data); + tasklet_unlock(t); + continue; + } + tasklet_unlock(t); + } + + ddekit_lock_lock(&tasklet_hi_vec.lock); + t->next = tasklet_hi_vec.list; + tasklet_hi_vec.list = t; + raise_softirq_irqoff_cpu(HI_SOFTIRQ, 0); + ddekit_lock_unlock(&tasklet_hi_vec.lock); + } +} + + +#define MAX_SOFTIRQ_RETRIES 10 + +/** Run softirq handlers + */ +void __do_softirq(void) +{ + int retries = MAX_SOFTIRQ_RETRIES; + do { + struct softirq_action *h = softirq_vec; + unsigned long pending = local_softirq_pending(); + + /* reset softirq count */ + set_softirq_pending(0); + + /* While we have a softirq pending... */ + while (pending) { + /* need to execute current softirq? */ + if (pending & 1) + h->action(h); + /* try next softirq */ + h++; + /* remove pending flag for last softirq */ + pending >>= 1; + } + + /* Somebody might have scheduled another softirq in between + * (e.g., an IRQ thread or another tasklet). */ + } while (local_softirq_pending() && --retries); + +} + + +void do_softirq(void) +{ + unsigned long flags; + + local_irq_save(flags); + if (local_softirq_pending()) + __do_softirq(); + local_irq_restore(flags); +} + +/** Softirq thread function. + * + * Once started, a softirq thread waits for tasklets to be scheduled + * and executes them. + * + * \param arg # of this softirq thread so that it grabs the correct lock + * if multiple softirq threads are running. + */ +void l4dde26_softirq_thread(void *arg) +{ + printk("Softirq daemon starting\n"); + l4dde26_process_add_worker(); + + /* This thread will always be in a softirq, so set the + * corresponding flag right now. + */ + preempt_count() |= SOFTIRQ_MASK; + + while(1) { + ddekit_sem_down(dde_softirq_sem); + do_softirq(); + } +} + +/** Initialize softirq subsystem. + * + * Start NUM_SOFTIRQ_THREADS threads executing the \ref l4dde26_softirq_thread + * function. + */ +void l4dde26_softirq_init(void) +{ + char name[20]; + + dde_softirq_sem = ddekit_sem_init(0); + + set_softirq_pending(0); + + ddekit_lock_init_unlocked(&tasklet_vec.lock); + ddekit_lock_init_unlocked(&tasklet_hi_vec.lock); + + snprintf(name, 20, ".softirqd"); + dde_softirq_thread = ddekit_thread_create( + l4dde26_softirq_thread, + NULL, name); + + open_softirq(TASKLET_SOFTIRQ, tasklet_action); + open_softirq(HI_SOFTIRQ, tasklet_hi_action); + + INITIALIZE_INITVAR(dde26_softirq); +} -- cgit v1.2.3 From a4bb3955579991dfb1ef5b8ffcc498b54671351e Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sat, 27 Feb 2010 15:46:25 +0100 Subject: Use lock to protect pending softirq variable. This is a temporary solution. I should implement a correct mechanism to simulate cli/sti. --- libdde_linux26/lib/src/arch/l4/softirq.c | 13 +++++++++++-- libdde_linux26/lib/src/net/core/dev.c | 9 +++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) (limited to 'libdde_linux26/lib/src/arch/l4/softirq.c') diff --git a/libdde_linux26/lib/src/arch/l4/softirq.c b/libdde_linux26/lib/src/arch/l4/softirq.c index 21b36d17..be13422b 100644 --- a/libdde_linux26/lib/src/arch/l4/softirq.c +++ b/libdde_linux26/lib/src/arch/l4/softirq.c @@ -172,6 +172,7 @@ static void tasklet_hi_action(struct softirq_action *a) } } +ddekit_lock_t cli_lock; #define MAX_SOFTIRQ_RETRIES 10 @@ -186,6 +187,8 @@ void __do_softirq(void) /* reset softirq count */ set_softirq_pending(0); + ddekit_lock_unlock(&cli_lock); +// local_irq_enable(); /* While we have a softirq pending... */ while (pending) { @@ -197,6 +200,8 @@ void __do_softirq(void) /* remove pending flag for last softirq */ pending >>= 1; } +// local_irq_disable(); + ddekit_lock_lock(&cli_lock); /* Somebody might have scheduled another softirq in between * (e.g., an IRQ thread or another tasklet). */ @@ -209,10 +214,14 @@ void do_softirq(void) { unsigned long flags; - local_irq_save(flags); + if (cli_lock == NULL) + ddekit_lock_init_unlocked(&cli_lock); + ddekit_lock_lock(&cli_lock); +// local_irq_save(flags); if (local_softirq_pending()) __do_softirq(); - local_irq_restore(flags); +// local_irq_restore(flags); + ddekit_lock_unlock(&cli_lock); } /** Softirq thread function. diff --git a/libdde_linux26/lib/src/net/core/dev.c b/libdde_linux26/lib/src/net/core/dev.c index 64917332..128f4d73 100644 --- a/libdde_linux26/lib/src/net/core/dev.c +++ b/libdde_linux26/lib/src/net/core/dev.c @@ -2611,11 +2611,16 @@ out: void __napi_schedule(struct napi_struct *n) { unsigned long flags; + extern ddekit_lock_t cli_lock; - local_irq_save(flags); + if (cli_lock == NULL) + ddekit_lock_init_unlocked(&cli_lock); + ddekit_lock_lock(&cli_lock); +// 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); +// local_irq_restore(flags); + ddekit_lock_unlock(&cli_lock); } EXPORT_SYMBOL(__napi_schedule); -- cgit v1.2.3 From fbb1c9f5d35a8b89bbebb55a4a49c3da2f189c05 Mon Sep 17 00:00:00 2001 From: Zheng Da Date: Sun, 28 Feb 2010 05:24:57 +0100 Subject: 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. --- libdde_linux26/include/linux/spinlock.h | 7 ++--- libdde_linux26/lib/src/arch/l4/cli_sti.c | 49 +++++++++++++++++++++++++++++++- libdde_linux26/lib/src/arch/l4/softirq.c | 16 +++-------- libdde_linux26/lib/src/net/core/dev.c | 9 ++---- 4 files changed, 56 insertions(+), 25 deletions(-) (limited to 'libdde_linux26/lib/src/arch/l4/softirq.c') 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); -- cgit v1.2.3