Neutrino Momentics - Attaching an interrupt handler to an in

GCC 2.95.3

While porting an interrupt handler from QNX 4.25, to Neutrino 6.2.0(NC),
GCC identifies a candidate function, but does not select it.

From the header file:

MyClass
{
MyClass ();
~MyClass ();

void SetupIsr(int irqLevel);

private:
struct sigevent event;

const struct sigevent *MyIsr (void *arg, int id);
}

From the implementation file:
const struct sigevent *MyClass::MyIsr(void *arg, int id)
{

event.sigev_notify = SIGEV_INTR;
return (&event);
}

// Attach the interrupt handler to the given hardware interrupt level:
void MyClass::SetupIsr(int irqLevel)
{
// Enable I/O privity
ThreadCtl (_NTO_TCTL_IO, 0);
irqID = InterruptAttach (interruptLevel, (MyIsr), NULL, 0, 0);

}

Compiler Messages:
…/my_class.cpp: no matches converting function MyIsr' to type const
struct sigevent * (*)(void *, int)’

…/my_class.cpp: candidates are: const struct sigevent *
MyClass::MyIsr(void *, int)

So, if GCC has identified the correct function, why did it generate
an error instead of selecting it?

Ideas?

-GF

“Gordon Freeman” <gordon.freeman@hotmail.com> wrote in message
news:3E051348.5070506@hotmail.com

GCC 2.95.3

While porting an interrupt handler from QNX 4.25, to Neutrino 6.2.0(NC),
GCC identifies a candidate function, but does not select it.

From the header file:

MyClass
{
MyClass ();
~MyClass ();

void SetupIsr(int irqLevel);

private:
struct sigevent event;

const struct sigevent *MyIsr (void *arg, int id);
}

From the implementation file:
const struct sigevent *MyClass::MyIsr(void *arg, int id)
{

event.sigev_notify = SIGEV_INTR;
return (&event);
}

// Attach the interrupt handler to the given hardware interrupt level:
void MyClass::SetupIsr(int irqLevel)
{
// Enable I/O privity
ThreadCtl (_NTO_TCTL_IO, 0);
irqID = InterruptAttach (interruptLevel, (MyIsr), NULL, 0, 0);

}

Compiler Messages:
…/my_class.cpp: no matches converting function MyIsr' to type const
struct sigevent * (*)(void *, int)’

…/my_class.cpp: candidates are: const struct sigevent *
MyClass::MyIsr(void *, int)

So, if GCC has identified the correct function, why did it generate
an error instead of selecting it?

Ideas?

It hasn’t identified the correct function. It has told you that it hasn’t
found a function which matches the signature that is required by
InterruptAttach. Anything that isn’t PRECISELY “const struct sigevent *
(*)(void , int)" will not work. Two possibilities that might help. 1) try
declaring the member function MyIsr as static. That way there is only one
rather than one per instance of MyClass. The other possibility is to pass
an actual instance of the MyIsr function to InterruptAttach using the →

operator. Something like (this)->MyIsr. I don’t know if either of these
things will work. You may need to declare a "const struct sigevent *
(
)(void *, int)” outside of the class.

cheers,

Kris

Kris Warkentin wrote:

Something like (this)->MyIsr. I don’t know if either of these
things will work. You may need to declare a "const struct sigevent *
(
)(void *, int)" outside of the class.

The C++ resmanager framework I just announced on
qdn.public.qnxrtp.devtools, allows you attach an instance member
function to an interrupt. There is an example program with the
source that shows how to do this with reswrap. It does this by
using the signal/slot mechanism of libsigc++. For higher
performance, it also allows you to attach a handler via
InterruptAttachEvent (no signal/slot handling at interrupt
time).

Rennie

Two possibilities that might help. 1) try
declaring the member function MyIsr as static.

Tried this. Compiler says ‘cannot’.

The other possibility is to pass
an actual instance of the MyIsr function to InterruptAttach using the ->*
operator. Something like (this)->*MyIsr.

Tried this also. The error message remains the same.

I don’t know if either of these
things will work. You may need to declare a “const struct sigevent *
(*)(void *, int)” outside of the class.

This appears to be the only workable result, since the only difference
in function signature is the name of the class the ISR function belongs
to.

But if the interrupt function is defined outside the class, then I lose
access to the class private data!

It seems GCC is not very flexible in this way, it is forcing a single
solution (define the ISR function outside the class) rather than
allowing any latitude (use the ‘candidate’ function defined inside the
class).

-GF

This appears to be the only workable result, since the only difference
in function signature is the name of the class the ISR function belongs
to.

But if the interrupt function is defined outside the class, then I lose
access to the class private data!

It seems GCC is not very flexible in this way, it is forcing a single
solution (define the ISR function outside the class) rather than
allowing any latitude (use the ‘candidate’ function defined inside the
class).

The issue is that you can’t take a pointer to a C++ class member as a
function pointer unless that entry is declared as static. This is nothing
to do with GCC. There are hidden parameters (the this pointer) that are
included with C++ member functions. You are not going to be able to access
your class data from an interrupt handler anyways, since the handler only
has a limited sub-set of the processes memory space avaliable to it (passed
in via the area pointer to InterruptAttach()). Plus there are such a limited
subset of system functionality you can use from an ISR that it is best to
code it up as a simple C function.

