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