Problem on Interrupt (QNX6)

I have a PCI card on which 4 registers must be accessed
in an atomic way (4 regs as a whole). Several processes
can access them during runtime.

To ensure it, I used InterruptDisable() before I access them, later
InterruptEnable().
However, found out that it didn’t work as I expected.

From the docs, InterruptDisable() can disable all the
hardware interrupts. Does it mean it also disables the
timer interrupt (thus no context switch)?

The following is a test code to check if my ISR is
called after I call InterruptDisable()?
I expected that my ISR should not be called. However it
seems like InterruptDisable() is not working as I
expect. Something wrong?

////////////////////////////////////////////
#include <stdio.h>
#include <math.h>
#include <sys/neutrino.h>

volatile unsigned long count;
const struct sigevent *myISR(void *area, int id)
{
count++;
return 0;
}

int main()
{
unsigned int i;
int id;
double a;

ThreadCtl(_NTO_TCTL_IO,0);
id=InterruptAttach(0, myISR, 0,0,0);
InterruptDisable();
printf(“the count=%ld\n”,count);
for(i=0;i<0x500000;i++)
a+=sin((double)i);
printf(“the count=%ld\n”,count);
InterruptEnable();
InterruptDetach(id);
return 0;
}

Jerry wrote:

I have a PCI card on which 4 registers must be accessed
in an atomic way (4 regs as a whole). Several processes
can access them during runtime.

To ensure it, I used InterruptDisable() before I access them, later
InterruptEnable().

Ok, but not SMP-Save.
Use InterruptLock/InterruptUnlock.

However, found out that it didn’t work as I expected.

From the docs, InterruptDisable() can disable all the
hardware interrupts. Does it mean it also disables the
timer interrupt (thus no context switch)?

The following is a test code to check if my ISR is
called after I call InterruptDisable()?
I expected that my ISR should not be called. However it
seems like InterruptDisable() is not working as I
expect. Something wrong?

Yes, printf is not allowed at IRQ-Level!!!
I assume after your 1st printf, the IRQ’s are enabled again.

////////////////////////////////////////////
#include <stdio.h
#include <math.h
#include <sys/neutrino.h

volatile unsigned long count;
const struct sigevent *myISR(void *area, int id)
{
count++;
return 0;
}

int main()
{
unsigned int i;
int id;
double a;

ThreadCtl(_NTO_TCTL_IO,0);
id=InterruptAttach(0, myISR, 0,0,0);
InterruptDisable();
printf(“the count=%ld\n”,count);
for(i=0;i<0x500000;i++)
a+=sin((double)i);
printf(“the count=%ld\n”,count);
InterruptEnable();
InterruptDetach(id);
return 0;
}

Also tried InterruptLock(), no luck,
Actually my machine is not a SMP.

“Michael Tasche” <michael.tasche@esd-electronics.com> wrote in message
news:3E252D2D.56B30EC7@esd-electronics.com

Jerry wrote:

I have a PCI card on which 4 registers must be accessed
in an atomic way (4 regs as a whole). Several processes
can access them during runtime.

To ensure it, I used InterruptDisable() before I access them, later
InterruptEnable().

Ok, but not SMP-Save.
Use InterruptLock/InterruptUnlock.

However, found out that it didn’t work as I expected.

From the docs, InterruptDisable() can disable all the
hardware interrupts. Does it mean it also disables the
timer interrupt (thus no context switch)?

The following is a test code to check if my ISR is
called after I call InterruptDisable()?
I expected that my ISR should not be called. However it
seems like InterruptDisable() is not working as I
expect. Something wrong?

Yes, printf is not allowed at IRQ-Level!!!
I assume after your 1st printf, the IRQ’s are enabled again.


////////////////////////////////////////////
#include <stdio.h
#include <math.h
#include <sys/neutrino.h

volatile unsigned long count;
const struct sigevent *myISR(void *area, int id)
{
count++;
return 0;
}

int main()
{
unsigned int i;
int id;
double a;

ThreadCtl(_NTO_TCTL_IO,0);
id=InterruptAttach(0, myISR, 0,0,0);
InterruptDisable();
printf(“the count=%ld\n”,count);
for(i=0;i<0x500000;i++)
a+=sin((double)i);
printf(“the count=%ld\n”,count);
InterruptEnable();
InterruptDetach(id);
return 0;
}

Don’t make any calls inside the Disable/Enable() enclosure. At least two
reasons - interrupts off is a bad idea for long periods of time, which you
are doing; and also because many library functions could result in a kernel
call at somewhere down the line.

InterruptDisable/Enable() work, as not much would if they didn’t.

Why not just use a shared mutex to serialize access to this resource?

-Adam

Jerry <xwindow@yahoo.com> wrote in message news:b03r41$aar$1@inn.qnx.com

Also tried InterruptLock(), no luck,
Actually my machine is not a SMP.

