[Home]
[Edit this page]
[Recent Changes]
[Special Pages]
[Help]
QbasicFAQ_ChangeColors » iTV » MUMPS » QbasicFAQ_Inkey » CPU » help » complexnumbers » CppCli » WhatLinksHere » QbasicFAQ_EventDriven » thunks
Displaying differences between revision 11 and the latest revision
Some libraries, like sax, may take a function as an argument with one less parameter than you need. Expat, a sax implementation for XML http://expat.sourceforge.net/ , for example, takes global function pointers as the callback argument. This can be annying if you want a reentrant parser. ¶
¶
How you can associate the callback function with an instance of an object if you are using the same parser from different threads, or how can you avoid global variables?¶
¶
It is possible using a thunk technique.¶
¶
Suppose you wanted all your callbacks to reference a class or struct:¶
¶
[code]struct CallbackHelper¶
{¶
//a bunch of variables ...¶
}[/code]¶
¶
and your api requires a callback like this¶
¶
[code]typedef void (*callback)(int callback_supplied1,¶
double callback_supplied2)[/code]¶
¶
but you need a CallbackHelper passed to your version:¶
¶
[code]typedef void (*Mycallback)(int callback_supplied1,¶
double callback_supplied2, CallbackHelper *myObject)[/code]¶
¶
Many languages provide a nice way to do this with a closure or partial application or lambda lifting. Haskell, emacs lisp, Ruby, python, and many more have decent support for this case. ¶
¶
For languages that don't, you have to create a callback object which pushes the extra argument on the stack and then continues on to the real callback. ¶
¶
C and C++ are lacking in built in support, but there is a workaround. Create a thunk, an intermediate callback, that pushes your hidden argument onto the stack and calls your final callback. You have to create a thunk for each function you want called back to which you want to supply extra arguments.¶
¶
1. Create a space for the thunk. The best place is within CallbackHelper¶
[code]struct CallbackHelper¶
{¶
// a bunch of variables¶
...¶
//space for the thunk¶
unsigned thunk[16]; //whatever, just make sure its enough.¶
}[/code]¶
¶
2. write your callback including your CallbackHelper¶
[code]staticvoid myCallback(int callback_supplied1, double callback_supplied2,¶
CallbackHelper *me);[/code]¶
¶
3. Create the thunk, usally with a macro or other function.¶
[code]thunk[0]=push &myCallbackHelper //according to your instruction set¶
thunk[1]=jump myCallback //according to your instruction set[/code]¶
If you have aprotected memory operating system, like Windows NT/XP/9X/2K, you have to make sure the thunk is executable. The virtual memory functions in windows allow this to be done quite easily.[br]¶
You can replace the jump myCallback with a callMyCallback;return if you need to do something more involved with the arguments (reorder them etc).[br]¶
¶
4. Register the callback. ¶
[code]//coerce thunk into the right type.¶
callback callWithMyStructure=(callback)(thunk);¶
//register with the underlying library¶
CallMeBackWithSomethingUseful(callWithMyStructure)[/code]¶
¶
5. Be careful.¶
¶
Don't delete the thunk until there are no more references to it. If you delete your callback object and then dereference it, you are asking for a crash whether or not you are using thunk techniques. ¶
¶
However, with the thunk techniuqe, if you have destroyed the thunk and it gets called back from somewhere, not only will you crash, but you will be wondering why your instruction pointer is in your data space.¶
¶
Although this is an unusual technique, it is not especially dangerous and is something libraries you may be using already do, maybe your tcp/IP stack or embedded OS. Certainly, its nothing more complicated than what your compiler does -- its pretty bogus there is no partial application built into C, but you can roll your own when you need to.¶
¶
The Active Template Library (ATL) for windows COM program does exactly the above technique to create a function call that can invoke an instance method on a class. It does this because window classes in ATL are classes, and windows callbacks for particular windows messages are static functions.
[Edit this page] [Page history] [What links here] [Discuss this topic] [Printer Friendly]
QbasicFAQ_ChangeColors » iTV » MUMPS » QbasicFAQ_Inkey » CPU » help » complexnumbers » CppCli » WhatLinksHere » QbasicFAQ_EventDriven » thunks
Displaying differences between revision 11 and the latest revision
¶
How you can associate the callback function with an instance of an object if you are using the same parser from different threads, or how can you avoid global variables?¶
¶
It is possible using a thunk technique.¶
¶
Suppose you wanted all your callbacks to reference a class or struct:¶
¶
[code]struct CallbackHelper¶
{¶
//a bunch of variables ...¶
}[/code]¶
¶
and your api requires a callback like this¶
¶
[code]typedef void (*callback)(int callback_supplied1,¶
double callback_supplied2)[/code]¶
¶
but you need a CallbackHelper passed to your version:¶
¶
[code]typedef void (*Mycallback)(int callback_supplied1,¶
double callback_supplied2, CallbackHelper *myObject)[/code]¶
¶
¶
For languages that don't, you have to create a callback object which pushes the extra argument on the stack and then continues on to the real callback. ¶
¶
C and C++ are lacking in built in support, but there is a workaround. Create a thunk, an intermediate callback, that pushes your hidden argument onto the stack and calls your final callback. You have to create a thunk for each function you want called back to which you want to supply extra arguments.¶
¶
1. Create a space for the thunk. The best place is within CallbackHelper¶
[code]struct CallbackHelper¶
{¶
// a bunch of variables¶
...¶
//space for the thunk¶
unsigned thunk[16]; //whatever, just make sure its enough.¶
}[/code]¶
¶
2. write your callback including y
[code]static
CallbackHelp
¶
3. Create
[code]thunk
thunk
If you have a
You can replace the jump myCallback with a callMyCallback;return if you need to do something more involved with the arg
¶
4. Register the callbac
[code
callback callWithMyStructure=(callback)(thunk);¶
//register with the underlying library¶
CallMeBackWithSomethingUseful(callWithMyStructure)[/code
¶
5. Be careful.¶
¶
Don't delete the thunk until there are no more references to it. If you delete your callback object and then dereference it, you are asking for a crash whether or not you are using thunk techniques. ¶
¶
However, with the thunk techniuqe, if you have destroyed the thunk and it gets called back from somewhere, not only will you crash, but you will be wondering why your instruction pointer is in your data space.¶
¶
Although this is an unusual technique, it is not especially dangerous and is something libraries you may be using already do, maybe your tcp/IP stack or embedded OS. Certainly, its nothing more complicated than what your compiler does -- its pretty bogus there is no partial application built into C, but you can roll your own when you need to.¶
¶
The Active Template Library (ATL) for windows COM program does exactly the above technique to create a function call that can invoke an instance method on a class. It does this because window classes in ATL are classes, and windows callbacks for particular windows messages are static functions
[Edit this page] [Page history] [What links here] [Discuss this topic] [Printer Friendly]
