diff options
author | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2011-11-06 21:03:30 +0100 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2011-11-06 21:03:30 +0100 |
commit | 587ca4c991338a72f6a02407dd5b2809fc07dd27 (patch) | |
tree | f76655feafb2a46541406d62d04dccad78e3ef32 /libdde_linux26/lib | |
parent | 55f9e891d5ba9c3eb504cb0fd4e855298381db6c (diff) |
Fix unlocking in raw_local_irq_restore inside a fake_local_irq_disable/restore
* libdde_linux26/lib/src/arch/l4/cli_sti.c (unlock_refcnt): New variable.
(raw_local_irq_restore): Unlock `cli_lock' when `flags' are equal to
`unlock_refcnt' (and clear the latter).
(raw_local_irq_disable): If `cli_lock' was not locked, save the current
value of `_refcnt' into `unlock_refcnt', unless the former is already
smaller than the latter.
Diffstat (limited to 'libdde_linux26/lib')
-rw-r--r-- | libdde_linux26/lib/src/arch/l4/cli_sti.c | 26 |
1 files changed, 21 insertions, 5 deletions
diff --git a/libdde_linux26/lib/src/arch/l4/cli_sti.c b/libdde_linux26/lib/src/arch/l4/cli_sti.c index 051f2598..e55e6401 100644 --- a/libdde_linux26/lib/src/arch/l4/cli_sti.c +++ b/libdde_linux26/lib/src/arch/l4/cli_sti.c @@ -4,6 +4,8 @@ /* IRQ lock reference counter */ static atomic_t _refcnt = ATOMIC_INIT(0); +/* Refcnt value at which unlocking the cli_lock (it's not always 0) */ +static int unlock_refcnt; static ddekit_lock_t cli_lock; /* Check whether IRQs are currently disabled. @@ -57,9 +59,6 @@ void fake_local_irq_restore(unsigned long flags) /* 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) { @@ -82,8 +81,10 @@ void raw_local_irq_restore(unsigned long flags) { Assert(cli_lock != NULL); atomic_set(&_refcnt, flags); - if (flags == 0) + if (flags == unlock_refcnt) { ddekit_lock_unlock(&cli_lock); + unlock_refcnt = 0; + } } /* Disable IRQs by grabbing the IRQ lock. */ @@ -95,7 +96,22 @@ void raw_local_irq_disable(void) if (cli_lock == NULL) ddekit_lock_init_unlocked(&cli_lock); - nested_lock(cli_lock); + if (nested_lock(cli_lock)) { + /* Tell the corresponding restorer to release cli_lock, + * but do not update the value if there has been a re-enable in + * between, that would store a bogus value. + * XXX: scenario that will still break: + * save + * disable + * enable + * save + * disable + * restore + * restore + */ + if (unlock_refcnt < atomic_read(&_refcnt)) + unlock_refcnt = atomic_read(&_refcnt); + } atomic_inc(&_refcnt); } |