[EMAIL PROTECTED] wrote:
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 .

[...]

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?

NCI isn't fully specified yet, but I'll outline some of our current thoughts and likely directions. Discussion welcome.

We would like to eliminate the massive list of precompiled thunks for C function calls generated by call_list.txt. The tricky part is that you can't compile a C function at runtime. The best you can do is JIT it, and that depends on having a working JIT for the platform. We might be able to use LLVM's JIT, which would gain us a working JIT on a number of platforms.

The JIT solution would continue to use the dlfunc interface, but instead of looking up a precompiled thunking function for the passed in signature, it would JIT one. As with the precompiled thunk, the JITed thunk is incorporated into an NCI sub object, which can be stored in a namespace, or passed around anonymously, and invoked, just like an ordinary sub object.

That said, it's unlikely that we'll ever completely eliminate the list of precompiled thunks. Some platforms just won't have a JIT, and we can't afford to cut off NCI for the lack of a JIT. (For one thing, Parrot internals use NCI quite heavily.) But we can make them more manageable. We'll probably end up with something similar to src/ops/*.ops, with multiple files of signatures. The core file would be the absolute minimum required to run Parrot without loading external C libraries. Then we could add a file for each subsystem (MySQL, Postgres, pcre, SDL, Python builtins, and tcl, are a few already mentioned in call_list.txt). A configuration option when compiling Parrot could decide whether to precompile a restricted set, the full set, or add in some additional signatures for another external system. Some signature files for a particular library could be generated by a limited C parser, but it would always need to be checked by a human. Duplicate signatures between files would be merged. (And remember, this is only a fallback for platforms that can't JIT.)

So, that's one part of the question. The other part is callbacks. If/when we develop a JIT solution for NCI call thunks, we can use the same technique for generating callback thunks. In the mean time, we'll have to continue with the precompiled callback thunks.

Callbacks will use the concurrency scheduler. (There's some info about the concurrency scheduler in the new Events PDD, but more details will be in the Concurrency PDD next month.) For the moment all you need to know is that the concurrency scheduler is a central dispatcher in the Parrot interpreter that handles events, exceptions, async I/O, threads, etc.

When you call 'new_callback', you pass it a Parrot sub, a user_data argument, and a signature. At the moment the signature is limited to two alternatives, in the future it will allow all the same signature options as an NCI call. The signature of the Parrot sub should match the signature passed into 'new_callback'.

The 'new_callback' op will take these arguments and create a CallbackHandler PMC which stores the user data and the passed in sub, as well as any other information needed to properly invoke the right sub in the right interpreter. It then registers that CallbackHandler with the concurrency scheduler. Registering a callback handler returns a unique concurrency id (CID) for the handler, kind of like a process id.

After registering the callback handler, 'new_callback' will look up a precompiled thunk or JIT a thunk with the requested signature. For the JITed thunk it will embed the CID as a constant within the thunk. For precompiled thunks, we're probably going to have to add more information to the CallbackHandler PMC (the signature, possibly a library identifier, etc).

When the callback thunk is called from C, it bundles the C arguments into appropriate Parrot arguments, then notifies the concurrency scheduler that it has a callback with a particular CID, or particular set of characteristics (similar to scheduling an event of a particular type). The concurrency scheduler will look through its registered callback handlers to look for a matching handler, and if it finds one, invoke it, passing it the arguments that were passed to the C thunk.

Essentially, this uses the concurrency scheduler as your global data store and as the source of unique identifiers. But, it's integrated with a core system.

The immediate solution, to get OpenGL working now without waiting for the implementation of the concurrency scheduler and JITed call/callback thunks, is to add a few more callback signatures to the current set of alternatives, and to write a little bit of custom C code for the cases that can't pass dispatch information in a user data argument.

I wouldn't go so far as implementing the callback_list.txt option at this point. You'll have at least a basic implementation of the concurrency scheduler by December 1st as we need it for events.

Allison

Reply via email to