qnx_hint_attach(-1,...

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?

Thanks,

Scott

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
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;
id = InterruptAttach(SYSPAGE_ENTRY(qtime)->intr, handler, NULL, 0,
_NTO_INTR_FLAGS_TRK_MSK);
if (id == -1) {
perror(“InterruptAttach failed”);
exit(EXIT_FAILURE);
}

for (;:wink: {
InterruptWait(0, NULL);
printf(“If we got here then some thread failed its deadline!\n”);
}

Thanks,

Scott

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.

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.

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?

if (id == -1) {
perror(“InterruptAttach failed”);
exit(EXIT_FAILURE);
}

for (;:wink: {
InterruptWait(0, NULL);
printf(“If we got here then some thread failed its deadline!\n”);
}

Thanks,

Scott

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().

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.

if (id == -1) {
perror(“InterruptAttach failed”);
exit(EXIT_FAILURE);
}

for (;:wink: {
InterruptWait(0, NULL);
printf(“If we got here then some thread failed its deadline!\n”);
}

Thanks,

Scott

Steven Dufresne <stevend@qnx.com> wrote:

J. Scott Franko <> jsfranko@switch.com> > wrote:



Steven Dufresne wrote:

J. Scott Franko <> jsfranko@switch.com> > wrote:
snip
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

Whoops, it is doc’d in the library reference manual.

the details of the system page thereby allowing us to restructure it
should we want to.
snip

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 (;:wink: {
InterruptWait(0, NULL);
printf(“If we got here then some thread failed its deadline!\n”);
}

Thanks,

Scott

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 (;:wink: {
InterruptWait(0, NULL);
printf(“If we got here then some thread failed its deadline!\n”);
}

Thanks,

Scott

J. Scott Franko <jsfranko@switch.com> wrote:

Steven Dufresne wrote:

J. Scott Franko <> jsfranko@switch.com> > wrote:

Steven Dufresne wrote:

J. Scott Franko <> jsfranko@switch.com> > wrote:
snip
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?

Return 0, just as you do in QNX 4.

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 )

The use of area and size are optional. Just as in QNX 4, the ISR and
the process shared data.

Unlike QNX 4, you don’t have to do the FP_SEG() thing anymore. We
take care of it.

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.

What do you do in QNX 4? If you toggled your bit from within the ISR
then do the same thing here and don’t wake up the process. Your overhead
is the work the kernel has to do before and after calling your
interrupt handler every 1ms. If you toggled the bit in the process then
why not use timer_create() and timer_settime() with a 50ms timer?

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
snip

Steve

Steven Dufresne wrote:

J. Scott Franko <> jsfranko@switch.com> > wrote:

Steven Dufresne wrote:

J. Scott Franko <> jsfranko@switch.com> > wrote:

Steven Dufresne wrote:

J. Scott Franko <> jsfranko@switch.com> > wrote:
snip
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?

Return 0, just as you do in QNX 4.

Good. That’s what we do.

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 )

The use of area and size are optional. Just as in QNX 4, the ISR and
the process shared data.

Unlike QNX 4, you don’t have to do the FP_SEG() thing anymore. We
take care of it.

Good. So I’ll just send a null pointer and a zero size and the handler will be able to
access.

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.

What do you do in QNX 4? If you toggled your bit from within the ISR
then do the same thing here and don’t wake up the process. Your overhead
is the work the kernel has to do before and after calling your
interrupt handler every 1ms. If you toggled the bit in the process then
why not use timer_create() and timer_settime() with a 50ms timer?

We do toggle the bit in the handler. What I meant was that our process was going to be
interrupted 50 more times as often. That adds up to a lot of interrupts and context
switch’s in a second. This processes does nanosleep for the difference between 100ms and
the time it took to run through main(). I’m not sure how much time that is.

But for the time that the process is active, and getting intterupted, are you saying it
won’t slow down the processing going on, when its getting hit with all the context
switches to the ISR handler? (last question on this subject, I swear! ;o) ) This is all
the handler does right now:

const struct sigevent* wd_int( void* area, int id )
{
if ( ++count50ms < SEC_3 )
{
previous_output = ~previous_output;
out8( tgl_b, previous_output );
//outp( TOGGLE_BASE, previous_output );
}

if ( wdkick )
{
count50ms = 0;
wdkick = FALSE;
}

return( 0 );
}



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
snip

Steve

J. Scott Franko <jsfranko@switch.com> wrote:

Steven Dufresne wrote:
J. Scott Franko <> jsfranko@switch.com> > wrote:
Steven Dufresne wrote:
J. Scott Franko <> jsfranko@switch.com> > wrote:
Steven Dufresne wrote:
J. Scott Franko <> jsfranko@switch.com> > wrote:
snip
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.
snip
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.

What do you do in QNX 4? If you toggled your bit from within the ISR
then do the same thing here and don’t wake up the process. Your overhead
is the work the kernel has to do before and after calling your
interrupt handler every 1ms. If you toggled the bit in the process then
why not use timer_create() and timer_settime() with a 50ms timer?


We do toggle the bit in the handler. What I meant was that our process was going to be
interrupted 50 more times as often. That adds up to a lot of interrupts and context
switch’s in a second. This processes does nanosleep for the difference between 100ms and
the time it took to run through main(). I’m not sure how much time that is.

But for the time that the process is active, and getting intterupted, are you saying it
won’t slow down the processing going on, when its getting hit with all the context
switches to the ISR handler? (last question on this subject, I swear! ;o) ) This is all
the handler does right now:

Sure it will slow processing down some. Here and in QNX 4, the
kernel’s timer interrupt handler was being called. The extra here
is the call to your handler, time in the handler and return from
the handler. A quick test would be to do ‘pidin ti’ run a process
that spins for a fixed long time then do ‘pidin ti’ again (from the
shell, pidin ti;looper;pidin ti). Do the test with and without the
ISR installed. In the pidin ti output, the interesting number is
in the utime column. Subtract the one before from the one after,
this is how much time your loop was not being held up by the ISR.

const struct sigevent* wd_int( void* area, int id )
{
if ( ++count50ms < SEC_3 )
{
previous_output = ~previous_output;
out8( tgl_b, previous_output );
//outp( TOGGLE_BASE, previous_output );
}

if ( wdkick )
{
count50ms = 0;
wdkick = FALSE;
}

return( 0 );
}

J. Scott Franko <jsfranko@switch.com> wrote:


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?

Yep… I’ll update the docs where appropriate.
FWIW, Brian says that if the clock speed of a CPU is <= 40MHz then the default clock period
is set to 10 milliseconds, otherwise the default is set 1 millisecond.

-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 (;:wink: {
InterruptWait(0, NULL);
printf(“If we got here then some thread failed its deadline!\n”);
}

Thanks,

Scott