Ah Lance welcome to the wonderful world of C++ ABI.
All non-static member functions in C++ have an implied 'first'
argument that is a this pointer.
Hence the C++ function declaration of
virtual void timeoutOccurred(IOTimerEventSource *sender);
is equivalent to the C declaration (with some poetic licence) :-
struct MY_CLASS_NAME_vtable {
struct MY_BASE_CLASS_vtable supervtable;
...
void (*timeoutOccurred)(MY_CLASS_NAME *this, IOTimerEventSource
*sender);
...
);
In IOKit we chose to mostly use C function pointers in our Target/
Action/Parameter (TAP) idiom. This means that a conversion must be
made from C++ to C, this is easy and direct for static member
functions but is indirect for non-static member functions.
Now the C++ police get very upset with me when I start doing this, as
they would like the flexibility of being able to arbitrarily change
the ABI for non-static member functions. However they operate in a
cloud-cuckoo-land where ever piece of C++ code is recompiled every
time a new compiler is used or a header changes and sometimes even an
implementation changes. This is implied with the egregious
'template' concept.
Unfortunately in the real world we had to provide binary
compatibility in a cross module way. This implied that the C++ ABI
was locked down from the moment that IOKit was released (causing
angst). Since we have locked down this ABI it is perfectly safe to
use our knowledge of the C++ ABI to call a member function from a C
TAP. This also causes angst.
IYAI: There are to mechanisms in C++ for dealing with function
pointers. The is the classic C style pointer to a function and there
is the C++ pointer to member function. One would think that the
conversion of C++ to C pointers would be unstable against new
compilers and so it has proved at a source code level, however at the
ABI level it has been rock solid. However the pointer to member
function code broke at the ABI level, we needed get a compiler change
made to support 10.0 & 10.1 drivers.
Godfrey
On 05/25/2005, at 12:03 , Lance Drake wrote:
The answer depends on what type of function timeoutOccured is.
Action is defined as
typedef void (*Action)(OSObject *owner, IOTimerEventSource *sender);
1> It is a static member function. In this case the owner and
sender arguments are what you would expect.
2> You are using a normal member function or virtual member
function. In this case the owner argument is passed to you in the
'this' pointer. Eg
virtual void timeoutOccurred(IOTimerEventSource *sender) is
the correct declaration and you use OSCastMemberFunction to
convert it into a IOTimerEventSource::Action, then in your
void MY_CLASS_NAME::(IOTimerEventSource *sender)
{
#if DEBUG
if (!OSDynamicCast(MY_CLASS_NAME, this))
; // We have a problem log it.
#endif
}
Godfrey
Hi Godfrey,
Thank you so much for responding. I note two interesting
things in your example.
1) There is only one argument for the timeouthandler - which is
different from the sample code where there are two arguments - as
in "void TimerEventSample::timeoutHandler(OSObject *owner,
IOTimerEventSource *sender)"
2) if (!OSDynamicCast(MY_CLASS_NAME, this)) refers to 'this' and
not the incoming argument of 'sender'.