I started to write an OpenGL library and was only a couple of dozen
lines into the pir when I remembered the documentation about callbacks
in docs/pdds/draft/pdd16_native_call.pod .

Currently there are only two signatures supported on callbacks: one
with user_data and extern_data and the other with extern_data and
user_data (the positions are all that is different).  These are nice
and general functions and work well because the user_data is/should be
opaque to the calling C function, the user_data provides a place to
store the PMC, and the user_data is used to lookup the interpreter
that should be used to run the sub stored in the PMC.  The pdd says
that outside the two provided signatures, anybody wanting to implement
NCI connections to callback functions will need to do some hand C
coding.  Hand C coding isn't at all bad, but it would be nice to have
a generic mechanism for storing callbacks from C functions that don't
provide a slot for opaque user_data.  I was on my way to coding a
solution with my meager C skills and wanted to make sure that what I
was doing was sane (for some definition of the word sane).

So my proposal goes something like this:

 - Get a new unique id from a new op called get_callback_id
 - Call a variant of the new_callback op, passing in the unique id
 - The new_callback variant stores the user data under the unique id
 - The callback references a unique C function that will return that unique id
 - When the callback is fired, the unique id is used to lookup the user_data
 - Any external data is parsed as needed
 - The registered sub is played

Ok, sounds hard enough - but it gets worse.  Here is how I would
implement this generic callback system and what I think would be
required.

There will probably need to a file similar to src/call_list.txt such
as src/callback_list.txt with entries similar to:

10 v v
10 v ii

Where the first number is the number of functions to pre-create, and
the other two parts are the return type and signature.  I'd rather not
have the number be hardcoded and go with a jit solution or some other
solution for runtime C function generation - but I'm not aware of
anything else that would work besides pre-compiled C functions.  I think it 
would be nice if libraries could generate/compile the needed functions
independent of anything hardcoded (and that goes for call_list.txt too
for that matter).

The entires in callback_list.txt would generate functions similar to the 
following in nci.c
 # parrot callback functions
 void pcbf_v_JV_0(void) # depending up signature
 void pcbf_v_JV_1(void)
 ...
 void pcbf_v_JV_9(void)


I would then add two more ops (I shudder to say that - I'm not sure if
adding ops is a frowned upon thing).  Those ops are (I haven't played
with it to know if this is the right format):

  op get_callback_id(out INT, in STR)
  # the output is a unique INT for the given signature in STR
  # it would fail if called more times than the 10 listed
  # in callback_list.txt (unless a jit solution could be implemented)

  op delete_callback_id(in INT, in STR)
  # deletes the user_data in the storage structure, freeing it
  # for later use


Currently the following op is defined in src/ops/core.ops:

   op new_callback(out PMC, invar PMC, invar PMC, in STR)

I want to add one more variant of this op

  op new_callback(out PMC, in INT, invar PMC, invar PNC, in STR)

Another piece that is required is that there be a global
ResizablePMCArray (actually there may be multiple based on the
registered signatures).  Again, I can hear everybody shuddering at the
mention of a global.  I don't know enought about parrot yet to know if
it should be a true global variable, or if it should be tied to an
interpreter, or if there is somewhere I should register the PMC with,
or if there is already a central structure that would take care of
functions like this.

My questions are:

 - Does anybody else want a generic callback function mechanism in NCI?
 - Is this a relatively sane/clean way to do it?
 - Is there a better way to generate the functions for each signature?
 - What is the right way to store that global user_data until the callbacks 
are fired?

I don't think I've been clear enough, but I'll post and then answer
questions.  I think that it would be good to have something that
libraries could use without having to drop down to the C level - I
just am not sure if this is too much bloat to implement it.

Paul Seamons
I've been here all along - I'm just really quiet.

Reply via email to