“Michael Tasche” <> michael.tasche@esd-electronics.com> > wrote in message
news:> 3E252D2D.56B30EC7@esd-electronics.com> …
Jerry wrote:

I have a PCI card on which 4 registers must be accessed
in an atomic way (4 regs as a whole). Several processes
can access them during runtime.

To ensure it, I used InterruptDisable() before I access them, later
InterruptEnable().

Ok, but not SMP-Save.
Use InterruptLock/InterruptUnlock.

However, found out that it didn’t work as I expected.

From the docs, InterruptDisable() can disable all the
hardware interrupts. Does it mean it also disables the
timer interrupt (thus no context switch)?

The following is a test code to check if my ISR is
called after I call InterruptDisable()?
I expected that my ISR should not be called. However it
seems like InterruptDisable() is not working as I
expect. Something wrong?

Yes, printf is not allowed at IRQ-Level!!!
I assume after your 1st printf, the IRQ’s are enabled again.


////////////////////////////////////////////
#include <stdio.h
#include <math.h
#include <sys/neutrino.h

volatile unsigned long count;
const struct sigevent *myISR(void *area, int id)
{
count++;
return 0;
}

int main()
{
unsigned int i;
int id;
double a;

ThreadCtl(_NTO_TCTL_IO,0);
id=InterruptAttach(0, myISR, 0,0,0);
InterruptDisable();
printf(“the count=%ld\n”,count);
for(i=0;i<0x500000;i++)
a+=sin((double)i);
printf(“the count=%ld\n”,count);
InterruptEnable();
InterruptDetach(id);
return 0;
}

Jerry <xwindow@yahoo.com> wrote:

I have a PCI card on which 4 registers must be accessed
in an atomic way (4 regs as a whole). Several processes
can access them during runtime.

To ensure it, I used InterruptDisable() before I access them, later
InterruptEnable().
However, found out that it didn’t work as I expected.

From the docs, InterruptDisable() can disable all the
hardware interrupts. Does it mean it also disables the
timer interrupt (thus no context switch)?

All interrupts, including the timer interrupt.

BUT, the timer interrupt is NOT required for a context switch.
A context switch can occur on any kernel call, interrupt, or
processor fault (e.g. illegal instruction).

The following is a test code to check if my ISR is
called after I call InterruptDisable()?
I expected that my ISR should not be called. However it
seems like InterruptDisable() is not working as I
expect. Something wrong?



ThreadCtl(_NTO_TCTL_IO,0);
id=InterruptAttach(0, myISR, 0,0,0);
InterruptDisable();
printf(“the count=%ld\n”,count);

printf() is the problem.

Under QNX, anytime you make a kernel call, interrupts will be
enabled. printf() will call write() which will call MsgSend() which
is a kernel call, and this will re-enable interrupts.

So, you did not have interrupts disabled through your test code.

Try the following to test:
int a, i, j;

InterruptDisable()
ocount = count;
for(i=0;i<0x500000;i++)
for ( j = 0; j < 50000; j++)
a = i+j;
newcount = count;
InterruptEnable();
printf(“count before delay: %d, count after delay: %d\n”, ocount, newcount);

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

David Gibbs wrote:

Jerry <> xwindow@yahoo.com> > wrote:
From the docs, InterruptDisable() can disable all the
hardware interrupts. Does it mean it also disables the
timer interrupt (thus no context switch)?

All interrupts, including the timer interrupt.

Just a small QNX API criticism:
If the InterruptLock or InterruptDisable Calls had an additional
parameter IRQ-Id (perhaps the return value from InterruptAttach), it
would be possible to disable IRQs only up to the needed Level.

BUT, the timer interrupt is NOT required for a context switch.

Yes, but if some bad driver locks IRQs too long, you will loose some
ticks.

Michael

Michael Tasche <michael.tasche@esd-electronics.com> wrote:


David Gibbs wrote:

Jerry <> xwindow@yahoo.com> > wrote:
From the docs, InterruptDisable() can disable all the
hardware interrupts. Does it mean it also disables the
timer interrupt (thus no context switch)?

All interrupts, including the timer interrupt.

Just a small QNX API criticism:
If the InterruptLock or InterruptDisable Calls had an additional
parameter IRQ-Id (perhaps the return value from InterruptAttach), it
would be possible to disable IRQs only up to the needed Level.

InterruptMask & InterruptUnmask() allow you to mask & unmask just
a specific irq level.

BUT, the timer interrupt is NOT required for a context switch.

Yes, but if some bad driver locks IRQs too long, you will loose some
ticks.

Absolutely. But that has nothing to do with context switches.
You could lose ethernet packets, drop bytes on a serial port,
maybe lose data to/from other hardware, etc. Keeping interrupts
disabled for long periods of time is a bad thing to do for many
reasons.

I was clarifying there that context switching did not depend on
the timer tick.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

David Gibbs wrote:

Jerry <> xwindow@yahoo.com> > wrote:

I have a PCI card on which 4 registers must be accessed
in an atomic way (4 regs as a whole). Several processes
can access them during runtime.


