[plt-scheme] 3m

From: Jon Rafkind (workmin at ccs.neu.edu)
Date: Sun Jul 2 01:42:32 EDT 2006

Matthew Flatt wrote:
> At Sat, 01 Jul 2006 20:57:12 -0400, Jon Rafkind wrote:
>>> Both of the major obstacles above have recently become much smaller:
>>>  * Using the "foreign.ss" library with 3m is usually not much more
>>>    difficult than with CGC. As our library bindings have migrated to
>>>    "foreign.ss" (instead of writing the glue in C), using 3m has
>>>    become much easier.
>>>    Meanwhile, we also have mzc --xform (and a better tool in the
>>>    pipeline) for transforming C-implemented glue code to work with 3m.
>> I just tried drscheme3m with the C library, Allegro, that I use for
>> doing graphics; drscheme crashed immediately upon initializing the
>> Allegro system. I dont understand how using foreign.ss would make 3m
>> handle C pointers better, but from the above paragraph I was under the
>> impression that it would Just Work( TM ).
> It will Just Work ( TM ) for simple uses, where no GCable data is kept
> by the foreign library across call. For example, the simple FFI uses in
> MzLib's "os.ss" need no special treatment for 3m.
> When a library holds a reference to a GCable across interaction with
> MzScheme, though, the problem is that the 3m GC might move the object.
> For example, in your Allegro binding, GC-managed data gets registered
> with the library for use later:
>  (define rgb-map (let ((f (malloc _RGBMAP (* 32 32 32))))
>                    (cpointer-push-tag! f RGBMAP-tag)
>                    (set-RGBMAP-data! f f)
>                    (set-ffi-obj! "rgb_map" liballegro _RGBMAP-pointer f)
>                    f))
> With CGC, this works ok. The module-level binding to `rgb-map' ensures
> that the allocated object won't get collected, and since the GC never
> moves objects, the allocated object will stay where the library expects
> to find it.
> With the 3m GC, although the allocated object won't get GCed, it may be
> moved in memory.
> One solution to the problem is to allocate the object with 'raw, which
> uses the system malloc(), so the resulting object is not GCed (and not
> moved). You can attach a finalizer to something that free the
> malloc()ed object, maybe like this:
>  (define rgb-map (let* ((r (malloc 'raw _RGBMAP (* 32 32 32)))
>                         (f (make-rgb-map-wrapper r)))
>                    (set-ffi-obj! "rgb_map" liballegro _RGBMAP-pointer r)
>                    (register-finalizer r (lambda (r) (free f)))
>                    f))
> Beware, though, that a 'raw object shouldn't refer to GCable objects,
> since 'raw memory is not traversed by the GC. Refering to other 'raw
> objects is no problem, of course, and 'raw is always fine for atomic
> data (which is the intent in the example above, I think).
> Movement of GCable objects is the main challenge for connecting 3m with
> foreign libraries.
I removed all the pointers in allegro.ss that are used in the Allegro
library like rgb-map, they are legacy things anyway which shouldnt be
used. I'm still getting a crash with 3m but the problem seems to lie
elsewhere. If I run this code in 3m it crashes:

(require (planet "image.ss" ("kazzmir" "allegro.plt" 1 0)))
(require (planet "util.ss" ("kazzmir" "allegro.plt" 1 0)))
(easy-init 640 480 16)
(define x (create 200 200))
;; crash

Basically it just sets up the Allegro system and creates a memory bitmap
then immediately segfaults. (create) calls into allegro using
create_bitmap which returns a pointer. 3m just moves objects it knows
about around but not the values of the objects so the pointer returned
from (create) should always point to the same thing right?

 Things seem to break as soon as I store something returned from Allegro
in a scheme variable. The following also breaks:

(require (planet "image.ss" ("kazzmir" "allegro.plt" 1 0)))
(require (planet "util.ss" ("kazzmir" "allegro.plt" 1 0)))
(easy-init 640 480 16)
;; ok
(define x (screen))
;; crash

Where screen is
(define-struct image (bitmap width height))
(define (screen)
   (let ((b (allegro-screen))
     (make-image b (BITMAP-w b) (BITMAP-h b))))

And allegro-screen is defined as a c parameter:
(define screen (make-c-parameter "screen" liballegro _BITMAP-pointer))

Posted on the users mailing list.