| View previous topic :: View next topic |
| Author |
Message |
Guest
|
Posted: Tue Jun 24, 2008 11:13 am Post subject: accessing code from thread and interrupt context on MP machi |
|
|
Is it possible to access a critical section of code from both multiple
threads (running on N processors) and interrupt context? For a
uniprocessor machine, a simple cli instruction will protect between
interrupt and thread context, but for multiprocessor machines, where
each CPU is capable of accessing the critical section, I'm guessing
you would have to do the following:
cli
acquire a spinlock
/*Critical code */
release the spinlock
sti
However, it seems like a bad idea, since what if process A on CPU A
executes the cli, but process B on CPU B already has the spinlock,
meaning that the CPU A is now stalled (with interrupts disabled) until
process B releases the spinlock. Even then, there is no guarantee
that A will ever acquire the spinlock, especially if there is high
contention for the lock over multiple processors. Although unlikely
that CPU A would be starved forever, but possibly may be a significant
latency.
Is it therefore generally the practice that crit sections only be
accessible from interrupt/_local_ thread context OR thread/thread
context?
Regards,B. |
|
| Back to top |
|
 |
| |
Ads |
Advertising
Sponsor
|
|
Alexei A. Frounze Guest
|
Posted: Tue Jun 24, 2008 11:39 am Post subject: Re: accessing code from thread and interrupt context on MP m |
|
|
On Jun 24, 4:13 am, boroph...@gmail.com wrote:
| Quote: |
Is it possible to access a critical section of code from both multiple
threads (running on N processors) and interrupt context? For a
uniprocessor machine, a simple cli instruction will protect between
interrupt and thread context, but for multiprocessor machines, where
each CPU is capable of accessing the critical section, I'm guessing
you would have to do the following:
cli
acquire a spinlock
/*Critical code */
release the spinlock
sti
However, it seems like a bad idea, since what if process A on CPU A
executes the cli, but process B on CPU B already has the spinlock,
meaning that the CPU A is now stalled (with interrupts disabled) until
process B releases the spinlock. Even then, there is no guarantee
that A will ever acquire the spinlock, especially if there is high
contention for the lock over multiple processors. Although unlikely
that CPU A would be starved forever, but possibly may be a significant
latency.
Is it therefore generally the practice that crit sections only be
accessible from interrupt/_local_ thread context OR thread/thread
context?
Regards,B.
|
What you can do is:
1. minimize the work done in the ISRs and move out of them as much as
possible to threads. That way no other interrupts will be disabled for
a long time anywhere.
2. if there isn't a lot of contention and you can allow for a latency
in the communication, don't let the thread spin on the spinlock
forever. Do N spins, then put the thread to sleep for X microseconds,
then spin again and so on until the lock is acquired.
3. if it's only a matter of exchanging information between 2 entities,
then you can implement a non-blocking ring buffer (ISR writes to it,
thread reads from it or vice versa, but only one reader and one
writer) using 2 atomically updated pointers/indices. No interrupts to
disable, no locks to acquire.
Alex |
|
| Back to top |
|
 |
| |
Ads |
Advertising
Sponsor
|
|
Brendan Guest
|
Posted: Tue Jun 24, 2008 4:28 pm Post subject: Re: accessing code from thread and interrupt context on MP m |
|
|
Hi,
On Jun 24, 8:13 pm, boroph...@gmail.com wrote:
| Quote: |
Is it possible to access a critical section of code from both multiple
threads (running on N processors) and interrupt context?
|
Yes, but if you can avoid doing it I'd recommend avoiding doing it
(see Alex's post). :-)
Unfortunately in some situations you can't avoid it....
There is something you'd need to consider first - the order you do
things.
Basically you *shouldn't* do this:
cli
acquire a spinlock
/*Critical code */
release the spinlock
sti
The problem here is lock contention - you're spinning (potentially for
a relatively long time) with interrupts disabled. The end result is
that you can't guarantee that you'll be able to handle IRQs fast
enough (even completely unrelated IRQs).
Also, you *can't* do this:
acquire a spinlock
cli
/*Critical code */
sti
release the spinlock
The problem here is that you can acquire the lock and get an IRQ
before you execute the CLI, and the IRQ might try to acquire the same
lock. This leads to a deadlock in the middle of an IRQ handler (oops).
This would also be one of those insidious bugs, where your code locks
up after running well for several months (where there's an extremely
small chance of ever finding the cause of problem).
The way to do it properly is to disable IRQs and acquire the lock at
the same time. For example:
..testLock:
bt [myLock],0 ;Is the lock free?
jnc .tryLock ; yes, try to acquire it
pause ;Do some nothing for Pentium 4 CPUs
jmp .testLock ;Loop until the lock is free
..tryLock:
cli
lock bts [myLock],0 ;Can I have the lock?
jnc .gotLock ; yes!
sti ; no, wait until it's free
before locking the bus again
jmp .testLock
..gotLock:
In this case the code to release the lock is fairly simple - "btr
[myLock],0" (or "mov [myLock],0") followed by "sti". Here, you can't
do "sti" and then do "btr [myLock],0" because you could get an IRQ
before the lock is released (deadlock again).
Note: If a lock may be acquired by any IRQ handler, then all attempts
to acquire and release the lock must use the "CLI/STI" version of the
lock/unlock code (including code that isn't part of any IRQ handler
and isn't called by any IRQ handler). If you don't follow this simple
rule your IRQ handlers can/will lock-up (deadlock).
I normally use macros for the acquire/release code - for e.g. one
macro for acquiring normal spinlocks, one macro for acquiring "IRQ
spinlocks", one macro for releasing normal spinlocks and one macro for
releasing "IRQ spinlocks".
Also, in my experience "good" spinlock code isn't good until you
instrument it to detect errors. For a simple example (releasing a
lock), consider something like:
%ifdef DEBUGGING
btr [myLock],0
sti
jnc CRITICAL_ERROR_lockReleaseWithoutAcquire
%else
mov [myLock],0
sti
%endif
It's possible to detect other things too; like some types of deadlock
(same CPU trying to acquire a lock a second time), inappropriate lock
release (different CPU trying to free a lock), using the wrong acquire/
release code for the lock type, and lock corruption (unused bits that
are non-zero). That way a kernel developer could end up with something
like a "blue screen of death" when they mess up re-entrancy locks,
which makes debugging much much easier...
Cheers,
Brendan |
|
| Back to top |
|
 |
| |
Ads |
Advertising
Sponsor
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|

130 Attacks blocked
Powered by phpBB © 2001, 2005 phpBB Group
|