[Openmcl-cvs-notifications] r11802 - /trunk/source/doc/src/ffi.xml
rme at clozure.com
rme at clozure.com
Sat Feb 28 21:18:22 EST 2009
Author: rme
Date: Sat Feb 28 21:18:22 2009
New Revision: 11802
Log:
Minor editing and updates to tutorial about allocating foreign data.
Modified:
trunk/source/doc/src/ffi.xml
Modified: trunk/source/doc/src/ffi.xml
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- trunk/source/doc/src/ffi.xml (original)
+++ trunk/source/doc/src/ffi.xml Sat Feb 28 21:18:22 2009
@@ -2399,48 +2399,34 @@
<sect1 id=3D"Tutorial--Allocating-Foreign-Data-on-the-Lisp-Heap">
<title>Tutorial: Allocating Foreign Data on the Lisp Heap </title>
<para>Not every foreign function is so marvelously easy to use
- as the ones we saw in the last section. Some of them require
- you to allocate a C struct, fill it in with your own
- information, and pass it a pointer to the struct. Some of them
- require you to allocate an empty struct so they can fill it in,
- and then you can read the information out of it.</para>
- <para>Also, some of them have their own structs and return a
- pointer to that same struct every time you call them, but those
- are easier to deal with, so they won't be covered in this
- section.</para>
- <para>You might know that Lisp (and, indeed, most programming
- languages) has two separate regions of memory. There's the
- stack, which is where variable bindings are kept. Memory on the
- stack is allocated every time any function is called, and
- deallocated when it returns, so it's useful for anything that
- doesn't need to last longer than one function call, when there's
- only one thread. If that's all you need, you can do it with
- .</para>
- <para>Then, there's the heap, which holds everything else, and
- is our subject here. There are two advantages and one big
- disadvantage to putting things on the heap rather than the
- stack. First, data allocated on the heap can be passed outside
- of the scope in which it was created. This is useful for data
- which may need to be passed between multiple C calls or multiple
- threads. Also, some data may be too large to copy multiple times
- or may be too large to allocate on the stack.</para>
- <para>The second advantage is security. If incoming data is
- being placed directly onto the stack, the input data can cause
- stack overflows and underflows. This is not something which
- Lisp users generally worry about since garbage collection
- generally handles memory management. However, "stack smashing"
- is one of the classic exploits in C which malicious hackers can
- use to gain control of a machine. Not checking external data is
- always a bad idea; however, allocating it into the heap at least
- offers more protection than direct stack allocation.</para>
+ as the ones we saw in the last section. Some functions require
+ you to allocate a C struct, fill it with your own
+ information, and pass in a pointer to that struct. Some of them
+ require you to allocate an empty struct that they will fill in
+ so that you can read the information out of it.</para>
+ <para>There are generally two ways to allocate foreign data. The
+ first way is to allocate it on the stack; the RLET macro is one way to=
do this.
+ This is analogous to using automatic variables in C. In the
+ jargon of Common Lisp, data allocated this way is said to have
+ dynamic extent.</para>
+ <para>The other way to heap-allocate the foreign data. This is
+ analogous to calling malloc in C. Again in the jargon of Common
+ Lisp, heap-allocated data is said to have indefinite extent. If a
+ function heap-allocates some data, that data remains valid even
+ after the function itself exits. This is useful for data which
+ may need to be passed between multiple C calls or multiple
+ threads. Also, some data may be too large to copy multiple times
+ or may be too large to allocate on the stack.</para>
<para>The big disadvantage to allocating data on the heap is
that it must be explicitly deallocated—you need to "free" it
- when you're done with it. Ordinarily, in Lisp, you wouldn't
- allocate memory yourself, and the garbage collector would know
- about it, so you wouldn't have to think about it again. When
- you're doing it manually, it's very different. Memory
- management becomes a manual process, just like in C and
- C++.</para>
+ when you're done with it. Normal Lisp objects, even those with inde=
finite
+ extent, are deallocated by the garbage collector when it can prove
+ that they're no longer referenced. Foreign data, though, is outside=
the
+ GC's ken: it has no way to know whether a blob of foreign data is s=
till
+ referenced by foreign code or not. It is thus up to the programmer
+ to manage it manually, just as one
+ does in C with malloc and free.
+ </para>
<para>What that means is that, if you allocate something and
then lose track of the pointer to it, there's no way to ever
free that memory. That's what's called a memory leak, and if
@@ -2522,32 +2508,6 @@
<programlisting>
gcc -dynamiclib -Wall -o libptrtest.dylib ptrtest.c -install_name ./=
libptrtest.dylib
</programlisting>
- <para>If that command doesn't make sense to you, feel free to go back
- and read about it at .</para>
- <para>Now, start &CCL; and enter:</para>
- <programlisting>
- ? ;; make-heap-ivector courtesy of Gary Byers
- (defun make-heap-ivector (element-count element-type)
- (let* ((subtag (ccl::element-type-subtype element-type)))
- (unless (=3D (logand subtag target::fulltagmask)
- target::fulltag-immheader)
- (error "~s is not an ivector subtype." element-type))
- (let* ((size-in-bytes (ccl::subtag-bytes subtag element-count)))
- (ccl::%make-heap-ivector subtag size-in-bytes element-count)))) =
=
- MAKE-HEAP-IVECTOR
-
- ? ;; dispose-heap-ivector created for symmetry
- (defmacro dispose-heap-ivector (a mp)
- `(progn
- (ccl::%dispose-heap-ivector ,a)
- ;; Demolish the arguments for safety
- (setf ,a nil)
- (setf ,mp nil)))
- DISPOSE-HEAP-IVECTOR
- </programlisting>
- <para>If you don't understand how those functions do what they do.
- That's okay; it gets into very fine detail which really doesn't
- matter, because you don't need to change them.</para>
<para>The function <literal>make-heap-ivector</literal> is the
primary tool for allocating objects in heap memory. It
allocates a fixed-size &CCL; object in heap memory. It
@@ -2658,33 +2618,14 @@
<para>There is one final bit of housekeeping to deal with.
Before moving on, the memory needs to be deallocated:</para>
<programlisting>
- ? ;; dispose-heap-ivector created for symmetry
- ;; Macro repeated here for pedagogy
- (defmacro dispose-heap-ivector (a mp)
- `(progn
- (ccl::%dispose-heap-ivector ,a)
- ;; Demolish the arguments for safety
- (setf ,a nil)
- (setf ,mp nil)))
- DISPOSE-HEAP-IVECTOR
-
? (dispose-heap-ivector a ap)
- NIL
-
- ? a
- NIL
-
- ? ap
NIL
</programlisting>
<para>The <literal>dispose-heap-ivector</literal> macro actually
deallocates the ivector, releasing its memory into the heap for
- something else to use. In addition, it makes sure that the
- variables which it was called with are set to nil, because
- otherwise they would still be referencing the memory of the
- ivector - which is no longer allocated, so that would be a bug.
- Making sure there are no other variables set to it is up to
- you.</para>
+ something else to use. Both <literal>a</literal> and <literal>ap</l=
iteral>
+ now have undefined values.
+ </para>
<para>When do you call <literal>dispose-heap-ivector</literal>?
Anytime after you know the ivector will never be used again, but
no sooner. If you have a lot of ivectors, say, in a hash table,
More information about the Openmcl-cvs-notifications
mailing list