Another silly primitive question
Lex Spoon
lex at cc.gatech.edu
Tue Feb 16 22:33:19 UTC 1999
Chris Reuter <cgreuter at calum.csclub.uwaterloo.ca> wrote:
> Tcl has its faults, but its interface to C is the most elegant that
> I've seen. A glue function gets an integer (argc) and an array of
> strings[1] (argv). A bunch of functions are provided to convert the
> individual arguments to C data types. For example, "Tcl_GetInt" will
> attempt to convert its argument to an integer. On failure, it returns
> an error code and sets the error flag in the interpreter so all the
> glue routine has to do is return the constant TCL_ERROR. If you want
> to do something fancy, you can always ignore the error and try again.
>
> I was able to write quite a lot of them easily using cut+paste and
> search+replace. (I found out too late that swig would have done all
> this for me. Oh well...)
>
> In contrast, linking to external C[2] code from Squeak requires:
>
> 1) Writing a CrossTalk[3] method and adding it to the interpreter.
> 2) Writing C routine to launder the arguments.
> 3) Decoding object headers to check types, get lengths and do
> general Object-to-C-type conversion.
> 4) Doing the reverse when returning values to Squeak.
>
Hmm, I'm not so sure it's all that involved. It could be easier, to be
sure....
Here is a slightly cleaned-up primitive I wrote recently; it plays a
CDROM under Linux. The main interface functions used are:
stackObjectValue(i) -- returns an oop
stackIntegerValue(i) -- returns an integer, if its a valid
SmallInteger; else signals a primitive failure
pop(n) -- pop a number of levels from the stack
There's a zillion functions like this defined at the top of sq.h -- they
are free for use!
The big caveats seem to be:
- you have to remember to do error checking, especially on input
parameters!
- fix up the stack correctly (leave it alone on errors, and leave just
one item on success)
Here it is:
/* play a sequence of tracks */
int cdrom_playFromTo(void)
{
struct cdrom_info info;
int rcvr, from, to;
struct cdrom_ti ti;
/* module initialization */
init_session();
/* retrieve arguments */
rcvr = stackObjectValue(2);
from = stackIntegerValue(1);
to = stackIntegerValue(0);
if(!success) {
/* one or more of the arguments was screwed up */
return 0;
}
#ifdef TRACE
fprintf(stderr, "playing from %d to %d\n", from, to);
#endif
/* check the reciever */
get_cdrom_info(rcvr, &info); /* another routine I wrote that
grabs some instance variables out of rcvr */
if(!success) {
/* wrong reciever type, probably */
return 0;
}
if(standard_check(&info)) {
primitiveFail();
return 0;
}
/* okay, do the playing (nothing Squeak specific involved) */
ti.cdti_trk0 = from;
ti.cdti_trk1 = to;
ti.cdti_ind0 = ti.cdti_ind1 = 0;
if(ioctl(cdrom_fd, CDROMPLAYTRKIND, &ti)) {
perror("CDROMPLAYTRKIND");
primitiveFail();
return 0;
}
/* fix up the stack */
pop(2);
/* return value is ignored */
return 1;
}
This seems only a little more complicated than it would be in Tcl
(judging only by your comments--I've never actually done anything with
Tcl).
I guess MY big suggestion at this point, would be for some
*documentation* to be made. Things like "how to clean up the stack",
"how to check argument types", "how to decode integers" would be a great
set of initial explanations to make up a "Squeak Pluggable Primitive
HOWTO".
(And no, I'm not volunteering to get it rolling myself, because I don't
even have time to be responding on this thread :))
Lex
> So, my thoughts went, why not write a Tcl-style API for calling native
> functions from Squeak? There would be a small set of primitives and
> accompanying C routines to convert Squeak objects (at least a small
> subset thereof) to C types, copying them to an external data
> structure, and passing this structure to the external C glue routine.
> The glue routine would then use another group of functions to test for
> type and possibly retrieve the data, just like the Tcl_Get* functions.
> A similar set of routines would allow one or more objects to be
> returned to the caller.
>
> I haven't given too much thought to what the Smalltalk end would look
> like--probably a class "ExternalLibrary" that handles dynamic loading
> and implements methods like #invokeExternal:withArgs: and subclasses
> for specific commonly-used libraries.
>
> This setup has the advantages of being simple, easy to use and a lot
> safer, since all the hairy stuff is hidden. Also, because the
> external routines never need to touch the image, we can mark the
> object memory as read-only (on those platforms that support it[4])
> just before calling the glue routine and unlock it afterward. That
> way, if there's an image-trashing bug, it will immediately come to
> light. (Performance considerations might make this feasable only as a
> debugging tool.)
>
> I actually started hacking together the beginnings of the above, but
> then I started hearing about pluggable primitives so shelved it lest I
> reinvent the wheel, badly. I haven't had a chance to look at them yet
> so I don't know if the above still has any worth. I thought I'd throw
> out the ideas, anyway.
>
>
> --Chris
>
>
>
> [1] Which, it turns out, are not necessarily that easy. Tcl is
> actually a relatively decent language in its own right (but nowhere
> near as good as Smalltalk).
>
> [2] Substitute your favourite compiled programming language.
>
> [3] My proposal for the offical catchy name for the subset of
> Smalltalk that can be translated to C.
>
> [4] I know it can be done under UnixWare, Linux, OS/2 and Win16 (via
> some DMPI calls in assembly language--ick). I would guess that the
> rest must also have some way of doing this, since they all have MMUs.
More information about the Squeak-dev
mailing list
|