NAME
docs/pdds/pdd16_native_call.pod - NCI conventions and definitions
ABSTRACT
This PDD describes the native call interface, and the function signatures used to describe those functions.
DESCRIPTION
The NCI is designed to allow Parrot to interface to most of the functions in a C library without having to write any C code for that interface. It isn't designed to be a universal C-less interface--there will always be libraries that have some bizarre parameter list that requires that some C be written. It should, however, handle all the simple cases.
Using the NCI, parrot automatically wraps the C functions and presents them as prototyped subroutines that follow normal parrot calling conventions, and can be called like any other parrot subroutine.
The NCI uses the platform native dynamic by-name function loading mechanism (dlopen/dlsym on unix and LoadLibrary/GetProcAddress on Win32, for example) to get the function pointer, then dynamically generates the wrapper based on the signature of that function.
As there is no good platform-independent way to determine function signatures (C header files are not always available (certainly not for libraries not designed for access from C) and not always reasonably parseable anyway, and there is no generic way to query a function for its signature) the signature must be passed in when the linkage between the C function and parrot is made.
Function signatures
The following list are the valid letters in the function signatures for Parrot's NCI. Note that only letters and numbers are valid, and each letter represents a single parameter passed into the NCI. Note that the letters are case-sensitive, and must be within the base 7-bit ASCII character set.
At some point punctuation may be used as modifiers on the function parameters, in which case each parameter may be represented by multiple letters.
In no case should the signature letters be separated by whitespace. This restriction may be lifted in the future, but for now remains as an avenue for adding additional functionality.
- v
-
Void. As a return type indicates that there is no return type. As a parameter indicates that there are no parameters. Can't be mixed with other parameter types.
- c
-
Char. This is an integer type, taken from (or put into) an I register. NOTE: it might be signed or unsigned because that is how an unadorned C 'char' works.
- s
-
short. An integer type, taken from or put into an I register. It is always signed, not unsigned.
- i
-
int. An integer type. It is always signed, not unsigned.
- l
-
long. An integer type. You know the drill. It is always signed, not unsigned.
- f
-
float. F register denizen.
- d
-
double. F register, double-precision floating point type
- P
-
A PMC register.
- p
-
PMC thingie. A generic pointer, taken from or stuck into a PMC's data pointer. If this is a return type, parrot will create a new UnManagedStruct PMC type, which is just a generic "pointer so some damn thing or other" PMC type which Parrot does no management of.
- 2
-
A pointer to a short, taken from an P register of an int-like PMC. On return from NCI, the PMC_int_val will hold the new value.
- 3
-
A pointer to an int, taken from an P register of an int-like PMC. On return from NCI, the PMC_int_val will hold the new value.
- 4
-
A pointer to a long, taken from an P register of an int-like PMC. On return from NCI, the PMC_int_val will hold the new value.
- t
-
string pointer. Taken from, or stuck into, a string register. (Converted to a null-terminated C string before passing in)
- C
-
This parameter is used for passing in a callback function pointer. It refers to the function Parrot_callback_C, which has a signature of:
void Parrot_callback_C(void *external_data, PMC *callback_info);
More explanation in the callbacks section.
- D
-
This parameter is used for passing in a callback function pointer. It refers to the function Parrot_callback_C, which has a signature of:
void Parrot_callback_D(PMC *callback_info, void *external_data);
More explanation in the callbacks section.
- Y
-
This parameter is a PMC for the sub which should be called into by the callback. Only valid in a signature with a C or D parameter, and it must be immediately followed by a parameter of type Z.
- Z
-
This parameter is a PMC representing the data to be passed into the function being called into. It is only valid when it immediately follows a parameter of type Y.
Note that not all types are valid as return types.
Examples
Most of the function parameters are reasonably self-evident. Some, however, merit additional explanation. The
Callbacks
Some libraries, particularly ones implementing more complex functionality such as databases or GUIs, want callbacks, that is ways to call a function under the control of the library rather than under control of the interpreter. These functions must be C functions, and generally are passed parameters to indicate what should be done.
Unfortunately there's no good way to generically describe all possible callback parameter sets, so in some cases hand-written C will be necessary. However, many callback functions share a common signature, and parrot provides some ready-made functions for this purpose that should serve for most of the callback uses.
There are two callback functions, Parrot_callback_C and Parrot_callback_D, corresponding to callback function signature letters C and D, respectively. If the callback function is supposed to look like:
void (function *)(void *library_data, void *your_data);
then use type C, where if the function signature is:
void (function *)(void *your_data, void *library_data);
then use a type of D. The actual pointer types for the parameters don't have to be void *, but they must be pointers of some sort.
Since parrot needs more than just a pointer to a generic function to figure out what to do, it stuffs all the extra information into the your_data
pointer, which contains a custom PMC holding all the information that Parrot needs.
The NCI function signature for a callback matching Parrot_callback_C is vCYZ
, while the function signature for a callback matching Parrot_callback_D is vDYZ
.
The callback functions take care of wrapping the external data pointer into an UnManagedStruct PMC, the same as if it were a p return type of a normal NCI function.
The signature of the parrot subroutine which is called by the callback should be:
void parrotsub(PMC user_data, PMC external_data)
The sequence for this is:
- Step 1
-
Register the function which takes all the callback information
dlfunc CALLBACK_REGISTER_FUNC, LIBRARY_PMC, FUNCTION_NAME, 'vCYZ'
- Step 2
-
Register the actual callback
newsub $P5, .Sub, _some_parrot_sub # Alternately, if it's in a global # $P5 = global "some::sub::name" new $P6, .PerlInt # The data we get handed .pcc_begin prototyped .arg $P5 .arg $P6 .pcc_call CALLBACK_REGISTER_FUNC .pcc_end
- Step 3
-
Hand over control to the external library. IT IS IMPORTANT THAT THE INTERPRETER YOU ARE CALLING BACK INTO IS NOT ACTIVE WHEN THE CALLBACK IS MADE!
When the callback function is invoked by the external library, the function itself should look like:
.sub _my_callback prototyped
.param pmc my_data
.param pmc library_data
# Do something with the passed in data
.end
Parrot itself handles all the nasty bits involved in collecting up the interpreter pointer, creating the wrapping PMCs, stuffing data various places, and generally dealing with the bookkeeping.
REFERENCES
VERSION
CURRENT
Maintainer: Dan Sugalski
Class: Internals
PDD Number: 16
Version: 1.0
Status: Developing
Last Modified: December 28, 2003
PDD Format: 1
Language: English
HISTORY
CHANGES
3 POD Errors
The following errors were encountered while parsing the POD:
- Around line 102:
Expected text after =item, not a number
- Around line 107:
Expected text after =item, not a number
- Around line 112:
Expected text after =item, not a number