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