Re: semtake function in ISR



I don't usually yell, but what you are doing screams to me as BAD
CODING PRACTICE!! DANGER WILL ROBINSON, DANGER!!

Now that I have your attention, here is my reasoning. Feel free to
yell and scream at me if anyone believes I am wrong.

I was going to go on about why one should not call semTake() in an
ISR, but upon closer inspection, it is being called from task-level.

I don't think this will work as you expect, and I expect that if you
keep it, you will encounter some strange bizarre effects that you are
not expecting. Unexpected strange and bizarre events are seldom a
good thing when it comes to software.

I shall attempt to illustrate.

#1.
Each task and ISR context keeps track of the various processor flags,
including whether interrupts are enabled or disabled. On the x86
processors, that information is packaged in the EFLAGS register. Now,
lets imagine the following scenario.
- Two tasks are ready to run: taskA and taskB. Neither have locked
interrupts.
- TaskA is scheduled to run. It locks interrupts. Then it calls
semTake(semId, WAIT_FOREVER).
- TaskA gets the semaphore and continues chugging along, eventually
unlocking interrupts.
This looks good, right? Wrong! But what could be wrong? The answer
to that lies in the time between when it requested a lock on the
semaphore and the time at which it got it. TaskA could have blocked.
In this example, if it blocked taskB would run and it would have
interrupts enabled! Remember, taskB has its own EFLAGS register which
is loaded when the task context switch occurs. So when taskB
executes, it will enable interrupts for its duration. During that
period, interrupts may go off and be serviced.
Thus, don't expect that if you lock interrupts and call a blockable
routine that interrupts will stay locked until you get your resource.

#2. In this post, you do not mention what version of VxWorks you are
using. At one time for the 5.x versions (I assume it still exists for
6.x) there was a note that said if you lock interrupts don't make a
kernel call as upon returning from the kernel call, the interrupts
are not guaranteed to be locked. This is because many of the kernel
routines would lock interrupts at some point themselves without saving
the previous state--they effectively assumed that they were unlocked
prior to being called. This particular issue was generally limitted
to architecture specific implementations. Some of them had been
fixed, but I can not say if all of them have.

Those are the two big reasons why you should generally avoid locking
interrupts and then blocking.

If you know why you can't call an semaphore from within an ISR, ignore
the rest of this post. If not, read on.

If you are a newbie to VxWorks, here are the reasons why semTake()
should not be called from VxWorks.
- Taking a semaphore is a blockable operation. The rule of thumb
is, when in an interrupt do not block. This is why the manuals have a
list of acceptable VxWorks routines that can be called from an ISR.

But wait, what if the NO_WAIT (0) option is used as the timeout. Then
it can't block. Why can't I use it then?
- This is a longer answer.
- In versions of VxWorks prior to 6.6 there are three types of
semaphores: mutex, binary and counting. VxWorks 6.6 has introduced a
fourth type--reader/writer semaphores. I have not worked with their
6.6 implementation of reader/writer semaphores so I will not comment
on it here.
If you go into target/h/private/semLibP.h and pull up the structure
definition of SEMAPHORE, you will see a union. The macros semCount
and semOwner access the members of this union.
Mutex semaphores track the taskID of the task that successfully
took the semaphore (its owner). This is used for priority inheritance
as well as for enforcing the mutex property that only the owner can
give up the mutex semaphore. ISRs are not allowed to take a mutex
semaphore as it does not have a taskID. Therefore, even if NO_WAIT
were used as the timeout, an ISR can not take a mutex.

Binary semaphores also use semOwner and taskIdCurrent to track the
owner, but for different reasons. A binary semaphore as you may
recall has two states: taken and available, or if you prefer locked
and unlocked. Technically any two different values can be used.
However the ID of the current task (taskIdCurrent) is used to signify
that it is taken, and zero (0) to signify that it is available. This
gives the benefit of adding some debugging information to the
semaphore. That is, one can inspect the contents of the semaphore
structure and determine what task took the semaphore. This can be
very useful. However, in the context of an ISR, taskIdCurrent is
invalid. It no longer identifies the currently running task, but
rather the task that was interrupted. What if the system is idle--no
tasks are running in the system. I can't remember exactly off hand,
but I think it may be NULL. Therefore, if an ISR took it, it would
not look like it was taken. To summarize for binary semaphores--this
restriction comes about as a result of implementation choices.

Finally this brings us to counting semaphores. There is no
technical reason why one shouldn't be able to take a VxWorks counting
semaphore from within an ISR when using NO_WAIT as the timeout. The
only reason why I can see this not being allowed is consistency. It
can't be done for 2 out of the 3 semaphore types, therefore for
consistency, we're going to make it not allowed for 3 out of 3.

I hope all this helps.

Peter Mitsis


On Jan 30, 7:54 am, gvarndell <gvarnd...@xxxxxxxxxxx> wrote:
On Jan 30, 7:31 am, sant...@xxxxxxxxx wrote:

Thanks for the reply.

You mean to say that,  since the above mentioned process_Int() has
SemTake, which runs under task level,
will slowdown the network process and may cause networkcrash or other
network problems.

Yes.
Also, you disabling all interrupts in ISR context and enabling them in
task context.
I'm not sure exactly what the functions enable_all_interrupt() and
disable_all_interrupt() do, but they are not needed.
In fact, if you were successful in disabling all interrupts in an ISR
context, and that condition persisted when the kernel returned to
tasking, your system would be dead.

HTH
GV

.



Relevant Pages

  • Re: [PATCH 1/12]: MUTEX: Implement mutexes
    ... >> ldrex/strex instructions are available only on ARM architecture level 6 ... >> interrupts, do the semaphore update and enable interrupts again which is ... > interrupts and does the semaphore without any atomic instructions at all. ...
    (Linux-Kernel)
  • Re: semtake() in ISR
    ... calling the POSIX semaphore routine sem_trywait. ... (should be same amount of time as semGive which can be called from ISR) ... and critical interrupts are lost as the interrupts are disabled when ... /* Initializes semaphore SEMA to VALUE. ...
    (comp.os.vxworks)
  • Re: The idea of disabling interrupts
    ... disable interrupts for a short period, and you don't call any OS/library ... While flags may seem to resemble in one way like a semaphore in its ... 1)A flag may get modified any time and may introduce write/read ... for your product or application,provided your talking about RTOS .You ...
    (comp.arch.embedded)
  • Re: 2.6.13: loop ioctl crashes
    ... > being held or the interrupts otherwise disabled. ... to prevent somebody else from interfering with ... use a semaphore. ... send the line "unsubscribe linux-kernel" in ...
    (Linux-Kernel)
  • Re: how to minimize interrupt latency using interrupt affinity in
    ... it would be VERY useful if the CPU or ISR ... one can see nested interrupts etc). ... my ISR runs on a processor core which is not ever used by other ISRs: ... even though I set affinity to 0x3 for all drivers ...
    (microsoft.public.development.device.drivers)