Here is (I think) a more flexible approach:
1) A new opcode "callback" (or "register_cb") or such, which is working
like the current dlfunc opcode:
callback (out Pcb, in Psub, in Sig)
Pcb ... NCI function object for that callback function
Psub ... Parrot Sub PMC to be called on behalf of that C callback
Sig ... Signature of the C-callback function
Sig allows additionally one special signature char "U" user-data, which
is "Z" in pdd16, but I can remember <U>ser-data better ;)
So void (*PQnoticeProcessor)(void *, const char*) would have Sig "vUt"
and call a Parrot function f(P, S). Pdd16 type C callback is e.g. "vpU".
2) Actually registering the callback.
dlfunc (out Pfunc, in Plib, "func_with_cb", "vCU")
.pcc_begin prototpyed
.arg Pcb
.arg P_user_data
.nci_call Pfunc
That is instead of passing in the callback and the Parrot Sub ("CY" in
pdd16) the PMC obtained from 1) is passed with signature "C". The
calling signature matches again the C-function which we call.
When now calling this function the action behind the scene is the same:
The passed user_data PMC is combined with the callback PMC obtained from
1) and passed on to the C function. When the C function is doing the
callback, the NCI-stub generated in 1) is called, which extracts the
Parrot subroutine from the passed user data and passes on the original
user PMC and finally calls the PASM callback function.
But as the generated NCI stub in 1) knows the callback signature, this
scheme should be appropriate for all callback functons, that have at
least one "void *" user parameter to be passed on transparently.
Comments welcome,
leo
Well...
The current system's simple on purpose, because making sure all the
possible callback function signatures are supported would just be a
massive pain in the neck. (Not that we're not going well into the
nuts category with the current NCI setup--nci.o is 143K on my system
right now--but there are limits even for me :)
Before we go extend things any more, let's get the current system
fleshed out some (heck, let's get it working!) and then use it as a
base to proceed. The first order of business is for me to get pdd16's
examples a bit better fleshed out so folks know what I'm talking
about, and then go from there.
--
Dan
--------------------------------------"it's like this"-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk
> Well...
> The current system's simple on purpose, because making sure all the
> possible callback function signatures are supported would just be a
> massive pain in the neck.
> Before we go extend things any more, let's get the current system
> fleshed out some (heck, let's get it working!)
I've now implemented that as far as pdd16 goes. It requires one more step
(as already proposed in the previous f'up in this thread):
new_callback P5, P6, P7, "tU" # Z in pdd16
This constructs a callback PMC P5 from Sub P6 and user_data P7. The
actual callbacks signature is "xU" for callback_C or "Ux" for
callback_D. The signature char 'x' can be currently any of the integer
types or 't'. So we have a notion for the external_data we get passed on
in the callback.
This separate step seems to be necessary anyway, because the NCI
function could await that callback embeded in some structure, so we can't
always pass it on directly, like pdd16 does.
The signature type for the callback ('C' in pdd16) isn't currently
needed, the 'p' type is used instead. And I've used 'U' for user_data
not 'Z' like in pdd16.
Almost all other constraints from pdd16 are still true:
- the callback must pass on one void* user_data transparently
- the CB takes exactly 2 params, castable to void*
Finally getting a callback asynchronously isn't a problem, because
callbacks are run via the event system.
Do we still need the "do it all at once" shortcut from pdd16?
leo