Steven Dufresne wrote:
J. Scott Franko <> jsfranko@switch.com> > wrote:
Steven Dufresne wrote:
J. Scott Franko <> jsfranko@switch.com> > wrote:
In QNX4, the code I am porting used a qnx_hint_attach(-1,, …
to create a recurring 50ms intterupt timer. It was used as a watchdog
timer of sorts toggle a value on the paralell port. A device on the
port must be watching for this toggle, and if it doesn’t get it, it
declairs a failover condition (its called our failover device), and
switches our field I/O to the hotstandby computer, instantly. There
doesn’t seem to be an equivalent 50ms interrupt in the interupt table in
the docs for NTO’s interruptAttach().
Any suggestions as to how I should implement this 50ms interrupt handler
in NTO?
Here’s a snipet that uses the same timer that the kernel uses for
its timebase. This defaults to 1ms and is what all of your
Your example gave me fuel to find more info in the helpviewer. Thx! But when
I read about the ClockPeriod function, it said that the default period was
10ms.
It’s probably on docs list to change this but just in case, Donna?
timing that uses the kernel is based on so you wouldn’t want to do
anything like set it to 50ms. It does mean thatr you interrupt handler
will have to count interrupts and only toggle you bit for every
50th (fiftymseccount) of them. Usually you want to avoid this
sort of counting interrupts and use the timer_create()/timer_settime()
sutff instead but since this is a watchdog, you have to do it in
an interrupt handler. Your other option is to provide your own timer
hardware that generates its own interrupt.
ClockPeriod(CLOCK_REALTIME, NULL, &period, 0);
fiftymseccount = (50 * MILLION) / period.nsec;
ThreadCtl(_NTO_TCTL_IO, 0);
event.sigev_notify = SIGEV_INTR;
How is this event used? I don’t see it referenced below.
The interrupt handler returns to the kernel with the address of the
event. The kernel then delivers the event. In this case it is
a SIGEV_INTR event which goes to the thread that did the
InterruptAttach() and unblocks its InterruptWait().
Now I understand. Thanks for taking the time to explain it so clearly.
Now that I understand it, I realize that the process can’t wait on the event
interrupt, so I won’t be using InterruptWait(). The process needs to do other
processing, but at the same time it needs to get in every 50ms to tell the failover
hardware not to start a timeout for switching to the backup processor, by toggling a
bit on the parallel port. So if I don’t describe this event structure, and wait for
it, what does the kernel do with the event the handler returns. Do I have to do
something special to make the kernel not care?
Also, you define your counters outside the handler. I am confused by the
IntteruptAttach() option that allows you to send an Area pointer to the handler.
Can the handler have access to global scope variable defined outside it, or do you
have to pass in this area pointer. In QNX4 it was this far pointer thing, and we
passed our countrer in with the FP_SEG macro.
Would I do something like this:?
above main and wd_int:
static int count50ms = 0;
and in main:
// if ( qnx_hint_attach( -1, wd_int, FP_SEG( &count50ms ) ) < 0 )
if ( InterruptAttach( SYSPAGE_ENTRY(qtime)->intr,
wd_int,
&count50ms,
sizeof(count50ms),
_NTO_INTR_FLAGS_TRK_MSK )
< 0 )
And one other question: If I am intterupting my process now every 1ms and doing
the counting myself, instead of some other processing doing the counting for me and
interrupting my process every 50m as in the QNX4 hint_attach(-1,…) call, isn’t
this going to be a lot of overhead for the process? Will it affect my process
adversely? The process goes through a 100ms scan loop already and is the main
controlling routine for our process control system. A slow down because of overhead
intterupt processing like this could slow down critical processing in this major
process.
struct sigevent event;
unsigned counter;
int fiftymseccount;
const struct sigevent *
handler(void *area, int id)
{
if (++counter == fiftymseccount) {
counter = 0;
return &event;
}
return NULL;
}
id = InterruptAttach(SYSPAGE_ENTRY(qtime)->intr, handler, NULL, 0,
_NTO_INTR_FLAGS_TRK_MSK);
I don’t see any reference to the SYSPAGE_ENTRY(qtime)->intr in the function
description for InterruptAttach(). I assume that it is a way to support
selecting the interrupt to attach to in a crossplatform way, rather than
choosing an x86 intr from the table, but could you elaborate or point me to
the helpviewer section that describes it’s use?
As far as I know, only the timer interrupt can be found this way.
It is a part of the system page which we don’t document as such since
we discourage people using it unless the information cannot be gotten
from elsewhere, as in this case. And yes, it is good because it works
crossplatform. However, there are details on the system page in
the Building Embedded System book, Customizing Image Startup Programs
section because it is the startup code that has to set it. There are
no docs describing the macro, but its purpose is to isolate you from
the details of the system page thereby allowing us to restructure it
should we want to.
I assume you’ve seen that it is sorta documented from your next response after this
one. I’ve looked at the syspage.h and found the macro and the qtime structure and
its long intr. Thanks for the tip on where to look for more information. I often
find that there is information relavent to multiple topics that are only defined
specifically in the context of one topic. Another example is pulses, who’s use is
defined mostly within the context of Photon development, yet which have uses outside
of that context, and is hinted at in the migration documents.
Scott
if (id == -1) {
perror(“InterruptAttach failed”);
exit(EXIT_FAILURE);
}
for (;
{
InterruptWait(0, NULL);
printf(“If we got here then some thread failed its deadline!\n”);
}
Thanks,
Scott