Hi, I see a slide on rules of sleeping for RTOS. It says never sleep in atomic context (holding a lock, disabled interrupts etc.). It did not mention semaphore in a sleeping state. I think semaphore is also an atomic context. It should not sleep when holding a semaphore. Is it right? Thanks,
Are you asking for general rules, or for a specific RTOS?
Most RTOSes have contexts in which it is technically not possible to sleep, hold a lock, or do other things. If you have disabled interrupts or are running in an interrupt handler, you cannot sleep, because to wake up you'd need an interrupt. You cannot wait for another task to give you a resource because the other task needs an interrupt to be scheduled or wake up.
Some RTOSes implement interrupt or scheduler lock as a "kind of semaphore". So when you're holding that kind of semaphore, you cannot sleep.
If it is technically possible to sleep or hold a lock, there may be conventions that forbid it. For example, people expect 'malloc' to be fast, so the implementation of 'malloc' shouldn't sleep while holding the malloc semaphore. But there's nothing technically preventing that.
I am presuming you mean using say usleep() in *nix or Sleep() in Windows.
I don't even think you can sleep with interrupts off or "holding a lock" ( spinlock? something else? isn't a lock a semaphore? ). It doesn't make sense - if interrupts are off, how can you know the clock can run to have the timer for your sleep expire?
The interrupt architecture may be more complex* than on/off, but why would you want those interrupts off? If you can actually answer that, then do it. Otherwise, no.
*see also the 8259 interrupt controller, which queues up interrupts for you. There are others like it.
Since these rules are there to prevent mainly deadlock, you should try it once to see what happens, though - especially if you have a JTAG debugger that allows a break to the processor. Just be aware that the JTAG may not be able to get control in all cases.
That is the general rule. We use semaphores for mainly two things:
- Regulation ( as in the regulator on a clock ).
- Mutex arbitration of resources.
Mutex is covered well in the literature. "Regulation" is when you want to use a semaphore as a red light to another thread. Releasing the semaphore says "okay, go now. Green light."
In the regulation case, it may be that you want to poll a device in a thread and release the semaphore when it's ready. A "better" approach may be to signal the semaphore in an interrupt service routine, but the jitter behavior will be different in the two cases. It's entirely possible to get *lower* jitter - and therefore more latency - by polling.
But which applies depends on much. Learn how to measure these things so you can make informed decisions.
I was working on an embedded system design about 10 years ago when we ran into a very quirky sleep bug. We got 1st silicon back and started bringing up the sytem. Got down to the last known bug which was a very noticable flicker on the color lcd. Firmware engineer started shutting of services one by one to see what was causing it.
He got down to calling the scheduler to see that there was nothing to do,called a delay routine and then went back to the scheduler again.
Flicker was still there.
LCD controller had a dma master to pull its data from dram. It had a counter that started when a dma request was made and ended when it was filled. Its max was saved and usually ran about 80 clocks, It was now reading about 10,000.
Design was our first one to use the ARM1176 so after a few design reviews and some phone calls to Cambridge we found the problem.
The delay routine was a simple load constant and decrement to 0. The constant was 10,000.
The 1176 is in the middle of prefetching dram data in burst mode a cacheline at a time when the delay routine is called. Cache access is passed from prefetch to the execute core and stays there until
the program crosses a cacheline boundry.
The LCD requests data but is stalled because the dram is in the middle of a burst and has to finish it before it can service the new request.
The delay routine is so small that it fits entirely in one cacheline. It takes up to 10,000 cycles before it crosses a line boundry and can finish the burst access.
Solution: Pad out the delay routine to make it bigger.
PS: If you do something like this and don't document it then someday, somebody will hunt you down and kill you.
--------------------------------------- Posted through