A question about the softirq implementation in DDE Linux26
Da Zheng
zhengda1936 at gmail.com
Mon Mar 1 09:44:22 CET 2010
Hi,
On 10-3-1 下午4:25, Björn Döbel wrote:
>> I am thinking of using a lock to simulate cli/sti. When local_irq_enable() or
>> local_irq_save() is called, we hold the lock; when local_irq_restore() or
>> local_irq_disable(), we release the lock. We can even provide nested locking
>> support if local_irq_enable() or local_irq_save() is allowed to be called
>> multiple times in the same thread.
>
> A lock does not work - been there, done that. The problem is that you
> can call local_irq_disable() several times and then only call
> local_irq_enable() only once to reset everything, so the semantics are
> different from recursive locks.
I guess you have used locks, but somehow later removed the code, though I didn't
know the reason.
Can't we simulate the same semantics with a lock? If the same thread already
holds the lock, local_irq_disable() does nothing. My implementation for now
works pretty well, at least for the pcnet32 driver. Maybe I miss something
important. Here is my code:
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.
*
* XXX: Up to now, flags was always 0 at this point and
* I assume that this is always the case. Prove?
*/
unsigned long __raw_local_save_flags(void)
{
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);
}
>
> L4Linux uses a threaded lock implementation for that reason, so we'll
> discuss reusing this idea.
What is a threaded lock?
Best regards,
Zheng Da
More information about the l4-hackers
mailing list