Changeset 11802


Ignore:
Timestamp:
Mar 1, 2009, 2:18:22 AM (10 years ago)
Author:
rme
Message:

Minor editing and updates to tutorial about allocating foreign data.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/source/doc/src/ffi.xml

    r10800 r11802  
    24002400    <title>Tutorial: Allocating Foreign Data on the Lisp Heap </title>
    24012401    <para>Not every foreign function is so marvelously easy to use
    2402       as the ones we saw in the last section.  Some of them require
    2403       you to allocate a C struct, fill it in with your own
    2404       information, and pass it a pointer to the struct.  Some of them
    2405       require you to allocate an empty struct so they can fill it in,
    2406       and then you can read the information out of it.</para>
    2407     <para>Also, some of them have their own structs and return a
    2408       pointer to that same struct every time you call them, but those
    2409       are easier to deal with, so they won't be covered in this
    2410       section.</para>
    2411     <para>You might know that Lisp (and, indeed, most programming
    2412       languages) has two separate regions of memory.  There's the
    2413       stack, which is where variable bindings are kept.  Memory on the
    2414       stack is allocated every time any function is called, and
    2415       deallocated when it returns, so it's useful for anything that
    2416       doesn't need to last longer than one function call, when there's
    2417       only one thread.  If that's all you need, you can do it with
    2418       .</para>
    2419     <para>Then, there's the heap, which holds everything else, and
    2420       is our subject here.  There are two advantages and one big
    2421       disadvantage to putting things on the heap rather than the
    2422       stack.  First, data allocated on the heap can be passed outside
    2423       of the scope in which it was created.  This is useful for data
    2424       which may need to be passed between multiple C calls or multiple
    2425       threads. Also, some data may be too large to copy multiple times
    2426       or may be too large to allocate on the stack.</para>
    2427     <para>The second advantage is security.  If incoming data is
    2428       being placed directly onto the stack, the input data can cause
    2429       stack overflows and underflows.  This is not something which
    2430       Lisp users generally worry about since garbage collection
    2431       generally handles memory management.  However, "stack smashing"
    2432       is one of the classic exploits in C which malicious hackers can
    2433       use to gain control of a machine.  Not checking external data is
    2434       always a bad idea; however, allocating it into the heap at least
    2435       offers more protection than direct stack allocation.</para>
     2402      as the ones we saw in the last section.  Some functions require
     2403      you to allocate a C struct, fill it with your own
     2404      information, and pass in a pointer to that struct.  Some of them
     2405      require you to allocate an empty struct that they will fill in
     2406      so that you can read the information out of it.</para>
     2407    <para>There are generally two ways to allocate foreign data.  The
     2408    first way is to allocate it on the stack; the RLET macro is one way to do this.
     2409    This is analogous to using automatic variables in C.  In the
     2410    jargon of Common Lisp, data allocated this way is said to have
     2411    dynamic extent.</para>
     2412    <para>The other way to heap-allocate the foreign data.  This is
     2413    analogous to calling malloc in C.  Again in the jargon of Common
     2414    Lisp, heap-allocated data is said to have indefinite extent. If a
     2415    function heap-allocates some data, that data remains valid even
     2416    after the function itself exits.  This is useful for data which
     2417    may need to be passed between multiple C calls or multiple
     2418    threads. Also, some data may be too large to copy multiple times
     2419    or may be too large to allocate on the stack.</para>
    24362420    <para>The big disadvantage to allocating data on the heap is
    24372421      that it must be explicitly deallocated&mdash;you need to "free" it
    2438       when you're done with it.  Ordinarily, in Lisp, you wouldn't
    2439       allocate memory yourself, and the garbage collector would know
    2440       about it, so you wouldn't have to think about it again.  When
    2441       you're doing it manually, it's very different.  Memory
    2442       management becomes a manual process, just like in C and
    2443       C++.</para>
     2422      when you're done with it.  Normal Lisp objects, even those with indefinite
     2423      extent, are deallocated by the garbage collector when it can prove
     2424      that they're no longer referenced.  Foreign data, though, is outside the
     2425      GC's ken:  it has no way to know whether a blob of foreign data is still
     2426      referenced by foreign code or not. It is thus up to the programmer
     2427      to manage it manually, just as one
     2428      does in C with malloc and free.
     2429    </para>
    24442430    <para>What that means is that, if you allocate something and
    24452431      then lose track of the pointer to it, there's no way to ever
     
    25232509      gcc -dynamiclib -Wall -o libptrtest.dylib ptrtest.c -install_name ./libptrtest.dylib
    25242510    </programlisting>
    2525     <para>If that command doesn't make sense to you, feel free to go back
    2526       and read about it at .</para>
    2527     <para>Now, start &CCL; and enter:</para>
    2528     <programlisting>
    2529       ? ;; make-heap-ivector courtesy of Gary Byers
    2530       (defun make-heap-ivector (element-count element-type)
    2531        (let* ((subtag (ccl::element-type-subtype element-type)))
    2532         (unless (= (logand subtag target::fulltagmask)
    2533                  target::fulltag-immheader)
    2534          (error "~s is not an ivector subtype." element-type))
    2535         (let* ((size-in-bytes (ccl::subtag-bytes subtag element-count)))
    2536          (ccl::%make-heap-ivector subtag size-in-bytes element-count))))     
    2537       MAKE-HEAP-IVECTOR
    2538 
    2539       ? ;; dispose-heap-ivector created for symmetry
    2540       (defmacro dispose-heap-ivector (a mp)
    2541        `(progn
    2542          (ccl::%dispose-heap-ivector ,a)
    2543          ;; Demolish the arguments for safety
    2544          (setf ,a nil)
    2545          (setf ,mp nil)))
    2546       DISPOSE-HEAP-IVECTOR
    2547     </programlisting>
    2548     <para>If you don't understand how those functions do what they do.
    2549       That's okay; it gets into very fine detail which really doesn't
    2550       matter, because you don't need to change them.</para>
    25512511    <para>The function <literal>make-heap-ivector</literal> is the
    25522512      primary tool for allocating objects in heap memory.  It
     
    26592619      Before moving on, the memory needs to be deallocated:</para>
    26602620    <programlisting>
    2661       ? ;; dispose-heap-ivector created for symmetry
    2662       ;; Macro repeated here for pedagogy
    2663       (defmacro dispose-heap-ivector (a mp)
    2664       `(progn
    2665       (ccl::%dispose-heap-ivector ,a)
    2666       ;; Demolish the arguments for safety
    2667       (setf ,a nil)
    2668       (setf ,mp nil)))
    2669       DISPOSE-HEAP-IVECTOR
    2670 
    26712621      ? (dispose-heap-ivector a ap)
    2672       NIL
    2673 
    2674       ? a
    2675       NIL
    2676 
    2677       ? ap
    26782622      NIL
    26792623    </programlisting>
    26802624    <para>The <literal>dispose-heap-ivector</literal> macro actually
    26812625      deallocates the ivector, releasing its memory into the heap for
    2682       something else to use.  In addition, it makes sure that the
    2683       variables which it was called with are set to nil, because
    2684       otherwise they would still be referencing the memory of the
    2685       ivector - which is no longer allocated, so that would be a bug.
    2686       Making sure there are no other variables set to it is up to
    2687       you.</para>
     2626      something else to use.  Both <literal>a</literal> and <literal>ap</literal>
     2627      now have undefined values.
     2628      </para>
    26882629    <para>When do you call <literal>dispose-heap-ivector</literal>?
    26892630      Anytime after you know the ivector will never be used again, but
Note: See TracChangeset for help on using the changeset viewer.