What you want to do is have a thread running and use InterruptAttachEvent().
You can handle this a couple of ways, either with a friend function or with
a static member to your class. Then you pass in the “this” pointer as the
parameter to pthread_create(). For example:

#include <pthread.h>

class ThreadedObject
{
private:
static void* threadEntry( void *p ) {
ThreadedObject *pthis = (ThreadedObject *)p;
return pthis->run();
}

void* run() {
// Do your work here…
return 0;
}

public:
int runThread() {
return pthread_create( 0, 0, threadEntry, this );
}
};

I am sure you get the idea…

chris

\

Chris McKillop <cdm@qnx.com> “The faster I go, the behinder I get.”
Software Engineer, QSSL – Lewis Carroll –
http://qnx.wox.org/

Gordon Freeman <gordon.freeman@hotmail.com> wrote:

GCC 2.95.3

While porting an interrupt handler from QNX 4.25, to Neutrino 6.2.0(NC),
GCC identifies a candidate function, but does not select it.

From the header file:

MyClass
{
MyClass ();
~MyClass ();

void SetupIsr(int irqLevel);

private:
struct sigevent event;

const struct sigevent *MyIsr (void *arg, int id);
}

From the implementation file:
const struct sigevent *MyClass::MyIsr(void *arg, int id)
{

event.sigev_notify = SIGEV_INTR;
return (&event);
}

// Attach the interrupt handler to the given hardware interrupt level:
void MyClass::SetupIsr(int irqLevel)
{
// Enable I/O privity
ThreadCtl (_NTO_TCTL_IO, 0);
irqID = InterruptAttach (interruptLevel, (MyIsr), NULL, 0, 0);

}

Lots of people have commented on this, but I thought I would
throw my few cents in.

The other way to approach this (which is what was other OSs’
C++ users have had to do is to define a static function which
is responsible for re-instantiating the class based on the
argument.

// Redirect through the class ISR
static const struct sigevent *MyClassISRRedirect(void *area, int id) {
MyClass * myclass = (MyClass *)area;
return myclass->MyIsr(area, id);
}

… normal class definition …

// Attach the interrupt handler to the given hardware interrupt level:
void MyClass::SetupIsr(int irqLevel)
{
// Enable I/O privity
ThreadCtl (_NTO_TCTL_IO, 0);
irqID = InterruptAttach (interruptLevel, MyClassISRRedirect, this, 0, 0);
}

This means that you loose the extra argument, but you
can just encapsulate that in your class. It also means
that you need to declare the MyIsr() call to be public
so that it can be accessed externally, but it is fairly
clean otherwise.

Hope this helps,
Thomas

Thomas (toe-mah) Fletcher QNX Software Systems
thomasf@qnx.com Core OS Technology Group
(613)-591-0931 http://www.qnx.com/

Chris McKillop wrote:

included with C++ member functions. You are not going to be able to access
your class data from an interrupt handler anyways, since the handler only
has a limited sub-set of the processes memory space avaliable to it (passed
in via the area pointer to InterruptAttach()).

InterruptAttach documents no limitation as to the size of the area
pointed to by the area argument. Is there an undocumented limitation ?

My assumption was that the size of “area” would be rounded to a page
boundary, and a VM mapping set up that would be made available to the
interrupt handler.

If the size of area is not limited, then you can certainly access
class data in an interrupt handler (the fact that I currently do this
at least hints at the possibility :slight_smile:

Rennie

Chris McKillop wrote:

InterruptAttach documents no limitation as to the size of the area
pointed to by the area argument. Is there an undocumented limitation ?

My assumption was that the size of “area” would be rounded to a page
boundary, and a VM mapping set up that would be made available to the
interrupt handler.


That isn’t what I mean. If you simply pass a pointer to a class and it’s
size you will get the class itself, but if it has any explict or implicit
pointers they will not always be valid. So it isn’t a size issue so much as
having the data all in a linear virtual address space.

That’s true; but I don’t see how this is any greater a restriction
than those that are faced when you code the ISR in C. In either
case you have to be conscious of what you can/cannot access. Having
a class as a package of data is no different than having a pointer to
a struct, it neither adds nor subtracts any responsibility from the
developer of the ISR, it can however, be an architectural convenience
to allow an instance member function to be used as an ISR where
constraints permit.

Overall, I favour the InterruptAttachEvent methodology, but I see
no reason why I should have to constrain myself to writing ISRs
only in C.

InterruptAttach documents no limitation as to the size of the area
pointed to by the area argument. Is there an undocumented limitation ?

My assumption was that the size of “area” would be rounded to a page
boundary, and a VM mapping set up that would be made available to the
interrupt handler.

If the size of area is not limited, then you can certainly access
class data in an interrupt handler (the fact that I currently do this
at least hints at the possibility > :slight_smile:

That isn’t what I mean. If you simply pass a pointer to a class and it’s
size you will get the class itself, but if it has any explict or implicit
pointers they will not always be valid. So it isn’t a size issue so much as
having the data all in a linear virtual address space.

chris


Chris McKillop <cdm@qnx.com> “The faster I go, the behinder I get.”
Software Engineer, QSSL – Lewis Carroll –
http://qnx.wox.org/