To ensure it, I used InterruptDisable() before I access them, later
InterruptEnable().
However, found out that it didn’t work as I expected.

If you’re disabling interrupts under QNX, you’re probably
doing something wrong. The whole point of QNX is that
you do almost everything in real processes, not
interrupt-level code. You protect critical sections
with mutexes, not interrupt disabling. Among other
things, this works for multiprocessors, while disabling
interrupts will not.

It’s far, far easier to interface with hardware under
QNX than most other operating systems. But it’s
different. Don’t try to code in terms of a UNIX or VxWorks
driver model, with a process “top” and an interrupt-level
“bottom”.

John Nagle
Animats

David Gibbs wrote:

Michael Tasche <> michael.tasche@esd-electronics.com> > wrote:

David Gibbs wrote:

Jerry <> xwindow@yahoo.com> > wrote:
From the docs, InterruptDisable() can disable all the
hardware interrupts. Does it mean it also disables the
timer interrupt (thus no context switch)?

All interrupts, including the timer interrupt.

Just a small QNX API criticism:
If the InterruptLock or InterruptDisable Calls had an additional
parameter IRQ-Id (perhaps the return value from InterruptAttach), it
would be possible to disable IRQs only up to the needed Level.

InterruptMask & InterruptUnmask() allow you to mask & unmask just
a specific irq level.

Are they SMP-Save ?

BUT, the timer interrupt is NOT required for a context switch.

Yes, but if some bad driver locks IRQs too long, you will loose some
ticks.

Absolutely. But that has nothing to do with context switches.
You could lose ethernet packets, drop bytes on a serial port,
maybe lose data to/from other hardware, etc. Keeping interrupts
disabled for long periods of time is a bad thing to do for many
reasons.

I was clarifying there that context switching did not depend on
the timer tick.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

Michael Tasche <michael.tasche@esd-electronics.com> wrote:

Just a small QNX API criticism:
If the InterruptLock or InterruptDisable Calls had an additional
parameter IRQ-Id (perhaps the return value from InterruptAttach), it
would be possible to disable IRQs only up to the needed Level.

InterruptMask & InterruptUnmask() allow you to mask & unmask just
a specific irq level.

Are they SMP-Save ?

My understanding is yes. Essentially, the mask & unmask operate at
the interrupt controller level to mask/unmask one interrupt. The
disable/enable operate on a per-CPU basis to disable all interrupts
to that CPU.

-David

QNX Training Services
http://www.qnx.com/support/training/
Please followup in this newsgroup if you have further questions.

David Gibbs wrote:

Michael Tasche <> michael.tasche@esd-electronics.com> > wrote:
Are they SMP-Save ?


My understanding is yes. Essentially, the mask & unmask operate at
the interrupt controller level to mask/unmask one interrupt. The
disable/enable operate on a per-CPU basis to disable all interrupts
to that CPU.

Hmmm, if disable/enable is per CPU, wouldn’t that mean that if you mask
(say) IRQ 5, while the calling thread (i.e. the thread that called
InterruptMask) is being scheduled on CPU 0, that the OS is free to
schedule the IRQ 5 interrupt handler on CPU 1/2/3 before InterruptUnmask
is called ? That doesn’t sound SMP safe.

Rennie Allen wrote:

David Gibbs wrote:
My understanding is yes. Essentially, the mask & unmask operate at
the interrupt controller level to mask/unmask one interrupt. The
disable/enable operate on a per-CPU basis to disable all interrupts
to that CPU.


Hmmm, if disable/enable is per CPU, wouldn’t that mean that if you mask
(say) IRQ 5, while the calling thread (i.e. the thread that called
InterruptMask) is being scheduled on CPU 0, that the OS is free to
schedule the IRQ 5 interrupt handler on CPU 1/2/3 before InterruptUnmask
is called ? That doesn’t sound SMP safe.

The mask/unmask is happening on the 8259 interrupt controller chip.

Once masked, it won’t get through to ANY CPU.


Bill Caroselli
Q-TPS Consulting
(626) 824-7983

Bill Caroselli wrote:

Rennie Allen wrote:
David Gibbs wrote:
My understanding is yes. Essentially, the mask & unmask operate at
the interrupt controller level to mask/unmask one interrupt. The
disable/enable operate on a per-CPU basis to disable all interrupts
to that CPU.


Hmmm, if disable/enable is per CPU, wouldn’t that mean that if you mask
(say) IRQ 5, while the calling thread (i.e. the thread that called
InterruptMask) is being scheduled on CPU 0, that the OS is free to
schedule the IRQ 5 interrupt handler on CPU 1/2/3 before InterruptUnmask
is called ? That doesn’t sound SMP safe.

The mask/unmask is happening on the 8259 interrupt controller chip.
Once masked, it won’t get through to ANY CPU.
But 8259 access is slow, isn’t it?


Bill Caroselli
Q-TPS Consulting
(626) 824-7983