Index: /trunk/source/doc/src/openmcl-documentation.xml
===================================================================
--- /trunk/source/doc/src/openmcl-documentation.xml	(revision 8516)
+++ /trunk/source/doc/src/openmcl-documentation.xml	(revision 8516)
@@ -0,0 +1,11371 @@
+<?xml version="1.0" encoding="US-ASCII"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
+<!ENTITY rest "<varname><property>&amp;rest</property></varname>">
+<!ENTITY key "<varname><property>&amp;key</property></varname>">
+<!ENTITY optional "<varname><property>&amp;optional</property></varname>">
+<!ENTITY body "<varname><property>&amp;body</property></varname>">
+<!ENTITY aux "<varname><property>&amp;aux</property></varname>">
+<!ENTITY allow-other-keys
+         "<varname><property>&amp;allow-other-keys</property></varname>">
+]>
+<book lang="en">
+ <bookinfo>
+  <title>OpenMCL Documentation</title>
+ </bookinfo>
+
+ <chapter><title>Obtaining, Installing, and Running OpenMCL</title>
+  
+  <sect1><title>Releases and System Requirements</title>
+   
+   <para>There are three active versions of OpenMCL.  Version 1.0 was
+   a stable release (released in late 2005); it is no longer under
+   active development.  Version 1.1 has been under active development
+   since shortly after 1.0 was released; it's been distributed as a
+   series of development "snapshots" and CVS updates.  1.1 snapshots
+   have introduced support for x86-64 platforms, internal use of
+   Unicode, and many other features, but have presented something of a
+   moving target.  Version 1.2 (being released in early 2008) is
+   intended to both a more stable and predictable release schedule and
+   to make it a bit easier for users who wish to track the "bleeding
+   edge" of development to do so.</para>
+
+      <para>Version 1.0 is available for three platform configurations:</para>
+      <itemizedlist>
+        <listitem>
+          <para>Linux on PowerPC (32-bit implementation)</para>
+        </listitem>
+        <listitem>
+          <para>Mac OS X on PowerPC (32-bit implementation)</para>
+        </listitem>
+        <listitem>
+          <para>Mac OS X on PowerPC (64-bit implementation)</para>
+        </listitem>
+      </itemizedlist>
+
+      <para>Versions 1.1 and 1.2 are available for five platform
+      configurations:</para>
+      <itemizedlist>
+        <listitem>
+          <para>Linux on PowerPC (32-bit and 64-bit implementations)</para>
+        </listitem>
+        <listitem>
+          <para>>Mac OS X on PowerPC (32-bit and 64-bit implementations)</para>
+        </listitem>
+        <listitem>
+          <para>Linux on X86-64 (64-bit implementation)</para>
+        </listitem>
+        <listitem>
+          <para>Mac OS X on X86-64 (64-bit implementation)</para>
+        </listitem>
+        <listitem><para>FreeBSD on X86-64 (64-bit implementation)</para></listitem>
+      </itemizedlist>
+
+      <para>A 64-bit version of OpenMCL requires a 64-bit processor
+      (obviously) running a 64-bit OS variant.</para>
+      
+      <para>There are ongoing efforts to port OpenMCL to the Windows
+      operating system and 32-bit x86 processors.</para>
+      
+      
+      <para>Additional platform-specific information is given in the
+      following subsections.</para>
+
+      <sect2><title>LinuxPPC</title> 
+        
+        <para>OpenMCL versions 1.0 and later run under relatively
+        recent versions of LinuxPPC. All versions of OpenMCL require
+        version 2.2.13 (or later) of the Linux kernel and version
+        2.1.3 (or later) of the GNU C library (glibc) at a bare
+        minimum.</para>
+      </sect2>
+
+      <sect2><title>LinuxX8664</title> 
+
+        <para>Version 1.1 and later of OpenMCL runs on relatively
+        recent Linux distributions for the x86-64 architecture.  It
+        requires a Linux with Thread Local Storage support in the
+        toolchain and standard libraries, and the New Posix Thread
+        Library (NPTL).  Fortunately, these features seem to be
+        present in all current Linux distributions for x86-64, though
+        there may be some problems with early Linux distributions for
+        x86-64.  (Some GCC versions older than 4.0 on Linux have been
+        known to have problems compiling some of the C code in the
+        kernel, some very old Linux distributions don't follow the
+        current ABI standards wrt segment register usage, some early
+        Linux kernels for x86-64 had problems mapping large regions of
+        the address space ... it's difficult to enumerate exactly what
+        versions of what Linux distributions have what problems.  A
+        rule of thumb is that - since much of the development of
+        OpenMCL for x86-64 took place in that time frame - Linux
+        distributions released earlier than early 2006 may have
+        problems running OpenMCL.) </para>
+      </sect2>
+
+      <sect2><title>FreeBSD-amd64</title>
+        <para>Versions 1.1 and later of OpenMCL runs on FreeBSD on
+        x86-64 (FreeBSD releases generally call the platform "and64")
+        OpenMCL should run under FreeBSD 6.0 or later; as of this
+        writing, FreeBSD 7.0 is about to be released and it may be
+        necessary for FreeBSD 7 users to install the "compat6x"
+        package in order to use a version of OpenMCL built on FreeBSD
+        6.x under FreeBSD 7.  .</para>
+      </sect2>
+
+      <sect2><title>DarwinPPC-MacOS-X</title>
+
+        <para> OpenMCL 1.0 runs on MacOS X versions 10.2, 10.3 and
+        10.4 on the PowerPC.</para>
+
+        <para>Current development on version 1.1 and later takes place
+        under OS X versions 10.4 and 10.5 and requires at least
+        version 10.3.9</para>
+
+        <para>The 64-bit DarwinPPC version of OpenMCL requires
+        functionality introduced in OSX 10.4 (namely, the ability to
+        run 64-bit binaries).  It also, obviously, requires a G5
+        processor.</para>
+
+        <para>OpenMCL hasn't been tested under Darwin proper, but
+        OpenMCL doesn't intentionally use any MacOS X features beyond
+        the Darwin subset and therefore it seems likely that OpenMCL
+        would run on PPC Darwin versions that correspond to recent OSX
+        versions.</para>
+      </sect2>
+
+      <sect2><title>Darwinx8664-MacOS-X</title>
+        <para>Versions 1.1 and later of OpenMCL runs on 64-bit
+        DarwinX86 (MacOS on Intel).</para>
+
+        <para>OpenMCL Darwinx8664/MacOS X requires a 64-bit processor.
+        All Macintoshes currently sold by Apple (as of early 2008) and
+        all Macintoshes introduced by Apple since August 2006 have
+        such processors.  However, the original MacBooks, MacBook Pros
+        and Intel iMacs (models introduced in early 2006) used 32-bit
+        Core Duo processors, and so OpenMCL will not (yet) run on
+        them.</para>
+
+      </sect2>
+    </sect1>
+
+    <sect1><title>Installation</title>
+      <para>Installing OpenMCL consists of</para>
+      <orderedlist> 
+        <listitem>
+          <para>Downloading an appropriate distribution of OpenMCL;</para>
+        </listitem>
+        <listitem>
+          <para>If necessary, extracting the archive somewhere on your
+          computer;</para>
+        </listitem>
+        <listitem>
+          <para>Configuring a shell script so OpenMCL can locate
+          necessary library files and other auxilliary files.</para>
+        </listitem>
+      </orderedlist>
+
+      <sect2><title>Downloading and untarring OpenMCL binary source
+      releases</title> <para> OpenMCL releases and snapshots are
+      distributed as tarballs (compressed tar archives).</para>
+
+      <para>Tarballs of version 1.0 for supported platforms are
+      available from the download page of the OpenMCL website.</para>
+
+      <para>Tarballs of the latest development snapshots of version
+      1.1, along with release notes, are available from the testing
+      directory on Clozure.com.</para>
+      <para>Both the release and snapshot archives contain a directory
+      named <literal>ccl</literal>, which in turn contains a number of
+      files and subdirectories.  The <literal>ccl</literal> directory
+      can reside anywhere in the filesystem, assuming appropriate
+      permissions. If you wanted the <literal>ccl</literal> directory
+      to reside in <literal>``~/openmcl/ccl''</literal> and the
+      directory <literal>``~/openmcl/''</literal> already existed, you
+      could do anything equivalent to:</para>
+      <programlisting>
+shell&gt; cd ~/openmcl
+shell&gt; tar xvzf <emphasis>path-to-downloaded-openmcl-archive.tar.gz</emphasis>
+      </programlisting>
+      <para><emphasis>Important Note for Macintosh Users:</emphasis>
+      Double-clicking the archive in the Finder may work, but it also
+      may have unintended side-effects.  In some versions of the Mac
+      OS double-clicking an archive will invoke Stuffit, which may try
+      to replace linefeeds with carriage returns as it extracts
+      files. Also, tar can be used to merge the archive contents into
+      an existing <literal>ccl</literal> directory, whereas
+      double-clicking in the Finder will create a new directory named
+      <literal>ccl 2</literal> (or <literal>ccl 3</literal>, or...)
+      Bottom line is that you're better off using tar from the
+      shell.</para>
+
+      <para>Once the <literal>ccl</literal> directory is installed,
+      it's necessary to install and configure a shell script
+      distributed with OpenMCL before using it.</para>
+      </sect2>
+
+      <sect2><title>The-openmcl-Shell-Script"</title>
+      <para>OpenMCL needs to be able to find the
+      <literal>ccl</literal> directory in order to support features
+      such as <literal>require</literal> and
+      <literal>provide</literal>, access to foreign interface
+      information (see ) and the lisp build process (see
+      ). Specifically, it needs to set up logical pathname
+      translations for the <literal>"ccl:"</literal> logical host.  If
+      this logical host isn't defined (or isn't defined correctly),
+      some things might work, some things might not... and it'll
+      generally be hard to invoke and use OpenMCL productively.</para>
+
+        <para>OpenMCL uses the value of the environment variable
+        <literal>CCL_DEFAULT_DIRECTORY</literal> to determine the
+        filesystem location of the <literal>ccl</literal> directory;
+        the openmcl shell script is intended to provide a way to
+        invoke OpenMCL with that environment variable set
+        correctly.</para>
+        <para>There are two versions of the shell script:
+        <literal>"ccl/scripts/openmcl"</literal> is used to invoke
+        32-bit implementations of OpenMCL and
+        <literal>"ccl/scripts/openmcl64"</literal> is used to invoke
+        64-bit implementations.</para>
+        <para>To use the script:</para>
+        <orderedlist>
+          <listitem>
+            <para>Edit the definition of
+            <literal>CCL_DEFAULT_DIRECTORY</literal> near the
+            beginning of theshell script so that it refers to your ccl
+            directory.  Alternately,set
+            <literal>CCL_DEFAULT_DIRECTORY</literal> in your .cshrc,
+            .tcshrc, .bashrc,.bash_profile, .MacOSX/environment.plist,
+            or wherever you usually set environment variables.  If
+            there is an existing definition of thevariable, the
+            openmcl script will not override it.The shell script sets
+            a local variable (<literal>OPENMCL_KERNEL</literal>) to
+            the standard name of the OpenMCL kernel approprate for the
+            platform (asdetermined by 'uname -s'.) You might prefer to
+            set this variable manually in the shell script</para>
+          </listitem>
+
+          <listitem>
+            <para>Ensure that the shell script is executable, for
+            example:<literal>$ chmod +x
+            ~/openmcl/ccl/scripts/openmcl64</literal>This command
+            grants execute permission to the named script. If you
+            areusing a 32-bit platform, substitute "openmcl" in place
+            of "openmcl64".
+            <warning>
+	      <para>The above command won't work if you are not the
+	      owner of the installed copy of OpenMCL. In that case,
+	      you can use the "sudo" command like this:</para>
+              <para><literal>$ sudo chmod +x
+              ~/openmcl/ccl/scripts/openmcl64</literal></para>
+              <para>Give your password when prompted.</para>
+              <para>If the "sudo" command doesn't work, then you are
+              not an administrator on the system you're using, and you
+              don't have the appropriate "sudo" permissions. In that
+              case you'll need to get help from the system's
+              administrator.</para>
+            </warning></para>
+          </listitem>
+          <listitem>
+            <para>Install the shell script somewhere on your shell's
+            search path</para>
+          </listitem>
+        </orderedlist>
+
+        <para>Once this is done, it should be possible to invoke
+        OpenMCL by typing <literal>openmcl</literal> at a shell
+        prompt:</para>
+        <programlisting>
+&gt; openmcl [args ...]
+Welcome to OpenMCL Version whatever (DarwinPPC32)!
+?
+</programlisting>
+        <para>The openmcl shell script will pass all of its arguments
+        to the OpenMCL kernel.  See <xref linkend="invocation"/> for
+        more information about "args".  When invoked this way, the
+        lisp should be able to initialize the
+        <literal>"ccl:"</literal> logical host so that its
+        translations refer to the <literal>"ccl"</literal>
+        directory. To test this, you can call
+        <literal>probe-file</literal> in OpenMCL's read-eval-print
+        loop:</para>
+        <programlisting>
+? (probe-file "ccl:level-1;level-1.lisp")  ;will return the physical pathname of the file
+#P"/Users/alms/my_lisp_stuff/ccl/level-1/level-1.lisp"
+</programlisting>
+      </sect2>
+
+      <sect2 id="Personal-Customization-with-the-Init-File">
+	<title>Personal Customization with the Init File</title>
+        <para>By default OpenMCL will try to load the file
+        <literal>"home:openmcl-init.lisp"</literal> or the compiled
+	
+        <literal>"home:openmcl-init.fasl"</literal> upon starting
+        up. It does this by executing <literal>(load
+        "home:openmcl-init")</literal>.  If it is unable to load the
+        file (for example because it does not exist) no action is
+        taken; an error is not signalled.</para>
+        <para>The <literal>"home:"</literal> prefix to the filename is
+        a Common Lisp logical host, which OpenMCL initializes to refer
+        to your home directory, so this looks for either of the files
+        <literal>~/openmcl-init.lisp</literal> or
+        <literal>~/openmcl-init.fasl</literal>.</para>
+        <para>Since the init file is loaded the same way as normal
+        Lisp code is, you can put anything you want in it.  For
+        example, you can change the working directory, and load
+        packages which you use frequently.</para>
+        <para>To suppress the loading of this init-file, invoke OpenMCL with the
+<literal>--no-init</literal> option.</para>
+      </sect2>
+
+      <sect2 id="Some--hopefully--useful-options">
+	<title>Some (hopefully) useful options</title>
+        <para> The exact set of command-line arguments accepted by
+        OpenMCL may vary slightly from release to release;
+        <literal>openmcl --help</literal> will provide a definitive
+        (if somewhat terse) summary of the options accepted by the
+        current implementation and then exit. Some of those options
+        are described below.</para>
+	<itemizedlist>
+	  <listitem>
+	    <para>-S (or --stack-size). Specify the size of the initial process
+	    stack.</para>
+	  </listitem>
+
+	  <listitem>
+	    <para>-b (or --batch). Execute in &#34;batch mode&#34;. End-of-file
+	    from *STANDARD-INPUT* will cause OpenMCL to exit, as will attempts to
+	    enter a break loop.</para>
+	  </listitem>
+
+	  <listitem>
+	    <para>-n (or --no-init). If this option is given, the init file
+	    is not loaded.  This is useful if OpenMCL is being invoked by a
+	    shell script which should not be affected by whatever
+	    customizations a user might have in place.
+	    </para>
+	  </listitem>
+
+	  <listitem>
+	    <para>-e &#60;form&#62; (or --eval &#60;form&#62;). An expression is
+	    read (via READ-FROM-STRING from the string &#60;form&#62; and
+	    evaluated. If &#60;form&#62; contains shell metacharacters, it may be
+	    necessary to escape or quote them to prevent the shell from
+	    interpreting them.</para>
+	  </listitem>
+
+	  <listitem>
+	    <para>-l &#62;path&#62; (or --load &#60;path&#62;). Executes (load
+	    &#34;&#60;path&#62;&#34;).</para>
+	  </listitem>
+	</itemizedlist>
+
+        <para>The <literal>--load</literal> and
+        <literal>--eval</literal> options can each be provided
+        multiple times.  They're executed in the order specified on
+        the command line, after the init file (if there is one) is
+        loaded and before the toplevel read-eval-print loop is
+        entered.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Using-OpenMCL-with-GNU-Emacs-and-SLIME">
+      <title>Using OpenMCL with GNU Emacs and SLIME</title>
+      <para>A very common way to use OpenMCL is to run it within the
+      GNU Emacs editor, using a Lisp interface called SLIME ("Superior
+      Lisp Interaction Mode for Emacs"). SLIME is an Emacs package
+      designed to provide good support within Emacs for any of several
+      Common Lisp implementations; one of the supported
+      implementations is OpenMCL. This page describes how you can
+      download SLIME and set it up to work with your OpenMCL
+      installation.</para>
+      <para>Why use SLIME? With SLIME, you can do the following things from within
+an Emacs editing session:</para>
+      <itemizedlist>
+        <listitem><para>run and control Lisp</para></listitem>
+        <listitem><para>evaluate, compile, and load files or expressions</para></listitem>
+        <listitem><para>macroexpand expressions</para></listitem>
+        <listitem><para>fetch documentation and source code for Lisp symbols</para></listitem>
+        <listitem><para>autocomplete symbols and package names</para></listitem>
+        <listitem><para>cross-reference function calls</para></listitem>
+        <listitem><para>examine stack traces and debug errors</para></listitem>
+      
+      </itemizedlist>
+      <para>There is an excellent SLIME tutorial video available at
+Common-Lisp.net.  For
+complete information about SLIME, see the
+SLIME home page.</para>
+
+      <sect2 id="Assumptions-and-Requirements">
+	<title>Assumptions and Requirements</title>
+        <para>In order to simplify these instructions, we'll make
+        several assumptions about your system. Specifically, we
+        assume:</para>
+        <itemizedlist>
+          <listitem>
+	    <para>You have a working installation of GNU Emacs. If you
+	    don't have a working copy of GNU Emacs, see the web page on
+	    obtaining Emacs.  If you prefer to use XEmacs instead of
+	    GNU Emacs,these instructions should still work; SLIME
+	    supports XEmacs Version21. Mac OS X includes an Emacs
+	    installation.  If you want to look into different versions,
+	    you can check out theEmacsWiki, whichmaintains a
+	    page,EmacsForMacOS,that provides much more information
+	    about using Emacs on the Mac.
+            <warning>
+              <para>A popular version of Emacs among Mac users is
+              Aquamacs. This application is a version of GNU Emacs
+              with a number of customizations meant to make it behave
+              more like a standard Maciontosh application, with
+              windows, a menubar, etc.  Aquamacs includes SLIME; if
+              you like Aquamacs then you can use SLIME right away,
+              without getting and installing it separately. You just
+              need to tell SLIME where to find your installation of
+              OpenMCL. (See FIXTHIS.)</para>
+            </warning>
+	  </para>
+	  </listitem>
+          <listitem>
+            <para>You have a working copy of OpenMCL, installed in
+            <literal>"~/openmcl/ccl"</literal>If you prefer to install
+            OpenMCL in some directory other
+            than<literal>"~/openmcl/ccl"</literal> then these
+            instructions still work, but you must remember to use your
+            path to your ccl directory instead of theone that we give
+            here.</para>
+          </listitem>
+          <listitem>
+            <para>You install emacs add-ons in the folder
+            <literal>"~/emacs/site/"</literal>If this directory
+            doesn't exist on your system, you can just create it.If
+            you prefer to install Emacs add-ons in some place other
+            than<literal>"~/emacs/site/"</literal> then you must
+            remember to use your path toEmacs add-ons in place of
+            ours.</para>
+          </listitem>
+        
+        </itemizedlist>
+      </sect2>
+
+      <sect2 id="Getting_Slime"><title>Getting SLIME</title>       
+
+        <para>You can get SLIME from the SLIME Home Page. Stable
+        releases and CVS snapshots are available as archive files, or
+        you can follow the instructions on the SLIME Home Page to
+        check out the latest version from their CVS repository.</para>
+
+        <para>It's worth noting that stable SLIME releases happen very
+        seldom, but the SLIME developers often make changes and
+        improvements that are available through CVS updates. If you
+        asked the SLIM developers, they would most likely recommend
+        that you get SLIME from their CVS repository and update it
+        frequently.</para>
+
+        <para>Whether you get it from CVS, or download and unpack one
+        of the available archives, you should end up with a folder
+        named "slime" that contains the SLIME distribution.</para>
+      </sect2>
+
+      <sect2><title>Installing SLIME</title> 
+
+        <para>Once you have the "slime" folder described in the
+        previous section,installation is a simple matter of copying
+        the folder to the proper place. You can drag it into the
+        "~/emacs/site/" folder, or you can use a terminal command to
+        copy it there. For example, assuming your working directory
+        contains the unpacked "slime" folder:</para> <para><literal>$
+        cp -R slime ~/emacs/site/</literal></para> <para>That's all it
+        takes.</para>
+
+      </sect2>
+
+      <sect2 id="Telling-Emacs-About-SLIME">
+	<title>Telling Emacs About SLIME</title>
+        <para> Once SLIME and OpenMCL are installed, you just need to
+        add a line to your "~/.emacs" file that tells SLIME where to
+        find the script that runs OpenMCL:</para>
+        <para><literal>(setq inferior-lisp-program "~/openmcl/ccl/scripts/openmcl64")</literal></para>
+        <para>or</para>
+        <para><literal>(setq inferior-lisp-program "~/openmcl/ccl/scripts/openmcl")</literal></para>
+        <warning>
+          <para>Aquamacs users should add this line to the file "~/Library/Preferences/Aquamacs Emacs/Preferences.el".</para>
+        </warning>
+      </sect2>
+
+      <sect2 id="Running-OpenMCL-with-SLIME">
+	<title>Running OpenMCL with SLIME</title>
+        <para>Once the preparations in the previous section are
+        complete, exit Emacs and restart it, to ensure that it reads
+        the changes you made in your ".emacs" file (alternatively, you
+        could tell Emacs to reload the ".emacs" file). If all went
+        well, you should now be ready to run OpenMCL using
+        SLIME.</para>
+        <para>To run OpenMCL, execute the command "M-x slime". SLIME
+        should start an OpenMCL session in a new buffer.  (If you are
+        unfamiliar with the Emacs notation "M-x command", see the GNU
+        Emacs FAQ; specifically, take a look at questions 1, 2, and
+        128.)</para>
+      </sect2>
+
+      <sect2 id="What-if-a-New-Version-of-OpenMCL-Breaks-SLIME-">
+	<title>What if a New Version of OpenMCL Breaks SLIME?</title>
+	<para>Sometimes you'll get a new version of OpenMCL, set up
+	Emacs to use it with SLIME, and SLIME will fail. Most likely
+	what has happened is that the new version of OpenMCL has a
+	change in the output files produced by the compiler (OpenMCL
+	developers will say "the fasl version has changed." fasl
+	stands for &ldquo;fast load&rdquo; aka compiled files). This
+	problem is easy to fix: just delete the existing SLIME fasl
+	files. The next time you launch Emacs and start SLIME, it will
+	automatically recompile the Lisp files, and that should fix
+	the problem.</para>
+        <para>SLIME's load process stores its fasl files in a hidden
+        folder inside your home folder. The path is</para>
+        <para><literal>~/.slime/fasl</literal></para>
+        <para>You can use a shell command to remove the fasl files, or
+        remove them using your system's file browser.</para>
+        <screen><emphasis role="bold">Note for Macintosh
+        Users:</emphasis> The leading "." character in the ".slime"
+        folder's name prevents the Finder from showing this folder to
+        you. If you use the "Go To Folder" menu item in the Finder's
+        "Go" menu, you can type in "~/.slime" and the Finder will show
+        it to you. You can then drag the "fasl" folder to the trash.
+	</screen>
+      </sect2>
+
+      <sect2 id="Known-Bugs">
+	<title>Known Bugs</title>
+	<para>SLIME has not been updated to account for recent changes
+	made in OpenMCL to support x86-64 processors. You may run into
+	bugs running on those platforms.</para>
+        <para>The SLIME backtrace sometimes shows incorrect information.</para>
+        <para><literal>return-from-frame</literal> and
+        <literal>apply-in-frame</literal> do not work reliably.  (If
+        they work at all, it's pure luck.)</para>
+        <para>Some versions of Emacs on the Macintosh may have trouble
+        finding the shell script that runs OpenMCL unless you specify
+        a full path to it. See the above section "Telling Emacs About
+        SLIME" to learn how to specify the path to the shell
+        script.</para>
+        <para>For more help with OpenMCL on Mac OS X, consult the
+        OpenMCL mailing lists.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Example-Programs">
+      <title>Example Programs</title>
+      <para>Beginning with release 0.9, a number (ok, a
+      <emphasis>small</emphasis> number, at least initially) of
+      example programs are distributed in the "ccl:examples;"
+      directory of the source distribution. See the
+      README-OPENMCL-EXAMPLES text file in that directory for
+      information about prerequisites and usage.</para>
+      <para>Some of the example programs are derived from C examples
+      in textbooks, etc.; in those cases, the original author and work
+      are cited in the source code.</para>
+      <para>It may be a stretch to imply that the examples have a
+      great deal of value as "intellectual property", but I might as
+      well say this: Unless the original author or contributor claims
+      other rights, you're free to incorporate any of this example
+      code or derivative thereof in any of you're own works without
+      restriction. In doing so, you agree that the code was provided
+      "as is", and that no other party is legally or otherwise
+      responsible for any consequences of your decision to use
+      it.</para>
+      <para>If you've developed OpenMCL examples that you'd like to
+      see added to the distribution, please send mail to let me
+      know. Any such contributions would be welcome and appreciated
+      (as would bug fixes and improvements to the existing
+      examples.)</para>
+    </sect1>
+  </chapter>
+
+  <chapter><title>Building OpenMCL from its Source Code</title>
+
+    <para>OpenMCL, like many other Lisp implementations, consists of a
+    kernel and a heap image.  The kernel is an ordinary C program, and
+    is built with a C compiler.  It provides very basic and
+    fundamental facilities, such as memory management, garbage
+    collection, and bootstrapping.  All the higher-level features are
+    written in Lisp, and compiled into the heap image.  Both parts are
+    needed to have a working Lisp implementation; neither the kernel
+    nor the heap image can stand on their own.</para>
+
+    <para>You may already know that, when you have a C compiler which
+    is written in C, to build the compiler, you need to already have a
+    C compiler available.  The heap image includes a Lisp compiler,
+    which is written in Lisp.  Therefore, you need a working Lisp
+    compiler in order to build the heap image!</para>
+    
+    <para>Where will you get a working Lisp compiler?  No worries; you
+    can use a precompiled copy of a (slightly older and compatible)
+    version of OpenMCL.  For help, read on.</para>
+
+    <para>In principle it would be possible to use another Lisp as the
+    host compiler, rather than an old OpenMCL; this would be a
+    challenging and experimental way to build, and is not described
+    here.</para>
+
+    <sect1 id="building-definitions"><title>>building definitions</title>
+      <para>The following terms are used in subsequent sections; it
+      may be helpful to refer to these definitions.</para>
+
+      <para><indexterm><primary>fasl files</primary></indexterm> are
+      the object files produced by<literal>compile-file</literal>.
+      fasl files store the machine codeassociated with function
+      definitions and the external representationof other lisp objects
+      in a compact, machine-readable form. fasl is short for
+      &ldquo;<literal>FAS</literal>t
+      <literal>L</literal>oading&rdquo;.OpenMCL uses different
+      pathname types (extensions) to name faslfiles on different
+      platforms; see <xref
+      linkend="Platform-specific-filename-conventions"/> </para>
+
+      <para>The <indexterm><primary>lisp kernel</primary></indexterm> is
+      a C program (with a fair amount ofplatform-specific assembly
+      language code as well.)  Its basic job isto map a lisp heap
+      image into memory, transfer control to somecompiled lisp code
+      that the image contains, handle any exceptionsthat occur during
+      the execution of that lisp code, and provide variousother forms
+      of runtime support for that code.OpenMCL uses different
+      filenames to name the lisp kernel fileson different platforms;
+      see FIXTHIS.</para>
+
+      <para>A <indexterm><primary>heap image</primary></indexterm> is
+      a file that can be quickly mapped into aprocess's address space.
+      Conceptually, it's not too different from anexecutable file or
+      shared library in the OS's native format (ELF orMach-O/dyld
+      format); for historical reasons, OpenMCL's own heap images are in
+      their own (fairly simple) format.The term <literal>full heap
+      image</literal> refers to a heap image file thatcontains all of
+      the code and data that comprise OpenMCL.OpenMCL uses different
+      filenames to name the standard full heapimage files on different
+      platforms; see FIXTHIS .</para>
+
+      <para>A <indexterm><primary>bootstrapping
+      image</primary></indexterm> is a minimal heap image used in
+      the process of building OpenMCL itself.  The bootstrapping image
+      containsjust enough code to load the rest of OpenMCL from fasl
+      files.  It mayhelp to think of the bootstrapping image as the
+      egg and the full heapimage as the chicken...OpenMCL uses
+      different filenames to name the standardbootstrapping image
+      files on different platforms; see FIXTHIS .</para>
+
+      <para>Each supported platform (and possibly a few
+      as-yet-unsupported ones) has a uniquely named subdirectory of
+      <literal>ccl/lisp-kernel/</literal>; each such
+      <indexterm><primary>kernel build directory</primary></indexterm>
+      contains a Makefile and may contain some auxiliary files (linker
+      scripts, etc.) that are used to build the lispkernel on a
+      particular platform.The platform-specific name of the kernel
+      build directory is described in FIXTHIS.</para>
+
+      <sect2 id="Platform-specific-filename-conventions">
+       <title>Platform-specific filename conventions</title>
+       <table>
+	 <title>Platform-specific filename conventions</title>
+	 <tgroup cols="6">
+	   <thead>
+            <row>
+                <entry>Platform</entry>
+                <entry>kernel</entry>
+                <entry>full-image</entry>
+                <entry>boot-image</entry>
+                <entry>fasl extension</entry>
+                <entry>kernel-build directory</entry>
+	    </row>
+	   </thead>
+	   <tbody>
+	     <row>
+	       <entry>DarwinPPC32</entry>
+                <entry>dppccl</entry>
+                <entry>dppccl.image</entry>
+                <entry>ppc-boot.image</entry>
+                <entry>.dfsl</entry>
+                <entry>darwinppc</entry>
+	     </row>
+	     <row>
+	       <entry>LinuxPPC32</entry>
+                <entry>ppccl</entry>
+		<entry>PPCCL</entry>
+                <entry>ppc-boot</entry>
+                <entry>.pfsl</entry>
+                <entry>linuxppc</entry>
+	     </row>
+	     <row>
+	       <entry>DarwinPPC64</entry>
+	       <entry>dppccl64</entry>
+	       <entry>dppccl64.image</entry>
+	       <entry>ppc-boot64.image</entry>
+	       <entry>.d64fsl</entry>
+	       <entry>darwinppc64</entry>
+             </row>
+              <row>
+		<entry>LinuxPPC64</entry>
+                <entry>ppccl64</entry>
+                <entry>PPCCL64</entry>
+                <entry>ppc-boot64</entry>
+                <entry>.p64fsl</entry>
+                <entry>linuxppc64</entry>
+              </row>
+	      <row>
+		<entry>LinuxX8664</entry>
+                <entry>lx86cl64</entry>
+                <entry>LX86CL64</entry>
+                <entry>x86-boot64</entry>
+                <entry>.lx64fsl</entry>
+                <entry>linuxx8664</entry>
+              </row>
+	      <row>
+		<entry>DarwinX8664</entry>
+		<entry>dx86cl64</entry>
+                <entry>dx86cl64.image</entry>
+                <entry>x86-boot64.image</entry>
+                <entry>.dx64fsl</entry>
+                <entry>darwinx8664</entry>
+              </row>
+	      <row>
+		<entry>FreeBSDX8664</entry>
+                <entry>fx86cl64</entry>
+                <entry>FX86CL64</entry>
+                <entry>fx86-boot64</entry>
+                <entry>.fx64fsl</entry>
+                <entry>freebsdx8664</entry>
+              </row>
+	   </tbody>
+	 </tgroup>
+       </table>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Setting-Up-to-Build">
+      <title>Setting Up to Build</title>
+      <para>There are currently three versions of OpenMCL that you
+      might want to use (and therefore might want to build from
+      source):</para>
+      <itemizedlist>
+        <listitem><para>Version 1.0 - the more stable version</para></listitem>
+        <listitem><para>Version 1.1 - the more recent version, which
+        runs on more platforms (including x86-64 platforms) and
+        supports Unicode</para></listitem>
+	<listitem><para>Version 1.2 - supports (at least) all of the
+	features and platforms as 1.1, but is distributed and updated
+	differently</para></listitem>
+      </itemizedlist>
+      <para>All versions are available for download from the OpenMCL
+      website in the form of archives that contain everything you need
+      to work with OpenMCL, including the complete sources, a full
+      heap image, and the foreign-function interface database.</para>
+      <para>Version 1.0 archives are named
+      <literal>openmcl-</literal><replaceable>platform</replaceable><literal>-all-1.0.tar.gz</literal>,
+      where <replaceable>platform</replaceable> is either
+      <literal>darwinppc</literal>, <literal>darwinppc64</literal>, or
+      <literal>linuxppc</literal>.  Because version 1.0 is no longer
+      undergoing active development, you won't ever need to update
+      these sources.</para>
+      <para>Version 1.1 archives are named
+      <literal>openmcl-</literal><replaceable>platform</replaceable><literal>-snapshot-</literal><replaceable>yymmdd</replaceable><literal>.tar.gz</literal>,
+      where <replaceable>platform</replaceable> is either
+      <literal>darwinppc</literal>, <literal>darwinx8664</literal>,
+      <literal>linuxppc</literal>, <literal>linuxx8664</literal>, or
+      <literal>freebsdx8664</literal>, and where
+      <replaceable>yymmdd</replaceable> is the year, month, and day
+      the snapshot was released.</para>
+      <para>Because version 1.1 is undergoing active development,
+      there may be times when you want to get sources that are more
+      recent than the most recent snapshot and use them to build
+      yourself a new bleeding-edge OpenMCL.  In that case, you should
+      download and install the latest snapshot, and then update your
+      sources via CVS.  At that point you can rebuild and you'll have
+      the latest and greatest OpenMCL.  The snapshot has CVS
+      working-copy information in it, so all you need to do to update
+      is</para>
+      <programlisting>
+$ cd ccl
+$ cvs login             # password is "cvs"
+                        # this step only needs to be done once,
+                        # that'll store the trivially encrypted
+                        # password in ~/.cvspas
+$ cvs update
+      </programlisting>
+      <para>Unless you tell it to, cvs won't delete ("prune") empty
+      directories or create new ones when the repository changes.
+      It's generally a good habit to use</para>
+      <programlisting>
+$ cvs update -d -P      # create dirs as needed, prune empty ones
+      </programlisting>
+      <para>Version 1.2 archives follow naming conventions that are
+      similar to those used by 1.0 (though more platforms are supported.)
+      However, rather than containing CVS working-copy information, the
+      1.2 (and, presumably, later) archives contain metainformation used
+      by the Subversion (svn) source-code control system.</para>
+      <para>Subversion client programs are pre-installed on OSX 10.5 and
+      later and are typically either pre-installed or readily available
+      on Linux and FreeBSD platforms.  The <ulink url="http://subversion.tigris.org">Subversion web page</ulink> contains links to subversion client programs
+      for many platforms; users of OSX versions 10.4 and earlier can also
+      install Subversion clients via Fink or MacPorts.</para>
+      
+    </sect1>
+
+    <sect1 id="Building-Everything">
+      <title>Building Everything</title>
+      <para>Given that you now have everything you need, do the
+      following in a running OpenMCL to bring your Lisp system
+      completely up to date.</para>
+      <programlisting>
+? (ccl:rebuild-ccl :full t)
+      </programlisting>
+      <para>That call to the function <literal>rebuild-ccl</literal>
+      will perform the following steps:</para>
+      <itemizedlist>
+        <listitem>
+	  <para>Deletes all fasl files and other object files in the
+	  <literal>ccl</literal>directory tree</para>
+	</listitem>
+        <listitem>
+	  <para>Runs an external process which does a
+	  <literal>make</literal> in the currentplatform's kernel
+	  build directory to create a new kernel</para>
+	</listitem>
+        <listitem>
+	  <para>Does <literal>(compile-ccl t)</literal> in the running
+	  lisp, to produce aset of fasl files from the &ldquo;higher
+	  level&rdquo; lisp sources.</para>
+	</listitem>
+        <listitem>
+	  <para>Does <literal>(xload-level-0 :force)</literal> in the
+	  running lisp, to compile thelisp sources in the
+	  &ldquo;ccl:level-0;&rdquo; directory into fasl files and
+	  then createa bootstrapping image from those fasl
+	  files.</para>
+	</listitem>
+        <listitem>
+	  <para>Runs another external process, which causes the newly
+	  compiled lispkernel to load the new bootstrapping image.
+	  The bootsrtrapping image then loadsthe &ldquo;higher
+	  level&rdquo; fasl files and a new copy of the platform's
+	  full heap imageis then saved.</para>
+	</listitem>
+      </itemizedlist>
+      <para>If all goes well, it'll all happen without user
+      intervention and with some simple progress messages.  If
+      anything goes wrong during execution of either of the external
+      processes, the process output is displayed as part of a lisp
+      error message.</para>
+      <para><literal>rebuild-ccl</literal> is essentially just a short
+      cut for running all the individual steps involved in rebuilding
+      the system.  You can also execute these steps individually, as
+      described below.</para>
+    </sect1>
+
+    <sect1 id="Building-the-kernel">
+      <title>Building the kernel</title>
+      <para>The Lisp kernel is the executable which you run to use
+      Lisp.  It doesn't actually contain the entire Lisp
+      implementation; rather, it loads a heap image which contains the
+      specifics - the "library", as it might be called if this was a C
+      program.  The kernel also provides runtime support to the heap
+      image, such as garbage collection, memory allocation, exception
+      handling, and the OS interface.</para>
+
+      <para>The Lisp kernel file has different names on different
+      platforms. See FIXTHIS . On all platforms the lisp kernel sources reside
+      in <literal>ccl/lisp-kernel</literal>.</para>
+
+      <para>This section gives directions on how to rebuild the Lisp
+      kernel from its source code.  Most OpenMCL users will rarely
+      have to do this.  You probably will only need to do it if you are
+      attempting to port OpenMCL to a new architecture or extend or enhance
+      its kernel in some way.  As mentioned above, this step happens
+      automatically when you do
+      <programlisting>
+? (rebuild-ccl :full t)
+      </programlisting>
+      </para>
+
+
+      <sect2 id="Kernel-build-prerequisites">
+        <title>Kernel build prerequisites</title>
+	<para>The OpenMCL kernel can be bult with the following widely
+	available tools:</para>
+        <itemizedlist>
+          <listitem><para>cc or gcc- the GNU C compiler</para></listitem>
+          <listitem><para>ld - the GNU linker</para></listitem>
+          <listitem><para>m4 or gm4- the GNU m4 macro processor</para></listitem>
+          <listitem><para>as - the GNU assembler (version 2.10.1 or later)</para></listitem>
+	  <listitem><para>make - either GNU make or, on FreeBSD, the default BSD make program</para></listitem>
+	</itemizedlist>
+	<para> In general, the more recent the versions of those
+	tools, the better; some versions of gcc 3.x on Linux have
+	difficulty compiling some of the kernel source code correctly
+	(so gcc 4.0 should be used, if possible.)  On OSX, the
+	versions of the tools distributed with XCode should work fine;
+	on Linux, the versions of the tools installed with the OS (or
+	available through its package management system) should work
+	fine if they're "recent enough".  On FreeBSD, the installed
+	version of the <literal>m4</literal> program doesn't support
+	some features that the kernel build process depends on; the
+	GNU version of the m4 macroprocessor (called
+	<literal>gm4</literal> on FreeBSD) should be installed
+
+	</para>
+      </sect2>
+      <sect2 id="kernel-build-command">
+	<title>Using "make" to build the lisp kernel</title>
+        <para>With those tools in place, do:
+        <programlisting>
+shell> cd ccl/lisp-kernel/<replaceable>PLATFORM</replaceable>
+shell> make
+	</programlisting>
+	</para>
+        <para>That'll assemble several assembly language source files,
+        compile several C source files, and link
+        ../../<replaceable>the kernel</replaceable>.
+	</para>
+      </sect2>
+    </sect1>
+    <sect1 id="Building-the-heap-image">
+      <title>Building the heap image</title>
+      <para>The initial heap image is loaded by the Lisp kernel, and
+      provides most all of the language implementation The heap image
+      captures the entire state of a running Lisp (except for external
+      resources, such as open files and TCP sockets).  After it is
+      loaded, the contents of the new Lisp process's memory are
+      exactly the same as those of the old Lisp process when the image
+      was created.</para>
+      <para>The heap image is how we get around the fact that we can't
+      run Lisp code until we have a working Lisp implementation, and
+      we can't make our Lisp implementation work until we can run Lisp
+      code.  Since the heap image already contains a fully-working
+      implementation, all we need to do is load it into memory and
+      start using it.</para>
+      <para>If you're building a new version of OpenMCL, you need to
+      build a new heap image.</para>
+      <para>(You might also wish to build a heap image if you have a
+      large program which it is very complicated or time-consuming to
+      load, so that you will be able to load it once, save an image,
+      and thenceforth never have to load it again. At any time, a heap
+      image capturing the entire memory state of a running Lisp can be
+      created by calling the function
+      <literal>ccl:save-application</literal>.)</para>
+
+      <sect2 id="Development-cycle">
+	<title>Development cycle</title>
+        <para>Creating a new OpenMCL full heap image consists of the
+        following steps:</para>
+        <orderedlist>
+          <listitem><para>Using your existing OpenMCL, create a
+          bootstrapping image</para></listitem>
+          <listitem><para>Using your existing OpenMCL, recompile your
+          updated OpenMCL sources</para></listitem>
+          <listitem><para>Invoke OpenMCL with the bootstrapping image
+          you just created (rather than with the existing full heap
+          image).</para></listitem>
+	</orderedlist>
+	<para>When you invoke OpenMCL with the bootstrapping image, it
+	will start up, load al of the OpenMCL fasl files, and save out
+	a new full heap image.  Voila.  You've created a new heap
+	image.</para>
+        <para>A few points worth noting:</para>
+	<itemizedlist>
+          <listitem>
+	    <para>There's a circular dependency between the full heap
+	    image and thebootstrapping image, in that each is used to
+	    build the other.</para>
+	  </listitem>
+          <listitem>
+	    <para>There are some minor implementation
+	    differences, but the environment in effect after the
+	    bootstrapping image has loaded its fasl files is essentially
+	    equivalent to the environment provided by the full heap
+	    image; the latter loads a lot faster and is easier to
+	    distribute, of course.</para>
+	  </listitem>
+          <listitem>
+	    <para>If the full heap image doesn't work (because
+	    of an OScompatibilty problem or other bug), it's very likely
+	    that thebootstrapping image will suffer the same
+	    problems.</para>
+	  </listitem>
+	</itemizedlist>
+        <para>Given a bootstrapping image and a set of up-to-date fasl
+        files, the development cycle usually involves editing lisp
+        sources (or updating those sources via cvs update),
+        recompiling modified files, and using the bootstrapping image
+        to produce a new heap image.</para>
+      </sect2>
+
+      <sect2 id="Generating-a-bootstrapping-image">
+        <title>Generating a bootstrapping image</title>
+        <para>The bootstrapping image isn't provided in OpenMCL
+        distributions. It can be built from the source code provided
+        in distributions (using a lisp image and kernel provided in
+        those distributions) using the procedure described
+        below.</para>
+
+        <para>The bootstrapping image is built by invoking a special
+        utility inside a running OpenMCL heap image to load files
+        contained in the <literal>ccl/level-0</literal> directory. The
+        bootstrapping image loads several dozen fasl files.  After
+        it's done so, it saves a heap image via
+        <literal>save-application</literal>. This process is called
+        "cross-dumping".</para>
+
+        <para>Given a source distribution, a lisp kernel, and aheap
+        image, one can produce a bootstapping image by first invoking
+        OpenMCL from the shell:</para>
+        <programlisting>
+shell&gt; openmcl
+Welcome to OpenMCL .... !
+?
+	</programlisting>
+	<para>then calling <literal>ccl:xload-level-0</literal> at the
+	lisp prompt</para>
+	<programlisting>
+? (ccl:xload-level-0)
+	</programlisting>
+        <para>This will compile the lisp sources in the ccl/level-0
+        directory if they're newer than the corresponding fasl files
+        and will then load the resulting fasl files into a simulated
+        lisp heap contained inside data structures inside the running
+        lisp. That simulated heap image is then written to
+        disk.</para>
+        <para><literal>xload-level-0</literal> should be called
+        whenever your existing boot image is out-of-date with respect
+        to the source files in <literal>ccl:level-0;</literal>
+        :</para>
+        <programlisting>
+? (ccl:xload-level-0 :force)
+</programlisting>
+        <para>will force recompilation of the level-0 sources.</para>
+      </sect2>
+
+      <sect2 id="Generating-fasl-files">
+        <title>Generating fasl files</title>
+	<para> Calling:</para>
+        <programlisting>
+? (ccl:compile-ccl)
+	</programlisting>
+	<para>at the lisp prompt will compile any fasl files that are
+	out-of-date with respect to the corresponding lisp sources;
+	<literal>(ccl:compile-ccl t)</literal> will force
+	recompilation. <literal>ccl:compile-ccl</literal> will reload
+	newly-compiled versions of some files;
+	<literal>ccl:xcompile-ccl</literal> is analogous, but skips
+	this reloading step.</para>
+        <para>Unless there are bootstrapping considerations involved,
+        it usually doesn't matter whether these files reloaded after
+        they're recompiled.</para>
+        <para>Calling <literal>compile-ccl</literal> or
+        <literal>xcompile-ccl</literal> in an environment where fasl
+        files don't yet exist may produce warnings to that effect
+        whenever files are <literal>require</literal>d during
+        compilation; those warnings can be safely ignored. Depending
+        on the maturity of the OpenMCL release, calling
+        <literal>compile-ccl</literal> or
+        <literal>xcompile-ccl</literal> may also produce several
+        warnings about undefined functions, etc. They should be
+        cleaned up at some point.</para>
+      </sect2>
+
+      <sect2 id="Building-a-full-image-from-a-bootstrapping-image">
+	<title>Building a full image from a bootstrapping image</title>
+	<para>To build a full image from a bootstrapping image, just
+	invoke the kernel with the bootstrapping image is an
+	argument</para>
+        <programlisting>
+$ cd ccl                        # wherever your ccl directory is
+$ ./<replaceable><kernel&gt; <boot_image&gt;</replaceable>
+	</programlisting>
+        <para>Where <replaceable><kernel&gt;</replaceable> and
+        <replaceable><boot_image&gt;</replaceable> are the names of
+        the kernel and boot image appropriate to the platform you are
+        running on.  See FIXTHIS</para>
+        <para>That should load a few dozen fasl files (printing a
+        message as each file is loaded.) If all of these files
+        successfully load, the lisp will print a prompt. You should be
+        able to do essentially everything in that environment that you
+        can in the environment provided by a "real" heap image. If
+        you're confident that things loaded OK, you can save that
+        image.</para>
+        <programlisting>
+? (ccl:save-application "<replaceable>image_name</replaceable>") ; Overwiting the existing heap image
+	</programlisting>
+	<para>Where <replaceable>image_name</replaceable> is the name
+        of the full heap image for your platform. See FIXTHIS.</para>
+        <para>If things go wrong in the early stages of the loading
+        sequence, errors are often difficult to debug; until a fair
+        amount of code (CLOS, the CL condition system, streams, the
+        reader, the read-eval-print loop) is loaded, it's generally
+        not possible for the lisp to report an error.  Errors that
+        occur during these early stages ("the cold load") sometimes
+        cause the lisp kernel debugger (see ) to be invoked; it's
+        primitive, but can sometimes help one to get oriented.</para>
+      </sect2>
+    </sect1>
+  </chapter>
+
+  <chapter id="Questions-and-Answers">
+
+    <title>Questions and Answers</title>
+
+    <sect1 id="How-can-I-do-nonblocking--aka--unbuffered--and--raw---IO-">
+      <title>How can I do nonblocking (aka "unbuffered" and "raw") IO?</title>
+      <para>There's some code for manipulating TTY modes in
+      "ccl:library;pty.lisp".</para>
+      <programlisting>
+? (require "PTY")
+
+? (ccl::disable-tty-local-modes 0 #$ICANON)
+T
+      </programlisting>
+      <para>will turn off "input canonicalization" on file descriptor
+      0, which is at least part of what you need to do here.  This
+      disables the #$ICANON mode, which tells the OS not to do any
+      line-buffering or line-editing.  Of course, this only has any
+      effect in situations where the OS ever does that, which means
+      when stdin is a TTY or PTY.</para>
+      <para>If the #$ICANON mode is disabled, you can do things like:</para>
+      <programlisting>
+? (progn (read-char) (read-char))
+a
+#\a
+      </programlisting>
+      <para>(where the first READ-CHAR consumes the newline, which
+      isn't really necessary to make the reader happy anymore.)  So,
+      you can do:</para>
+      <programlisting>
+? (read-char)
+#\Space
+</programlisting>
+      <para>(where there's a space after the close-paren) without
+      having to type a newline.</para>
+    </sect1>
+
+    <sect1 id="I-m-using-the-graphics-demos--Why-doesn-t-the-menubar-change-">
+      <title>I'm using the graphics demos. Why doesn't the menubar
+      change?</title>
+      <para>When you interact with text-only OpenMCL, you're either
+      in Terminal or in Emacs, running OpenMCL as a subprocess.  When
+      you load Cocoa or the graphical environment, the subprocess does
+      some tricky things that turn it into a full-fledged Application,
+      as far as the OS is concerned.</para>
+      <para>So, it gets its own icon in the dock, and its own menubar,
+      and so on.  It can be confusing, because standard input and
+      output will still be connected to Terminal or Emacs, so you can
+      still type commands to OpenMCL from there.  To see the menubar
+      you loaded, or the windows you opened, just click on the OpenMCL
+      icon in the dock.</para>
+    </sect1>
+
+    <sect1 id="I-m-using-Slime-and-Cocoa--Why-doesn-t--standard-output--seem-to-work-">
+      <title>I'm using Slime and Cocoa. Why doesn't *standard-output*
+      seem to work? </title>
+      <para>This comes up if you're using the Slime interface
+      to run OpenMCL under Emacs, and you are doing Cocoa programming
+      which involves printing to *standard-output*.  It seems as
+      though the output goes nowhere; no error is reported, but it
+      doesn't appear in the *slime-repl* buffer.</para>
+
+      <para>For the most part, this is only relevant when you are
+      trying to insert debug code into your event handlers.  The SLIME
+      listener runs in a thread where the standard stream varaiables
+      (like <literal>*STANDARD-OUTPUT* and</literal> and
+      <literal>*TERMINAL-IO*</literal> are bound to the stream used to
+      communicate with Emacs; the Cocoa event thread has its own
+      bindings of these standard stream variables, and output to these
+      streams goes to the *inferior-lisp* buffer instead.  Look for it
+      there.</para>
+    </sect1>
+  </chapter>
+
+  <chapter id="Programming-with-Threads">
+    <title>Programming with Threads</title>
+
+    <sect1 id="Threads-overview">
+      <title>Threads Overview</title>
+
+      <para>OpenMCL provides facilities which enable multiple threads
+      of execution (<emphasis>threads</emphasis>, sometimes called
+      <emphasis>lightweight processes</emphasis> or just
+      <emphasis>processes</emphasis>, though the latter term shouldn't
+      be confused with the OS's notion of a process) within a lisp
+      session. This document describes those facilities and issues
+      related to multitheaded programming in OpenMCL.</para>
+
+      <para>Wherever possible, I'll try to use the term "thread" to
+      denote a lisp thread, even though many of the functions in the
+      API have the word "process" in their name. A
+      <emphasis>lisp-process</emphasis> is a lisp object (of type
+      CCL:PROCESS) which is used to control and communicate with an
+      underlying <emphasis>native thread</emphasis>. Sometimes, the
+      distinction between these two (quite different) objects can be
+      blurred; other times, it's important to maintain.</para>
+      <para>Lisp threads share the same address space, but maintain
+      their own execution context (stacks and registers) and their own
+      dynamic binding context.</para>
+      
+      <para>Traditionally, OpenMCL's threads have been
+      <emphasis>cooperatively scheduled</emphasis>: through a
+      combination of compiler and runtime suppport, the currently
+      executing lisp thread arranged to be interrrupted at certain
+      discrete points in its execution (typically on entry to a
+      function and at the beginning of any looping construct). This
+      interrupt occurred several dozen times per second; in response,
+      a handler function might observe that the current thread had
+      used up its time slice and another function (<emphasis>the lisp
+      scheduler</emphasis>) would be called to find some other thread
+      that was in a runnable state, suspend execution of the current
+      thread, and resume execution of the newly executed thread.  The
+      process of switching contexts between the outgoing and incoming
+      threads happened in some mixture of Lisp and assembly language
+      code; as far as the OS was concerned, there was one native
+      thread running in the Lisp image and its stack pointer and other
+      registers just happened to change from time to time.</para>
+      <para>Under OpenMCL's cooperative scheduling model, it was
+      possible (via the use of the CCL:WITHOUT-INTERRUPTS construct)
+      to defer handling of the periodic interrupt that invoked the
+      lisp scheduler; it was not uncommon to use WITHOUT-INTERRUPTS to
+      gain safe, exclusive access to global data structures. In some
+      code (including much of OpenMCL itself) this idiom was very
+      common: it was (justifiably) believed to be an efficient way of
+      inhibiting the execution of other threads for a short period of
+      time.</para>
+
+      <para>The timer interrupt that drove the cooperative scheduler
+      was only able to (pseudo-)preempt lisp code: if any thread
+      called a blocking OS I/O function, no other thread could be
+      scheduled until that thread resumed execution of lisp code. Lisp
+      library functions were generally attuned to this constraint, and
+      did a complicated mixture of polling and "timed blocking" in an
+      attempt to work around it. Needless to say, this code is
+      complicated and less efficient than it might be; it meant that
+      the lisp was a little busier than it should have been when it
+      was "doing nothing" (waiting for I/O to be possible.)</para>
+
+      <para>For a variety of reasons - better utilization of CPU
+      resources on single and multiprocessor systems and better
+      integration with the OS in general - threads in OpenMCL 0.14 and
+      later are <emphasis>preemptively scheduled. </emphasis>In this
+      model, lisp threads are native threads and all scheduling
+      decisions involving them are made by the OS kernel. (Those
+      decisions might involve scheduling multiple lisp threads
+      simultaneously on multiple processors on SMP systems.) This
+      change has a number of subtle effects:</para>
+
+      <itemizedlist>
+        <listitem>
+	  <para>it is possible for two (or more) lisp threads to be
+	  executingsimultaneously, possibly trying to access and/or
+	  modify the same datastructures. Such access really should
+	  have been coordinated throughthe use of synchronization
+	  objects regardless of the scheduling modelin effect;
+	  preemptively scheduled threads increase the chance ofthings
+	  going wrong at the wrong time and do not offer
+	  lightweightalternatives to the use of those synchronization
+	  objects.</para>
+	</listitem>
+        <listitem>
+	  <para>even on a single-processor system, a context switch
+	  can happenon any instruction boundary. Since (in general)
+	  other threads mightallocate memory, this means that a GC can
+	  effectively take place atany instruction boundary. That's
+	  mostly an issue for the compilerand runtime system to be
+	  aware of, but it means that certain practices(such as trying
+	  to pass the address of a lisp object to foreign code)that
+	  were always discouraged are now discouraged
+	  ... vehemently.</para>
+	</listitem>
+        <listitem>
+	  <para>there is no simple and efficient way to "inhibit the
+	  scheduler"or otherwise gain exclusive access to the entire
+	  CPU.</para>
+	</listitem>
+        <listitem>
+	  <para>There are a variety of simple and efficient ways
+	  tosynchronize access to particular data
+	  structures.</para>
+	</listitem>
+      </itemizedlist>
+      <para>As a broad generalization: code that's been aggressively
+      tuned to the constraints of the cooperative scheduler may need
+      to be redesigned to work well with the preemptive scheduler (and
+      code written to run under OpenMCL's interface to the native
+      scheduler may be less portable to other CL implementations, many
+      of which offer a cooperative scheduler and an API similar to
+      OpenMCL (< 0.14) 's.) At the same time, there's a large
+      overlap in functionality in the two scheduling models, and it'll
+      hopefully be possible to write interesting and useful MP code
+      that's largely independent of the underlying scheduling
+      details.</para>
+      <para>The keyword :OPENMCL-NATIVE-THREADS is on *FEATURES* in
+      0.14 and later and can be used for conditionalization where
+      required.</para>
+    </sect1>
+
+    <sect1 id="Intentionally--Missing-Functionality">
+      <title>(Intentionally) Missing Functionality</title>
+      <para>Much of the functionality described above is similar to
+      that provided by OpenMCL's cooperative scheduler, some other
+      parts of which make no sense in a native threads
+      implementation.</para>
+      <itemizedlist>
+        <listitem>
+	  <para>PROCESS-RUN-REASONS and PROCESS-ARREST-REASONS were
+	  SETFable process attributes; each was just a list of
+	  arbitrary tokens. A thread was eligible for scheduling
+	  (roughly equivalent to being "enabled") if its arrest-reasons
+	  list was empty and its run-reasons list was not. I don't
+	  think that it's appropriate to encourage a programming style
+	  in which otherwise runnable threads are enabled and disabled
+	  on a regular basis (it's preferable for threads to wait for
+	  some sort of synchronization event to occur if they can't
+	  occupy their time productively.)</para>
+	</listitem>
+        <listitem>
+	  <para>There were a number of primitives for maintaining
+	  process queues;that's now the OS's job.</para>
+	</listitem>
+        <listitem>
+	  <para>Cooperative threads were based on coroutining
+	  primitivesassociated with objects of type
+	  STACK-GROUP. STACK-GROUPs no longerexist.</para>
+	</listitem>
+      </itemizedlist>
+    </sect1>
+
+    <sect1 id="Implementation-Decisions-and-Open-Questions">
+      <title>Implementation Decisions and Open Questions</title>
+      <para> As of August 2003:</para>
+      <itemizedlist>
+        <listitem>
+	  <para>It's not clear that exposing
+	  PROCESS-SUSPEND/PROCESS-RESUME is a good idea: it's not clear
+	  that they offer ways to win, and it's clear that they offer
+	  ways to lose.</para>
+	</listitem>
+        <listitem>
+	  <para>It has traditionally been possible to reset and enable
+	  a process that's "exhausted" . (As used here, the
+	  term"exhausted" means that the process's initial function
+	  hasrun and returned and the underlying native thread has
+	  beendeallocated.) One of the principle uses of PROCESS-RESET
+	  is to "recycle" threads; enabling an exhausted process
+	  involves creating a new native thread (and stacks and
+	  synchronization objects and ...),and this is the sort of
+	  overhead that such a recycling scheme is seeking to avoid. It
+	  might be worth trying to tighten things up and declare that
+	  it's an error to apply PROCESS-ENABLE to an exhausted thread
+	  (and to make PROCESS-ENABLE detect this error.)</para>
+	</listitem>
+        <listitem>
+	  <para>When native threads that aren't created by OpenMCL
+	  first call into lisp, a "foreign process" is created, and
+	  that process is given its own set of initial bindings and set
+	  up to look mostly like a process that had been created by
+	  MAKE-PROCESS. The life cycle of a foreign process is
+	  certainly different from that of a lisp-created one: it
+	  doesn't make sense to reset/preset/enable a foreign process,
+	  and attempts to perform these operations should be
+	  detectedand treated as errors.</para>
+	</listitem>
+      </itemizedlist>
+    </sect1>
+
+    <sect1 id="Porting-Code-from-the-Old-Thread-Model">
+      <title>Porting Code from the Old Thread Model</title>
+      <para>Older versions of OpenMCL used what are often called
+      "user-mode threads", a less versatile threading model which does
+      not require specific support from the operating system.  This
+      section discusses how to port code which was written for that
+      mode.</para>
+      <para>It's hard to give step-by-step instructions; there are certainly
+      a few things that one should look at carefully:</para>
+      <itemizedlist>
+        <listitem>
+	  <para>It's wise to be suspicious of most uses
+	  of WITHOUT-INTERRUPTS; there may be exceptions, but
+	  WITHOUT-INTERRUPTS is often used as shorthand for
+	  WITH-APPROPRIATE-LOCKING. Determining what type of locking
+	  is appropriate and writing the code to implement it is
+	  likely to be straightforward and simple most of the
+	  time.</para>
+	</listitem>
+        <listitem>
+	  <para>I've only seen one case where a process's "run reasons"
+	  were used to communicate information as well as tocontrol
+	  execution; I don't think that this is a common idiom, but may
+	  be mistaken about that.
+	  </para>
+	</listitem>
+        <listitem>
+	  <para>It's certainly possible that programs written
+	  for cooperatively scheduled lisps that have run reliably for
+	  a long timehave done so by accident: resource-contention
+	  issues tend to be timing-sensitive, and decoupling thread
+	  scheduling from lisp program execution affects timing. I know
+	  that there is or was code in both OpenMCL and commercial MCL
+	  that was written under the explicit assumption that certain
+	  sequences of open-coded operations were uninterruptable; it's
+	  certainly possible that the same assumptions have been made
+	  (explicitly or otherwise) by application developers.</para>
+	</listitem>
+      </itemizedlist>
+    </sect1>
+
+    <sect1 id="Background-Terminal-Input">
+      <title>Background Terminal Input</title>
+
+      <sect2 id="backgrount-ti-overview">
+        <title>Overview</title>
+	<para>
+	  Unless and until OpenMCL provides alternatives (via window
+	  streams, telnet streams, or some other mechanism) all lisp
+	  processes share a common *TERMINAL-IO* stream (and therefore
+	  share *DEBUG-IO*, *QUERY-IO*, and other standard and
+	  internal interactive streams.)</para>
+	  <para>It's anticipated that most lisp processes other than
+	  the "Initial" process run mostly in the background. If a
+	  background process writes to the output side of
+	  *TERMINAL-IO*, that may be a little messy and a little
+	  confusing to the user, but it shouldn't really be
+	  catastrophic. All I/O to OpenMCL's buffered streams goes
+	  thru a locking mechanism that prevents the worst kinds of
+	  resource-contention problems.</para>
+	  <para>Although the problems associated with terminal output
+	  from multiple processes may be mostly cosmetic, the question
+	  of which process receives input from the terminal is likely
+	  to be a great deal more important. The stream locking
+	  mechanisms can make a confusing situation even worse:
+	  competing processes may "steal" terminal input from each
+	  other unless locks are held longer than they otherwise need
+	  to be, and locks can be held longer than they need to be (as
+	  when a process is merely waiting for input to become
+	  available on an underlying file descriptor).</para>
+	  <para>Even if background processes rarely need to
+	  intentionally read input from the terminal, they may still
+	  need to do so in response to errors or other unanticipated
+	  situations. There are tradeoffs involved in any solution to
+	  this problem. The protocol described below allows background
+	  processes which follow it to reliably prompt for and receive
+	  terminal input. Background processes which attempt to
+	  receive terminal input without following this protocol will
+	  likely hang indefinitely while attempting to do so. That's
+	  certainly a harsh tradeoff, but since attempts to read
+	  terminal input without following this protocol only worked
+	  some of the time anyway, it doesn't seem to be an
+	  unreasonable one.</para>
+	  <para>In the solution described here (and introduced in
+	  OpenMCL 0.9), the internal stream used to provide terminal
+	  input is always locked by some process (the "owning"
+	  process.) The initial process (the process that typically
+	  runs the read-eval-print loop) owns that stream when it's
+	  first created. By using the macro WITH-TERMINAL-INPUT,
+	  background processes can temporarily obtain ownership of the
+	  terminal and relinquish ownership to the previous owner when
+	  they're done with it.</para>
+	  <para>In OpenMCL, BREAK, ERROR, CERROR, Y-OR-N-P,
+	  YES-OR-NO-P, and CCL:GET-STRING- FROM-USER are all defined
+	  in terms of WITH-TERMINAL-INPUT, as are the :TTY
+	  user-interfaces to STEP and INSPECT.</para>
+      </sect2>
+
+      <sect2 id="background-terminal-example">
+        <title>An example</title>
+        <programlisting>
+? Welcome to OpenMCL Version (Beta: linux) 0.9!
+?
+
+? (process-run-function "sleeper" #'(lambda () (sleep 5) (break "broken")))
+#<PROCESS sleeper(1) [Enabled] #x3063B33E&gt;
+
+?
+;;
+;; Process sleeper(1) needs access to terminal input.
+;;
+</programlisting>
+        <para>This example was run under ILISP; ILISP often gets confused if one
+	tries to enter input and "point" doesn't follow a prompt.
+	Entering a "simple" expression at this point gets it back in
+	synch; that's otherwise not relevant to this example.</para>
+	<programlisting>
+()
+NIL
+? (:y 1)
+;;
+;; process sleeper(1) now controls terminal input
+;;
+> Break in process sleeper(1): broken
+> While executing: #<Anonymous Function #x3063B276&gt;
+> Type :GO to continue, :POP to abort.
+> If continued: Return from BREAK.
+Type :? for other options.
+1 > :b
+(30C38E30) : 0 "Anonymous Function #x3063B276" 52
+(30C38E40) : 1 "Anonymous Function #x304984A6" 376
+(30C38E90) : 2 "RUN-PROCESS-INITIAL-FORM" 340
+(30C38EE0) : 3 "%RUN-STACK-GROUP-FUNCTION" 768
+1 &gt; :pop
+;;
+;; control of terminal input restored to process Initial(0)
+;;
+?
+</programlisting>
+      </sect2>
+
+      <sect2 id="A-more-elaborate-example-">
+        <title>A more elaborate example.</title>
+	<para>If a background process ("A") needs access to the terminal
+	input stream and that stream is owned by another background process
+	("B"), process "A" announces that fact, then waits until
+	the initial process regains control.</para>
+	<programlisting>
+? Welcome to OpenMCL Version (Beta: linux) 0.9!
+?
+
+? (process-run-function "sleep-60" #'(lambda () (sleep 60) (break "Huh?")))
+#<PROCESS sleep-60(1) [Enabled] #x3063BF26&gt;
+
+? (process-run-function "sleep-5" #'(lambda () (sleep 5) (break "quicker")))
+#<PROCESS sleep-5(2) [Enabled] #x3063D0A6&gt;
+
+? ;;
+;; Process sleep-5(2) needs access to terminal input.
+;;
+()
+NIL
+
+? (:y 2)
+;;
+;; process sleep-5(2) now controls terminal input
+;;
+> Break in process sleep-5(2): quicker
+> While executing: #x3063CFDE>
+> Type :GO to continue, :POP to abort.
+> If continued: Return from BREAK.
+Type :? for other options.
+1 > ;; Process sleep-60(1) will need terminal access when
+;; the initial process regains control of it.
+;;
+()
+NIL
+1 > :pop
+;;
+;; Process sleep-60(1) needs access to terminal input.
+;;
+;;
+;; control of terminal input restored to process Initial(0)
+;;
+
+? (:y 1)
+;;
+;; process sleep-60(1) now controls terminal input
+;;
+> Break in process sleep-60(1): Huh?
+> While executing: #x3063BE5E>
+> Type :GO to continue, :POP to abort.
+> If continued: Return from BREAK.
+Type :? for other options.
+1 > :pop
+;;
+;; control of terminal input restored to process Initial(0)
+;;
+
+?
+</programlisting>
+      </sect2>
+
+      <sect2 id="Summary">
+	<title>Summary</title>
+	<para>This scheme is certainly not bulletproof: imaginative
+	use of PROCESS-INTERRUPT and similar functions might be able
+	to defeat it and deadlock the lisp, and any scenario where
+	several background processes are clamoring for access to the
+	shared terminal input stream at the same time is likely to be
+	confusing and chaotic. (An alternate scheme, where the input
+	focus was magically granted to whatever thread the user was
+	thinking about, was considered and rejected due to technical
+	limitations.)</para>
+	<para>The longer-term fix would probably involve using network or
+	window-system streams to give each process unique instances of
+	*TERMINAL-IO*.</para>
+        <para>Existing code that attempts to read from *TERMINAL-IO*
+        from a background process will need to be changed to use
+        WITH-TERMINAL-INPUT.  Since that code was probably not working
+        reliably in previous versions of OpenMCL, this requirement
+        doesn't seem to be too onerous.</para>
+        <para>Note that WITH-TERMINAL-INPUT both requests ownership of
+        the terminal input stream and promises to restore that
+        ownership to the initial process when it's done with it. An ad
+        hoc use of READ or READ-CHAR doesn't make this promise; this
+        is the rationale for the restriction on the :Y command.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="The-Threads-which-OpenMCL-Uses-for-Its-Own-Purposes">
+      <para>The Threads which OpenMCL Uses for Its Own Purposes
+In the "tty world", OpenMCL starts out with 2 lisp-level threads:</para>
+      <programlisting>
+? :proc
+1 : -> listener     [Active]
+0 :    Initial      [Active]
+</programlisting>
+      <para>If you look at a running OpenMCL with a debugging tool,
+      such as GDB, or Apple's Thread Viewer.app, you'll see an
+      additional kernel-level thread on Darwin; this is used by the
+      Mach exception-handling mechanism.</para>
+      <para>The initial thread, conveniently named "initial", is the
+      one that was created by the operating system when it launched
+      OpenMCL.  It maps the heap image into memory, does some
+      Lisp-level initialization, and, when the Cocoa IDE isn't being
+      used, creates the thread "listener", which runs the top-level
+      loop that reads input, evaluates it, and prints the
+      result.</para>
+      <para>After the listener thread is created, the initial thread
+      does "housekeeping": it sits in a loop, sleeping most of the
+      time and waking up occasionally to do "periodic tasks".  These
+      tasks include forcing output on specified interactive streams,
+      checking for and handling control-C interrupts, etc.  Currently,
+      those tasks also include polling for the exit status of external
+      processes and handling some kinds of I/O to and from those
+      processes.</para>
+      <para>In this environment, the initial thread does these
+      "housekeeping" activities as necessary, until
+      <literal>ccl:quit</literal> is called;
+      <literal>quit</literal>ting interrupts the initial thread, which
+      then ends all other threads in as orderly a fashion as possible
+      and calls the C function <literal>#_exit</literal>.</para>
+      <para>The short-term plan is to handle each external-process in
+      a dedicated thread; the worst-case behavior of the current
+      scheme can involve busy-waiting and excessive CPU utilization
+      while waiting for an external process to terminate in some
+      cases.</para>
+      <para>The Cocoa features use more threads.  Adding a Cocoa
+      listener creates two threads:</para>
+      <programlisting>
+? :proc
+3 : -> Listener     [Active]
+2 :    housekeeping  [Active]
+1 :    listener     [Active]
+0 :    Initial      [Active]
+      </programlisting>
+      <para>The Cocoa event loop has to run in the initial thread;
+      when the event loop starts up, it creates a new thread to do the
+      "housekeeping" tasks which the initial thread would do in the
+      terminal-only mode.  The initial thread then becomes the one to
+      receive all Cocoa events from the window server; it's the only
+      thread which can.</para>
+      <para>It also creates one "Listener" (capital-L) thread for each
+      listener window, with a lifetime that lasts as long as the
+      thread does.  So, if you open a second listener, you'll see five
+      threads all together:</para>
+      <programlisting>
+? :proc
+4 : -> Listener-2   [Active]
+3 :    Listener     [Active]
+2 :    housekeeping  [Active]
+1 :    listener     [Active]
+0 :    Initial      [Active]
+</programlisting>
+      <para>Unix signals, such as SIGINT (control-C), invoke a handler
+      installed by the Lisp kernel.  Although the OS doesn't make any
+      specific guarantee about which thread will receive the signal,
+      in practice, it seems to be the initial thread.  The handler
+      just sets a flag and returns; the housekeeping thread (which may
+      be the initial thread, if Cocoa's not being used) will check for
+      the flag and take whatever action is appropriate to the
+      signal.</para>
+      <para>In the case of SIGINT, the action is to enter a break
+      loop, by calling on the thread being interrupted.  When there's
+      more than one Lisp listener active, it's not always clear what
+      thread that should be, since it really depends on the user's
+      intentions, which there's no way to divine programmatically.  To
+      make its best guess, the handler first checks whether the value
+      of <literal>ccl:*interactive-abort-process*</literal> is a
+      thread, and, if so, uses it.  If that fails, it chooses the
+      thread which currently "owns" the default terminal input stream;
+      see .</para>
+      <para>In the bleeding-edge version of the Cocoa support which is
+      based on Hemlock, an Emacs-like editor, each editor window has a
+      dedicated thread associated with it.  When a keypress event
+      comes in which affects that specific window the initial thread
+      sends it to the window's dedicated thread.  The dedicated thread
+      is responsible for trying to interpret keypresses as Hemlock
+      commands, applying those commands to the active buffer; it
+      repeats this in a loop, until the window closes.  The initial
+      thread handles all other events, such as mouse clicks and
+      drags.</para>
+      <para>This thread-per-window scheme makes many things simpler,
+      including the process of entering a "recursive command loop" in
+      commands like "Incremental Search Forward", etc.  (It might be
+      possible to handle all Hemlock commands in the Cocoa event
+      thread, but these "recursive command loops" would have to
+      maintain a lot of context/state information; threads are a
+      straightforward way of maintaining that information.)</para>
+      <para>Currently (August 2004), when a dedicated thread needs to
+      alter the contents of the buffer or the selection, it does so by
+      invoking methods in the initial thread, for synchronization
+      purposes, but this is probably overkill and will likely be
+      replaced by a more efficient scheme in the future.</para>
+      <para>The per-window thread could probably take more
+      responsibility for drawing and handling the screen than it
+      currently does; -something- needs to be done to buffer screen
+      updates a bit better in some cases: you don't need to see
+      everything that happens during something like indentation; you
+      do need to see the results...</para>
+      <para>When Hemlock is being used, listener windows are editor
+      windows, so in addition to each "Listener" thread, you should
+      also see a thread which handles Hemlock command
+      processing.</para>
+      <para>The Cocoa runtime may make additional threads in certain
+      special situations; these threads usually don't run lisp code,
+      and rarely if ever run much of it.</para>
+    </sect1>
+
+    <sect1 id="Threads-Dictionary">
+      <title>Threads Dictionary</title>
+
+      <refentry id="f_all-processes">
+	<indexterm zone="f_all-processes">
+	  <primary>all-processes</primary>
+	</indexterm>
+
+	<refnamediv>
+	  <refname>ALL-PROCESSES</refname>
+	  <refpurpose>Obtain a fresh list of all known Lisp
+	  threads.</refpurpose>
+	  <refclass>Function</refclass>
+	</refnamediv>
+
+	<refsynopsisdiv>
+	  <synopsis>
+	    <function>all-processes</function> => result
+	  </synopsis>
+	</refsynopsisdiv>
+
+	<refsect1>
+	  <title>Values</title>
+	  
+	  <variablelist>
+	    <varlistentry>
+	      <term>result</term>
+	      <listitem>
+		<para>a list of all lisp processes (threads)
+		known to OpenMCL.</para>
+	      </listitem>
+	    </varlistentry>
+	  </variablelist>
+	</refsect1>
+	<refsect1>
+	  <title>Description</title>
+
+	  <para>Returns a list of all lisp processes (threads) known
+	  to OpenMCL as of the precise instant it&#39;s
+	  called. It&#39;s safe to traverse this list and to modify
+	  the cons cells that comprise that list (it&#39;s freshly
+	  consed.) Since other threads can create and kill threads at
+	  any time, there&#39;s generally no way to get an
+	  &#34;accurate&#34; list of all threads, and (generally) no
+	  sense in which such a list can be accurate.</para>
+	</refsect1>
+
+	<refsect1>
+	  <title>See Also</title>
+	 
+	  <simplelist type="inline">
+	    <member><xref linkend="v_current-process"/></member>
+	  </simplelist>
+	</refsect1>
+      </refentry>
+
+
+       <refentry id="f_make-process">
+	<indexterm zone="f_make-process">
+	  <primary>make-process</primary>
+	</indexterm>
+
+	<refnamediv>
+	  <refname>MAKE-PROCESS</refname>
+	  <refpurpose>Creates and returns a new process.</refpurpose>
+	  <refclass>Function</refclass>
+	</refnamediv>
+
+	<refsynopsisdiv>
+	  <synopsis>
+	    <function>make-process</function>
+	    name &key;
+	    persistent priority class stack-size vstack-size
+	    tstack-size initial-bindings use-standard-initial-bindings
+	    => process
+	  </synopsis>
+	</refsynopsisdiv>
+
+	<refsect1>
+	  <title>Arguments and Values</title>
+	  
+	  <variablelist>
+	    <varlistentry>
+	      <term>name</term>
+	      
+	      <listitem>
+		<para>a string, used to identify the process.</para>
+	      </listitem>
+	    </varlistentry>
+	    
+	    <varlistentry>
+	      <term>persistent</term>
+	      
+	      <listitem>
+		<para>if true, requests that information about the process
+		be retained by SAVE-APPLICATION so that an equivalent
+		process can be restarted when a saved image is run.  The
+		default is nil.</para>
+	      </listitem>
+	    </varlistentry>
+	    
+	    <varlistentry>
+	      <term>priority</term>
+	      
+	      <listitem>
+		<para>ignored.  It
+		shouldn't be ignored of course, but there are
+		complications on some platforms.  The default is 0.</para>
+	      </listitem>
+	    </varlistentry>
+	    
+	    <varlistentry>
+	      <term>class</term>
+	      
+	      <listitem>
+		<para>the class of process object to create;
+		should be a subclass of CCL:PROCESS.  The default is
+		CCL:PROCESS.</para>
+	      </listitem>
+	    </varlistentry>
+	    
+	    <varlistentry>
+	      <term>stack-size</term>
+	      
+	      <listitem>
+		<para>the size, in bytes, of the newly-created process's
+		control stack; used for foreign function calls and to save
+		function return address context.  The default is
+		CCL:*DEFAULT-CONTROL-STACK-SIZE*.</para>
+	      </listitem>
+	    </varlistentry>
+	    
+	    <varlistentry>
+	      <term>vstack-size</term>
+	      
+	      <listitem>
+		<para>the size, in bytes, of the newly-created process's
+		value stack; used for lisp function arguments, local
+		variables, and other stack-allocated lisp objects.
+		The default is CCL:*DEFAULT-VALUE-STACK-SIZE*.</para>
+	      </listitem>
+	    </varlistentry>
+	    
+	    <varlistentry>
+	      <term>tstack-size</term>
+	      
+	      <listitem>
+		<para>the size, in bytes, of the newly-created process's
+		temp stack; used for the allocation of dynamic-extent
+		objects.  The default is CCL:*DEFAULT-TEMP-STACK-SIZE*.</para>
+	      </listitem>
+	    </varlistentry>
+	    
+	    <varlistentry>
+	      <term>use-standard-initial-bindings</term>
+	      
+	      <listitem>
+		<para>when true, the global "standard initial
+		bindings" are put into effect in the new thread before. See
+		DEF-STANDARD-INITIAL-BINDING.  "standard" initial bindings
+		are put into effect before any bindings specified by
+		:initial-bindings are.  The default is t.</para>
+	      </listitem>
+	    </varlistentry>
+	    
+	    <varlistentry>
+	      <term>initial-bindings</term>
+	      
+	      <listitem>
+		<para>an alist of (<varname>symbol</varname> .
+		<varname>valueform</varname>) pairs, which can be
+		used to initialize special variable bindings in the new
+		thread. Each <varname>valueform</varname> is used to
+		compute the value of a new binding of
+		<varname>symbol</varname> in the execution environment of
+		the newly-created thread.  The default is nil.</para>
+	      </listitem>
+	    </varlistentry>
+	    
+	    <varlistentry>
+	      <term>process</term>
+	      
+	      <listitem>
+		<para>the newly-created process.</para>
+	      </listitem>
+	    </varlistentry>
+	  </variablelist>
+	</refsect1>
+
+	<refsect1>
+	  <title>Description</title>
+
+	  <para>Creates and returns a new lisp process (thread) with the
+	  specified attributes. <varname>process</varname> will not begin
+	  execution immediately; it will need to be
+	  <emphasis>preset</emphasis> (given
+	  an initial function to run, as by
+	  <xref linkend="f_process-preset"/>) and
+	  <emphasis>enabled</emphasis>
+	  (allowed to execute, as by <xref linkend="f_process-enable"/>)
+	  before it&#39;s able to actually do anything.</para>
+
+	  <para>If <varname>valueform</varname> is a function, it is
+	  called, with no arguments, in the execution environment of the
+	  newly-created thread; the primary value it returns is used for
+	  the binding of the corresponding <varname>symbol</varname>.</para>
+
+	  <para>Otherwise, <varname>valueform</varname> is evaluated in the
+	  execution
+	  environment of the newly-created thread, and the resulting value
+	  is used.</para>
+	</refsect1>
+
+	<refsect1>
+	  <title>See Also</title>
+	 
+	  <simplelist type="inline">
+	    <member><xref linkend="f_process-preset"/></member>
+	    <member><xref linkend="f_process-enable"/></member>
+	    <member><xref linkend="f_process-run-function"/></member>
+	  </simplelist>
+	</refsect1>
+      </refentry>
+
+      <sect2 id="PROCESS-SUSPEND">
+        <para>PROCESS-SUSPEND</para>
+        <informalfigure>process-suspend</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-SUSPEND &mdash; Suspends a specified process.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-suspend process
+	  => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>process
+            <variablelist>a lisp process (thread).</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>T if <literal>process</literal> had been runnableand is now suspended; NIL otherwise.  That is, T if<literal>process</literal>'stransitioned from 0 to 1.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Suspends <literal>process</literal>, preventing it from
+running, and stopping it if it was already running. This is a fairly
+expensive operation, because it involves a few
+calls to the OS.  It also risks creating deadlock if used
+improperly, for instance, if the process being suspended owns a
+lock or other resource which another process will wait for.</para>
+        <para>Each
+call to <literal>process-suspend</literal> must be reversed by
+a matching call to 
+before <literal>process</literal> is able to run.  What
+<literal>process-suspend</literal> actually does is increment
+the  of
+<literal>process</literal>.</para>
+        <para>A process cannot suspend itself (although that was possible in
+some older OpenMCL releases and this documentation claimed that
+it still was.)</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">,</para>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para><literal>process-suspend</literal> was previously called
+<literal>process-disable</literal>.</para>
+        <para>now names a function for which there is no
+obvious inverse, so <literal>process-disable</literal>
+is no longer
+defined.</para>
+      </sect2>
+
+      <sect2 id="PROCESS-RESUME">
+        <para>PROCESS-RESUME</para>
+        <informalfigure>process-resume</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-RESUME &mdash; Resumes a specified process which had previously
+been suspended by process-suspend.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-resume process
+	  => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>process
+            <variablelist>a lisp process (thread).</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>T if <literal>process</literal> had been suspendedand is now runnable; NIL otherwise.  That is, T if<literal>process</literal>'stransitioned from  to 0.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Undoes the effect of a previous call to
+; if
+all such calls are undone, makes the process runnable. Has no
+effect if the process is not suspended.  What
+<literal>process-resume</literal> actually does is decrement
+the  of
+<literal>process</literal>, to a minimum of 0.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">,</para>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para>This was previously called PROCESS-ENABLE;
+ now does something slightly
+different.</para>
+      </sect2>
+
+      <sect2 id="PROCESS-SUSPEND-COUNT">
+        <para>PROCESS-SUSPEND-COUNT</para>
+        <informalfigure>process-suspend-count</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-SUSPEND-COUNT &mdash; Returns the number of currently-pending suspensions
+applicable to a given process.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    process-suspend-count
+	    process => result
+
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>process
+            <variablelist>a lisp process (thread).</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>The number of "outstanding" calls on<literal>process</literal>, or NIL if<literal>process</literal> has expired.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>An "outstanding"  call
+is one which has not yet been reversed by a call to
+.  A process expires when
+its initial function returns, although it may later be
+reset.</para>
+        <para>A process is <emphasis>runnable</emphasis> when it has a
+<literal>process-suspend-count</literal> of 0, has been
+preset as by , and has been
+enabled as by .  Newly-created
+processes have a <literal>process-suspend-count</literal> of
+0.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">,</para>
+      </sect2>
+
+      <sect2 id="PROCESS-PRESET">
+        <para>PROCESS-PRESET</para>
+        <informalfigure>process-preset</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-PRESET &mdash; Sets the initial function and arguments of a specified
+process.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-preset
+	  process function &amp;rest args
+	  => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>process
+            <variablelist>a lisp process (thread).</variablelist>
+          </indexterm><indexterm>function
+            <variablelist>a function, designated by itself or by a symbolwhich names it.</variablelist>
+          </indexterm><indexterm>args
+            <variablelist>a list of values, appropriate as arguments to<literal>function</literal>.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>undefined.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Typically used to initialize a newly-created or newly-reset
+process, setting things up so that when <literal>process</literal>
+becomes enabled, it will begin execution by
+applying <literal>function</literal> to <literal>args</literal>.
+<literal>process-preset</literal> does not enable
+<literal>process</literal>,
+although a process must be <literal>process-preset</literal>
+before it can be enabled.  Processes are normally enabled by
+.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, ,</para>
+      </sect2>
+
+      <sect2 id="PROCESS-ENABLE">
+        <para>PROCESS-ENABLE</para>
+        <informalfigure>process-enable</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-ENABLE &mdash; Begins executing the initial function of a specified
+process.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-enable
+	  process &amp;optional timeout
+
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>process
+            <variablelist>a lisp process (thread).</variablelist>
+          </indexterm><indexterm>timeout
+            <variablelist>a time interval in seconds.  May be anynon-negative real number the <literal>floor</literal> ofwhich fits in 32 bits.  The default is 1.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>undefined.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Tries to begin the execution of <literal>process</literal>.
+An error is signaled if <literal>process</literal> has never
+been .  Otherwise,
+<literal>process</literal> invokes its initial function.</para>
+        <para><literal>process-enable</literal> attempts to
+synchronize with <literal>process</literal>, which is presumed
+to be reset or in the act of resetting itself.  If this attempt
+is not successful within the time interval specified by
+<literal>timeout</literal>, a continuable error is signaled,
+which offers the opportunity to continue waiting.</para>
+        <para>A process cannot meaningfully attempt to enable itself.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, ,</para>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para>It would be nice to have more discussion of what it means
+to synchronize with the process.</para>
+      </sect2>
+
+      <sect2 id="PROCESS-RUN-FUNCTION">
+        <para>PROCESS-RUN-FUNCTION</para>
+        <informalfigure>process-run-function</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-RUN-FUNCTION &mdash; Creates a process, presets it, and enables it.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-run-function
+	  process-specifier function &amp;rest args => process
+</programlisting>
+        <term><indexterm>process-specifier
+            <variablelist><literal>name</literal> |(<literal>&amp;key</literal> <literal>name</literal><literal>persistent</literal><literal>priority</literal><literal>class</literal><literal>stack-size</literal><literal>vstack-size</literal><literal>tstack-size</literal>)</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>name
+            <variablelist>a string, used to identify the process.Passed to <literal>make-process</literal>.</variablelist>
+          </indexterm><indexterm>function
+            <variablelist>a function, designated by itself or by a symbolwhich names it.  Passed to<literal>preset-process</literal>.</variablelist>
+          </indexterm><indexterm>persistent
+            <variablelist>a boolean, passed to <literal>make-process</literal>.</variablelist>
+          </indexterm><indexterm>priority
+            <variablelist>ignored.</variablelist>
+          </indexterm><indexterm>class
+            <variablelist>a subclass of CCL:PROCESS.  Passed to<literal>make-process</literal>.</variablelist>
+          </indexterm><indexterm>stack-size
+            <variablelist>a size, in bytes.  Passed to<literal>make-process</literal>.</variablelist>
+          </indexterm><indexterm>vstack-size
+            <variablelist>a size, in bytes.  Passed to<literal>make-process</literal>.</variablelist>
+          </indexterm><indexterm>tstack-size
+            <variablelist>a size, in bytes.  Passed to<literal>make-process</literal>.</variablelist>
+          </indexterm><indexterm>process
+            <variablelist>the newly-created process.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Creates a lisp process (thread) via
+,
+presets it via , and
+enables it via .  This means
+that <literal>process</literal> will immediately begin to
+execute.
+<literal>process-run-function</literal> is
+the simplest way to create and run a process.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, ,</para>
+      </sect2>
+
+      <sect2 id="PROCESS-INTERRUPT">
+        <para>PROCESS-INTERRUPT</para>
+        <informalfigure>process-interrupt</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-INTERRUPT &mdash; Arranges for the target process to invoke a
+specified function at some point in the near future, and then
+return to what it was doing.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-interrupt
+	  process function &amp;rest args => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>process
+            <variablelist>a lisp process (thread).</variablelist>
+          </indexterm><indexterm>function
+            <variablelist>a function.</variablelist>
+          </indexterm><indexterm>args
+            <variablelist>a list of values, appropriate as arguments to<literal>function</literal>.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>the result of applying <literal>function</literal>to <literal>args</literal> if <literal>proceess</literal>is the <literal>current-process</literal>, otherwiseNIL.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Arranges for <literal>process</literal> to apply <literal>function</literal> to <literal>args</literal> at
+some point in the near future (interrupting whatever <literal>process</literal>
+was doing.) If <literal>function</literal> returns normally, <literal>process</literal>
+resumes execution at the point at which it was interrupted.</para>
+        <para><literal>process</literal> must be in an enabled state in order to respond to a
+<literal>process-interrupt</literal> request.  It's perfectly legal for a process
+to call <literal>process-interrupt</literal> on itself.</para>
+        <para><literal>process-interrupt</literal> uses asynchronous POSIX signals to interrupt
+threads. If the thread being interrupted is executing lisp code, it
+can respond to the interrupt almost immediately (as soon as it has
+finished pseudo-atomic operations like consing and stack-frame
+initialization.)</para>
+        <para>If the interrupted thread is blocking in a system call, that system
+call is aborted by the signal and the interrupt is handled on return.</para>
+        <para>Beginning with the version 1.1 prereleases of OpenMCL interrupts are
+disabled in <literal>unwind-protect</literal> cleanup forms and in any stack-unwinding
+code between the point of the <literal>throw</literal> and the corresponding CATCH
+target.  If interrupts were enabled at the time that the CATCH was
+established, then any interrupt that had been deferred during
+unwinding will be taken just before the transfer to <literal>catch</literal> target
+(after all of that unwinding is complete.)</para>
+        <para>If an <literal>unwind-protect</literal> cleanup form actually does something that
+needs to be interruptible, it's necessary to use
+<literal>with-interrupts-enabled</literal>.  (This actually happens somewhere in
+the code which waits for external processes to complete; some of that
+waiting occurred within an unwind-protect cleanup, and interrupts
+needed to be explicitly enabled in that case in order to make the wait
+interruptible.)</para>
+        <para>Note that <literal>(without-interrupts (throw ...))</literal> wouldn't have the intended
+effect, since the <literal>throw</literal> would cause execution to exit the extent of
+the <literal>without-interrupts</literal>.</para>
+        <para>In versions prior to 1.1, interrupts could occur at arbitrary times
+during the process of unwinding the stack and executing intervening
+cleanup forms.</para>
+        <para>It is still difficult to reliably interrupt arbitrary foreign code
+(that may be stateful or otherwise non-reentrant); the interrupt
+request is handled when such foreign code returns to or enters lisp.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues"></para>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para>It would probably be better for <literal>result</literal> to always be NIL, since
+the present behaviour is inconsistent.</para>
+        <para><literal>Process-interrupt</literal> works by sending signals between threads, via
+the C function <literal>#_pthread_signal</literal>.  It could be argued that it
+should be done in one of several possible other ways under Darwin, to
+make it practical to asynchronously interrupt things which make heavy
+use of the Mach nanokernel.</para>
+      </sect2>
+
+      <sect2 id="iCURRENT-PROCESS-">
+        <para>*CURRENT-PROCESS*</para>
+        <informalfigure>*current-process*</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>*CURRENT-PROCESS* &mdash; Bound in each process, to that process
+itself.</para>
+        <para>Variable</para>
+        <bridgehead renderas="sect3">Value Type</bridgehead>
+        <para>A lisp process (thread).</para>
+        <bridgehead renderas="sect3">Initial Value</bridgehead>
+        <para>Bound separately in each process, to that process itself.</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Used when lisp code needs to find out what process it is
+executing in.  Shouldn't be set by user code.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues"></para>
+      </sect2>
+
+      <sect2 id="PROCESS-RESET">
+        <para>PROCESS-RESET</para>
+        <informalfigure>process-reset</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-RESET &mdash; Causes a specified process to cleanly exit from
+any ongoing computation.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-reset
+	  process &amp;optional kill-option => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>process
+            <variablelist>a lisp process (thread).</variablelist>
+          </indexterm><indexterm>kill-option
+            <variablelist>a generalized boolean.  The default is T.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>undefined.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Causes <literal>process</literal> to cleanly exit
+from any ongoing computation.  If <literal>kill-option</literal>
+is true, <literal>process</literal> then exits.  Otherwise, it
+enters a state where it can be
+. This
+is implemented by signaling a condition of type PROCESS-RESET;
+user-defined condition handlers should generally refrain from
+attempting to handle conditions of this type.</para>
+        <para>A process can meaningfully reset itself.</para>
+        <para>There is in general no way to know precisely when
+<literal>process</literal>
+has completed the act of resetting or killing itself; a process
+which has either entered the limbo of the reset state or exited
+has few ways of communicating either fact.</para>
+        <para>can reliably determine when a process has entered
+the "limbo of the reset state", but can't predict how long the
+clean exit from ongoing computation might take: that depends on
+the behavior of <literal>unwind-protect</literal> cleanup
+forms, and of the OS scheduler.</para>
+        <para>Resetting a process other than
+ involves the
+use of .</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">,</para>
+      </sect2>
+
+      <sect2 id="PROCESS-KILL">
+        <para>PROCESS-KILL</para>
+        <informalfigure>process-kill</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-KILL &mdash; Causes a specified process to cleanly exit from any
+ongoing computation, and then exit.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-kill process
+	  => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>process
+            <variablelist>a lisp process (thread).</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>undefined.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Entirely equivalent to calling
+(PROCESS-RESET PROCESS T).  Causes <literal>process</literal>
+to cleanly exit from any ongoing computation, and then exit.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">,</para>
+      </sect2>
+
+      <sect2 id="PROCESS-ABORT">
+        <para>PROCESS-ABORT</para>
+        <informalfigure>process-abort</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-ABORT &mdash; Causes a specified process to process an abort
+condition, as if it had invoked
+<literal>abort</literal>.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-abort process
+	  &amp;optional condition
+	  => NIL
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>process
+            <variablelist>a lisp process (thread).</variablelist>
+          </indexterm><indexterm>condition
+            <variablelist>a lisp condition.  The default is NIL.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Entirely equivalent to calling
+( <literal>process</literal>
+(<literal>lambda</literal> ()
+(<literal>abort</literal> <literal>condition</literal>))).
+Causes <literal>process</literal> to transfer control to the
+applicable handler or restart for <literal>abort</literal>.</para>
+        <para>If <literal>condition</literal> is non-NIL,
+<literal>process-abort</literal> does not consider any
+handlers which are explicitly bound to conditions other than
+<literal>condition</literal>.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">,</para>
+      </sect2>
+
+      <sect2 id="iTICKS-PER-SECOND-">
+        <para>*TICKS-PER-SECOND*</para>
+        <informalfigure>*ticks-per-second*</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>*TICKS-PER-SECOND* &mdash; Bound to the clock resolution of the OS
+scheduler.</para>
+        <para>Variable</para>
+        <bridgehead renderas="sect3">Value Type</bridgehead>
+        <para>A positive integer.</para>
+        <bridgehead renderas="sect3">Initial Value</bridgehead>
+        <para>The clock resoluton of the OS scheduler.  Currently,
+both LinuxPPC and DarwinPPC yeild an initial value of 100.</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>This value is ordinarily of marginal interest at best,
+but, for backward compatibility, some functions accept timeout
+values expressed in "ticks".  This value gives the number of
+ticks per second.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues"></para>
+      </sect2>
+
+      <sect2 id="PROCESS-WHOSTATE">
+        <para>PROCESS-WHOSTATE</para>
+        <informalfigure>process-whostate</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-WHOSTATE &mdash; Returns a string which describes the status of
+a specified process.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-whostate process
+	  => whostate
+</programlisting>
+        <term><indexterm>process
+            <variablelist>a lisp process (thread).</variablelist>
+          </indexterm><indexterm>whostate
+            <variablelist>a string which describes the "state" of<literal>process</literal>.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>This information is primarily for the benefit of
+debugging tools.  <literal>whostate</literal> is a terse report
+on what <literal>process</literal> is doing, or not doing,
+and why.</para>
+        <para>If the process is currently waiting in a call to
+ or
+, its
+<literal>process-whostate</literal> will be the value
+which was passed to that function as <literal>whostate</literal>.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, ,</para>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para>This should arguably be SETFable, but doesn't seem to
+ever have been.</para>
+      </sect2>
+
+      <sect2 id="PROCESS-ALLOW-SCHEDULE">
+        <para>PROCESS-ALLOW-SCHEDULE</para>
+        <informalfigure>process-allow-schedule</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-ALLOW-SCHEDULE &mdash; Used for cooperative multitasking; probably never
+necessary.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-allow-schedule
+</programlisting>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Advises the OS scheduler that the current thread has nothing
+useful to do and that it should try to find some other thread to
+schedule in its place. There's almost always a better
+alternative, such as waiting for some specific event to
+occur.  For example, you could use a lock or semaphore.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , ,</para>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para>This is a holdover from the days of cooperative
+multitasking.  All modern general-purpose operating systems use
+preemptive multitasking.</para>
+      </sect2>
+
+      <sect2 id="PROCESS-WAIT">
+        <para>PROCESS-WAIT</para>
+        <informalfigure>process-wait</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-WAIT &mdash; Causes the current lisp process (thread) to wait for
+a given
+predicate to return true.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-wait
+	  whostate function &amp;rest args => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>whostate
+            <variablelist>a string, which will be the value ofwhile the process is waiting.</variablelist>
+          </indexterm><indexterm>function
+            <variablelist>a function, designated by itself or by a symbolwhich names it.</variablelist>
+          </indexterm><indexterm>args
+            <variablelist>a list of values, appropriate as arguments to<literal>function</literal>.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>NIL.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Causes the current lisp process (thread) to repeatedly
+apply <literal>function</literal> to
+<literal>args</literal> until the call returns a true result, then
+returns NIL. After
+each failed call, yields the CPU as if by
+.</para>
+        <para>As with , it's almost
+always more efficient to wait for some
+specific event to occur; this isn't exactly busy-waiting, but
+the OS scheduler can do a better job of scheduling if it's given
+the relevant information.  For example, you could use a lock
+or semaphore.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , , ,</para>
+      </sect2>
+
+      <sect2 id="PROCESS-WAIT-WITH-TIMEOUT">
+        <para>PROCESS-WAIT-WITH-TIMEOUT</para>
+        <informalfigure>process-wait-with-timeout</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-WAIT-WITH-TIMEOUT &mdash; Causes the current thread to wait for a given
+predicate to return true, or for a timeout to expire.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-wait-with-timeout
+	  whostate ticks function args => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>whostate
+            <variablelist>a string, which will be the value ofwhile the process is waiting.</variablelist>
+          </indexterm><indexterm>ticks
+            <variablelist>either a positive integer expressing a durationin "ticks" (see ),or NIL.</variablelist>
+          </indexterm><indexterm>function
+            <variablelist>a function, designated by itself or by a symbolwhich names it.</variablelist>
+          </indexterm><indexterm>args
+            <variablelist>a list of values, appropriate as arguments to<literal>function</literal>.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>T if <literal>process-wait-with-timeout</literal>returned because its <literal>function</literal> returnedtrue, or NIL if it returned because the duration<literal>ticks</literal> has been exceeded.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>If <literal>ticks</literal> is NIL, behaves exactly like
+, except for returning T.
+Otherwise, <literal>function</literal> will be tested repeatedly,
+in the same
+kind of test/yield loop as in >
+until either <literal>function</literal> returns true,
+or the duration <literal>ticks</literal> has been exceeded.</para>
+        <para>Having already read the descriptions of
+ and
+, the
+astute reader has no doubt anticipated the observation that
+better alternatives should be used whenever possible.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , , , ,</para>
+      </sect2>
+
+      <sect2 id="WITHOUT-INTERRUPTS">
+        <para>WITHOUT-INTERRUPTS</para>
+        <informalfigure>without-interrupts</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>WITHOUT-INTERRUPTS &mdash; Evaluates its body in an environment in which
+process-interrupt requests are deferred.</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+without-interrupts
+	  &amp;body body => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>body
+            <variablelist>an implicit progn.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>the primary value returned by<literal>body</literal>.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Executes <literal>body</literal> in an environment in which
+ requests are deferred. As noted in the
+description of , this has nothing to do with
+the scheduling of other threads; it may be necessary to inhibit
+ handling when (for instance) modifying some
+data structure (for which the current thread holds an appropriate
+lock) in some manner that's not reentrant.</para>
+        <para>Beginning with the version 1.1 prereleases of OpenMCL interrupts are
+disabled in <literal>unwind-protect</literal> cleanup forms and in any
+stack-unwinding code between the point of the <literal>throw</literal> and the
+corresponding CATCH target. If an <literal>unwind-protect</literal> cleanup form
+actually does something that needs to be interruptible, it's necessary
+to use <literal>with-interrupts-enabled</literal>. In versions prior to 1.1,
+interrupts can occur at arbitrary times during the process of
+unwinding the stack and executing intervening cleanup forms.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues"></para>
+      </sect2>
+
+      <sect2 id="MAKE-LOCK">
+        <para>MAKE-LOCK</para>
+        <informalfigure>make-lock</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>MAKE-LOCK &mdash; Creates and returns a lock object, which can
+be used for synchronization between threads.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+make-lock &amp;optional
+	  name => lock
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>name
+            <variablelist>any lisp object; saved as part of<literal>lock</literal>.  Typically a string or symbolwhich may appear in the sof threads which are waiting for <literal>lock</literal>.</variablelist>
+          </indexterm><indexterm>lock
+            <variablelist>a newly-allocated object of type CCL:LOCK.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Creates and returns a lock object, which can
+be used to synchronize access to some shared resource.
+<literal>lock</literal> is
+initially in a "free" state; a lock can also be
+"owned" by a
+thread.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , , , ,</para>
+      </sect2>
+
+      <sect2 id="WITH-LOCK-GRABBED">
+        <para>WITH-LOCK-GRABBED</para>
+        <informalfigure>with-lock-grabbed</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>WITH-LOCK-GRABBED &mdash; Waits until a given lock can be obtained, then
+evaluates its body with the lock held.</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+with-lock-grabbed
+	  (lock) &amp;body body
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>lock
+            <variablelist>an object of type CCL:LOCK.</variablelist>
+          </indexterm><indexterm>body
+            <variablelist>an implicit progn.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>the primary value returned by<literal>body</literal>.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Waits until <literal>lock</literal> is either free or
+owned by the calling
+thread, then excutes <literal>body</literal> with the
+lock owned by the calling thread. If <literal>lock</literal>
+was free when <literal>with-lock-grabbed</literal> was called,
+it is restored to a free state after <literal>body</literal>
+is executed.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , , , ,</para>
+      </sect2>
+
+      <sect2 id="GRAB-LOCK">
+        <para>GRAB-LOCK</para>
+        <informalfigure>grab-lock</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>GRAB-LOCK &mdash; Waits until a given lock can be obtained, then
+obtains it.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+grab-lock lock
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>lock
+            <variablelist>an object of type CCL:LOCK.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Blocks until <literal>lock</literal> is owned by the
+calling thread.</para>
+        <para>The macro 
+<emphasis>could</emphasis> be defined in
+terms of <literal>grab-lock</literal> and
+, but it is actually
+implemented at a slightly lower level.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , , , ,</para>
+      </sect2>
+
+      <sect2 id="RELEASE-LOCK">
+        <para>RELEASE-LOCK</para>
+        <informalfigure>release-lock</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>RELEASE-LOCK &mdash; Relinquishes ownership of a given lock.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+release-lock lock
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>lock
+            <variablelist>an object of type CCL:LOCK.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Signals an error of type CCL:LOCK-NOT-OWNER if
+<literal>lock</literal>
+is not already owned by the calling thread; otherwise, undoes the
+effect of one previous
+.  If this means that
+<literal>release-lock</literal> has now been called on
+<literal>lock</literal> the same number of times as
+ has, <literal>lock</literal>
+becomes free.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , , , ,</para>
+      </sect2>
+
+      <sect2 id="TRY-LOCK">
+        <para>TRY-LOCK</para>
+        <informalfigure>try-lock</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>TRY-LOCK &mdash; Obtains the given lock, but only if it is not
+necessary to wait for it.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+try-lock lock => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>lock
+            <variablelist>an object of type CCL:LOCK.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>T if <literal>lock</literal> has been obtained,or NIL if it has not.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Tests whether <literal>lock</literal>
+can be obtained without blocking - that is, either
+<literal>lock</literal> is already free, or it is already owned
+by .  If it can,
+causes it to
+be owned by the calling lisp process (thread) and returns T.
+Otherwise, the lock
+is already owned by another thread and cannot be obtained without
+blocking; NIL is returned in this case.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , , , ,</para>
+      </sect2>
+
+      <sect2 id="MAKE-READ-WRITE-LOCK">
+        <para>MAKE-READ-WRITE-LOCK</para>
+        <informalfigure>make-read-write-lock</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>MAKE-READ-WRITE-LOCK &mdash; Creates and returns a read-write lock, which can
+be used for synchronization between threads.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+make-read-write-lock
+	  => read-write-lock
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>read-write-lock
+            <variablelist>a newly-allocated object of typeCCL:READ-WRITE-LOCK.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Creates and returns an object of type CCL::READ-WRITE-LOCK.
+A read-write lock may, at any given time, belong to any number
+of lisp processes (threads) which act as "readers"; or, it may
+belong to at most one process which acts as a "writer".  A
+read-write lock may never be held by a reader at the same time as
+a writer.  Intially, <literal>read-write-lock</literal> has
+no readers and no writers.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , ,</para>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para>There probably should be some way to
+atomically "promote" a reader, making it a writer without
+releasing the lock, which could otherwise cause delay.</para>
+      </sect2>
+
+      <sect2 id="WITH-READ-LOCK">
+        <para>WITH-READ-LOCK</para>
+        <informalfigure>with-read-lock</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>WITH-READ-LOCK &mdash; Waits until a given lock is available for
+read-only access, then evaluates its body with the lock
+held.</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+with-read-lock
+	  (read-write-lock) &amp;body body => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>read-write-lock
+            <variablelist>an object of typeCCL:READ-WRITE-LOCK.</variablelist>
+          </indexterm><indexterm>body
+            <variablelist>an implicit progn.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>the primary value returned by<literal>body</literal>.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Waits until <literal>read-write-lock</literal> has no
+writer,
+ensures that  is a
+reader of it, then executes <literal>body</literal>.</para>
+        <para>After executing <literal>body</literal>, if
+ was not a reader of
+<literal>read-write-lock</literal> before
+<literal>with-read-lock</literal> was called, the lock is
+released.  If it was already a reader, it remains one.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , ,</para>
+      </sect2>
+
+      <sect2 id="WITH-WRITE-LOCK">
+        <para>WITH-WRITE-LOCK</para>
+        <informalfigure>with-write-lock</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>WITH-WRITE-LOCK &mdash; Waits until the given lock is available for write
+access, then executes its body with the lock held.</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+with-write-lock
+	  (read-write-lock) &amp;body body
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>read-write-lock
+            <variablelist>an object of typeCCL:READ-WRITE-LOCK.</variablelist>
+          </indexterm><indexterm>body
+            <variablelist>an implicit progn.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>the primary value returned by<literal>body</literal>.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Waits until <literal>read-write-lock</literal> has no
+readers and no writer other than ,
+then ensures that  is the
+writer of it.  With the lock held, executes <literal>body</literal>.</para>
+        <para>After executing <literal>body</literal>, if
+ was not the writer of
+<literal>read-write-lock</literal> before
+<literal>with-write-lock</literal> was called, the lock is
+released.  If it was already the writer, it remains the
+writer.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , ,</para>
+      </sect2>
+
+      <sect2 id="MAKE-SEMAPHORE">
+        <para>MAKE-SEMAPHORE</para>
+        <informalfigure>make-semaphore</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>MAKE-SEMAPHORE &mdash; Creates and returns a semaphore, which can be used
+for synchronization between threads.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+make-semaphore
+	  => semaphore
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>semaphore
+            <variablelist>a newly-allocated object of type CCL:SEMAPHORE.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Creates and returns an object of type CCL:SEMAPHORE.
+A semaphore has an associated "count" which may be incremented
+and decremented atomically; incrementing it represents sending
+a signal, and decrementing it represents handling that signal.
+<literal>semaphore</literal> has an initial count of 0.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , , ,</para>
+      </sect2>
+
+      <sect2 id="SIGNAL-SEMAPHORE">
+        <para>SIGNAL-SEMAPHORE</para>
+        <informalfigure>signal-semaphore</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SIGNAL-SEMAPHORE &mdash; Atomically increments the count of a given
+semaphore.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+signal-semaphore
+	  semaphore => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>semaphore
+            <variablelist>an object of type CCL:SEMAPHORE.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>an integer representing an error identifierwhich was returned by the underlying OS call.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Atomically increments <literal>semaphore</literal>'s
+"count" by 1; this
+may enable a waiting thread to resume execution.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , , ,</para>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para><literal>result</literal> should probably be interpreted
+and acted on by <literal>signal-semaphore</literal>, because
+it is not likely to be meaningful to a lisp program, and the
+most common cause of failure is a type error.</para>
+      </sect2>
+
+      <sect2 id="WAIT-ON-SEMAPHORE">
+        <para>WAIT-ON-SEMAPHORE</para>
+        <informalfigure>wait-on-semaphore</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>WAIT-ON-SEMAPHORE &mdash; Waits until the given semaphore has a positive
+count which can be atomically decremented.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+wait-on-semaphore
+	  semaphore => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>semaphore
+            <variablelist>an object of type CCL:SEMAPHORE.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>WAIT-ON-SEMAPHORE always returns T.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Waits until <literal>semaphore</literal>
+has a positive count that can be
+atomically decremented; this will succeed exactly once for each
+corresponding call to SIGNAL-SEMAPHORE.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , , ,</para>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+      </sect2>
+
+      <sect2 id="TIMED-WAIT-ON-SEMAPHORE">
+        <para>TIMED-WAIT-ON-SEMAPHORE</para>
+        <informalfigure>timed-wait-on-semaphore</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>TIMED-WAIT-ON-SEMAPHORE &mdash; Waits until the given semaphore has a postive
+count which can be atomically decremented, or until a timeout
+expires.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+timed-wait-on-semaphore
+	  semaphore timeout => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>semaphore
+            <variablelist>An object of type CCL:SEMAPHORE.</variablelist>
+          </indexterm><indexterm>timeout
+            <variablelist>a time interval in seconds.  May be anynon-negative real number the <literal>floor</literal> ofwhich fits in 32 bits.  The default is 1.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>T if <literal>timed-wait-on-semaphore</literal>returned because it was able to decrement the count of<literal>semaphore</literal>; NIL if it returned becausethe duration <literal>timeout</literal> has beenexceeded.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Waits until <literal>semaphore</literal>
+has a positive count that can be
+atomically decremented, or until the duration
+<literal>timeout</literal> has
+elapsed.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , ,</para>
+      </sect2>
+
+      <sect2 id="PROCESS-INPUT-WAIT">
+        <para>PROCESS-INPUT-WAIT</para>
+        <informalfigure>process-input-wait</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-INPUT-WAIT &mdash; Waits until input is available on a given
+file-descriptor.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-input-wait
+	  fd &amp;optional timeout
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>fd
+            <variablelist>a file descriptor, which is a non-negative integerused by the OS to refer to an open file, socket, or similarI/O connection.  See CCL::STREAM-DEVICE.</variablelist>
+          </indexterm><indexterm>timeout
+            <variablelist>either NIL, or a time interval in seconds.  May be anynon-negative real number the <literal>floor</literal> ofwhich fits in 32 bits.  The default is NIL.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Wait until input is available on <literal>fd</literal>.
+This uses the <literal>select()</literal> system call, and is
+generally a fairly
+efficient way of blocking while waiting for input. More
+accurately, <literal>process-input-wait</literal>
+waits until it's possible to read
+from fd without blocking, or until <literal>timeout</literal>, if
+it is not NIL, has been exceeded.</para>
+        <para>Note that it's possible to read without blocking if
+the file is at its end - although, of course, the read will
+return zero bytes.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , ,</para>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para><literal>process-input-wait</literal> has a timeout parameter,
+and
+ does not.  This
+inconsistency should probably be corrected.</para>
+      </sect2>
+
+      <sect2 id="PROCESS-OUTPUT-WAIT">
+        <para>PROCESS-OUTPUT-WAIT</para>
+        <informalfigure>process-output-wait</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PROCESS-OUTPUT-WAIT &mdash; Waits until output is possible on a given file
+descriptor.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+process-output-wait fd
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>fd
+            <variablelist>a file descriptor, which is a non-negative integerused by the OS to refer to an open file, socket, or similarI/O connection.  See CCL::STREAM-DEVICE.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Wait until output is possible on <literal>fd</literal>.
+This uses the <literal>select()</literal> system call, and is
+generally a fairly
+efficient way of blocking while waiting to output.</para>
+        <para>If <literal>process-output-wait</literal> is called on
+a network socket which has not yet established a connection, it
+will wait until the connection is established.  This is an
+important use, often overlooked.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , ,</para>
+        <bridgehead renderas="sect3">Notes</bridgehead> 
+        <para>has a timeout parameter,
+and
+<literal>process-output-wait</literal> does not.  This
+inconsistency should probably be corrected.</para>
+      </sect2>
+
+      <sect2 id="WITH-TERMINAL-INPUT">
+        <para>WITH-TERMINAL-INPUT</para>
+        <informalfigure>with-terminal-input</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>WITH-TERMINAL-INPUT &mdash; Executes its body in an environment with exclusive
+read access to the terminal.</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+with-terminal-input
+	  &amp;body body => result
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>body
+            <variablelist>an implicit progn.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>the primary value returned by<literal>body</literal>.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Requests exclusive read access to the standard terminal
+stream, <literal>*terminal-io*</literal>.  Executes
+<literal>body</literal> in an environment with that access.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, :Y, , , , ,</para>
+      </sect2>
+
+      <sect2 id="iREQUEST-TERMINAL-INPUT-VIA-BREAK-">
+        <para>*REQUEST-TERMINAL-INPUT-VIA-BREAK*</para>
+        <informalfigure>request-terminal-input-via-break</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>*REQUEST-TERMINAL-INPUT-VIA-BREAK* &mdash; Controls how attempts to obtain ownership of
+terminal input are made.</para>
+        <para>Variable</para>
+        <bridgehead renderas="sect3">Value Type</bridgehead>
+        <para>A boolean.</para>
+        <bridgehead renderas="sect3">Initial Value</bridgehead>
+        <para>NIL.</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Controls how attempts to obtain ownership of terminal input
+are made. When NIL, a message is printed on *TERMINAL-IO*;
+it's expected that the user will later yield
+control of the terminal via the :Y toplevel command. When T, a
+BREAK condition is signaled in the owning process; continuing from
+the break loop will yield the terminal to the requesting process
+(unless the :Y command was already used to do so in the break
+loop.)</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, :Y, , , , ,</para>
+      </sect2>
+
+      <sect2 id="iY">
+        <para>:Y</para>
+        <informalfigure>:y</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>:Y &mdash; Yields control of terminal input to a specified
+lisp process (thread).</para>
+        <para>Toplevel Command</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+(:y p)
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>p
+            <variablelist>a lisp process (thread), designated either byan integer which matches its<literal>process-serial-number</literal>,or by a string which is <literal>equal</literal> toits <literal>process-name</literal>.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>:Y is a toplevel command, not a function.  As such, it
+can only be used interactively, and only from the initial
+process.</para>
+        <para>The command yields control of terminal input to the
+process <literal>p</literal>, which must have used
+ to request access to the
+terminal input stream.</para>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">, , , , , ,</para>
+      </sect2>
+    </sect1>
+  </chapter>
+
+  <chapter id="Programming-with-Sockets">
+    <title>Programming with Sockets</title>
+
+    <sect1 id="Sockets-Overview">
+      <para>OverviewOpenMCL supports the socket abstraction for
+      interprocess communication. A socket represents a connection to
+      another process, typically (but not necessarily) a TCP/IP
+      network connection to a client or server running on some other
+      machine on the network.</para>
+      <para>All symbols mentioned in this chapter are exported from
+      the CCL package. As of version 0.13, these symbols are
+      additionally exported from the OPENMCL-SOCKET package.</para>
+      <para>OpenMCL supports three types of sockets: TCP sockets, UDP
+      sockets, and Unix-domain sockets.  This should be enough for all
+      but the most esoteric network situations.  All sockets are
+      created by .  The type of socket depends on the arguments to it,
+      as follows:</para>
+      <term><indexterm>tcp-stream
+          <variablelist>A buffered bi-directional stream over a TCP/IP connection.tcp-stream is a subclass of stream, and you can read and write to itusing all the usual stream functions. Created by (make-socket:addess-family :internet :type :stream :connect :active ...) or by(accept-connection ...).</variablelist>
+        </indexterm><indexterm>file-socket-stream
+          <variablelist>A buffered bi-directional stream over a "UNIX domain"connection. file-socket-stream is a subclass of stream, and you canread and write to it using all the usual stream functions. Createdby (make-socket :address-family :file :type :stream :connect :active...) or by (accept-connection ...),</variablelist>
+        </indexterm><indexterm>listener-socket
+          <variablelist>A passive socket used to listen for incoming TCP/IPconnections on a particular port. A listener-socket is not a stream.It doesn't support I/O. It can only be used to create newtcp-streams by accept-connection. Created by (make-socket :type:stream :connect :passive ...)</variablelist>
+        </indexterm><indexterm>file-listener-socket
+          <variablelist>A passive socket used to listen for incoming UNIX domainconnections named by a file in the local filesystem. Alistener-socket is not a stream. It doesn't support I/O. It canonly be used to create new file-socket-streams by accept-connection.Created by (make-socket :address-family :file :type :stream :connect:passive ...)</variablelist>
+        </indexterm><indexterm>udp-socket
+          <variablelist>A socket representing a packet-based UDP/IP connection. Audp-socket supports I/O but it is not a stream. Instead, you mustuse the special functions send-to and receive-from to read and writeto it. Created by (make-socket :type :datagram ...)</variablelist>
+        </indexterm>
+      </term>
+    </sect1>
+
+    <sect1 id="Sockets-Dictionary">
+      <title>Sockets Dictionary</title>
+
+      <sect2 id="MAKE-SOCKET">
+        <para>MAKE-SOCKET</para>
+        <informalfigure>make-socket</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>MAKE-SOCKET &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+make-socket
+	  &amp;key address-family type connect eol format
+	  remote-host remote-port local-host local-port local-filename
+	  remote-filename keepalive reuse-address nodelay broadcast linger
+	  backlog
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>address-family
+            <variablelist>The address/protocol family of this socket. Currentlyonly :internet (the default), meaning IP, and :file,referring to UNIX domain addresses, are supported.</variablelist>
+          </indexterm><indexterm>type
+            <variablelist>One of :stream (the default) to request aconnection-oriented socket, or :datagram to request aconnectionless socket. The default is :stream.</variablelist>
+          </indexterm><indexterm>connect
+            <variablelist>This argument is only relevant to sockets of type:stream. One of :active (the default) to request a :passiveto request a file or TCP listener socket.</variablelist>
+          </indexterm><indexterm>eol
+            <variablelist>This argument is currently ignored (it is accepted forcompatibility with Franz Allegro).</variablelist>
+          </indexterm><indexterm>format
+            <variablelist>One of :text (the default), :binary, or :bivalent.This argument is ignored for :stream sockets for now, as:stream sockets are currently always bivalent (i.e. theysupport both character and byte I/O). For :datagram sockets,the format determines the type of buffer created byreceive-from.</variablelist>
+          </indexterm><indexterm>remote-host
+            <variablelist>Required for TCP streams, it specifies the host toconnect to (in any format acceptable to lookup-hostname).Ignored for listener sockets. For UDP sockets, it can beused to specify a default host for subsequent calls tosend-to or receive-from.</variablelist>
+          </indexterm><indexterm>remote-port
+            <variablelist>Required for TCP streams, it specifies the port toconnect to (in any format acceptable to lookup-port).Ignored for listener sockets. For UDP sockets, it can beused to specify a default port for subsequent calls to forsubsequent calls to send-to or receive-from.</variablelist>
+          </indexterm><indexterm>remote-filename
+            <variablelist>Required for file-socket streams, it specifies thename of a file in the local filesystem (e.g., NOT mountedvia NFS, AFP, SMB, ...) which names and controls access to aUNIX-domain socket.</variablelist>
+          </indexterm><indexterm>local-host
+            <variablelist>Allows you to specify a local host address for alistener or UDP socket, for the rare case where you want torestrict connections to those coming to a specific localaddress for security reasons.</variablelist>
+          </indexterm><indexterm>local-port
+            <variablelist>Specify a local port for a socket. Most useful forlistener sockets, where it is the port on which the socketwill listen for connections.</variablelist>
+          </indexterm><indexterm>local-filename
+            <variablelist>Required for file-listener-sockets. Specifies the nameof a file in the local filesystem which is used to name aUNIX-domain socket. The actual filesystem file should notpreviously exist when the file-listener-socket is created;its parent directory should exist and be writable by thecaller. The file used to name the socket will be deletedwhen the file-listener-socket is closed.</variablelist>
+          </indexterm><indexterm>keepalive
+            <variablelist>If true, enables the periodic transmission of"keepalive" messages.</variablelist>
+          </indexterm><indexterm>reuse-address
+            <variablelist>If true, allows the reuse of local ports in listenersockets, overriding some TCP/IP protocol specifications. Youwill need this if you are debugging a server..</variablelist>
+          </indexterm><indexterm>nodelay
+            <variablelist>If true, disables Nagle's algorithm, which triesto minimize TCP packet fragmentation by introducingtransmission delays in the absence of replies. Try settingthis if you are using a protocol which involves sending asteady stream of data with no replies and are seeingsignificant degradations in throughput.</variablelist>
+          </indexterm><indexterm>broadcast
+            <variablelist>If true, requests permission to broadcast datagrams ona UDP socket.</variablelist>
+          </indexterm><indexterm>linger
+            <variablelist>If specified and non-nil, should be the number ofseconds the OS is allowed to wait for data to be pushedthrough when a close is done. Only relevant for TCP sockets.</variablelist>
+          </indexterm><indexterm>backlog
+            <variablelist>For a listener socket, specifies the number ofconnections which can be pending but not accepted. Thedefault is 5, which is also the maximum on some operatingsystems.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Creates and returns a new socket</para>
+      </sect2>
+
+      <sect2 id="ACCEPT-CONNECTION">
+        <para>ACCEPT-CONNECTION</para>
+        <informalfigure>accept-connection</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>ACCEPT-CONNECTION &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+accept-connection
+	  (socket listener-socket) &amp;key wait
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The listener-socket to listen on.</variablelist>
+          </indexterm><indexterm>wait
+            <variablelist>If true (the default), and there are no connectionswaiting to be accepted, waits until one arrives. If false,returns NIL immediately.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Extracts the first connection on the queue of pending
+connections, accepts it (i.e. completes the connection startup
+protocol) and returns a new tcp-stream or file-socket-stream
+representing the newly established connection. The tcp stream
+inherits any properties of the listener socket that are relevant
+(e.g. :keepalive, :nodelay, etc.) The original listener socket
+continues to be open listening for more connections, so you can
+call accept-connection on it again.</para>
+      </sect2>
+
+      <sect2 id="DOTTED-TO-IPADDR">
+        <para>DOTTED-TO-IPADDR</para>
+        <informalfigure>dotted-to-ipaddr</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>DOTTED-TO-IPADDR &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+dotted-to-ipaddr
+	  dotted &amp;key errorp
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>dotted
+            <variablelist>A string representing an IP address in the"nn.nn.nn.nn" format</variablelist>
+          </indexterm><indexterm>errorp
+            <variablelist>If true (the default) an error is signaled if dottedis invalid. If false, NIL is returned.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Converts a dotted-string representation of a host address to
+a 32-bit unsigned IP address.</para>
+      </sect2>
+
+      <sect2 id="IPADDR-TO-DOTTED">
+        <para>IPADDR-TO-DOTTED</para>
+        <informalfigure>ipaddr-to-dotted</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>IPADDR-TO-DOTTED &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+ipaddr-to-dotted
+	  ipaddr &amp;key values
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>ipaddr
+            <variablelist>A 32-bit integer representing an internet host address</variablelist>
+          </indexterm><indexterm>values
+            <variablelist>If false (the default), returns a string in the form"nn.nn.nn.nn". If true, returns four valuesrepresenting the four octets of the address as unsigned8-bit integers.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Converts a 32-bit unsigned IP address into octets.</para>
+      </sect2>
+
+      <sect2 id="IPADDR-TO-HOSTNAME">
+        <para>IPADDR-TO-HOSTNAME</para>
+        <informalfigure>ipaddr-to-hostname</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>IPADDR-TO-HOSTNAME &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+ipaddr-to-hostname
+	  ipaddr &amp;key ignore-cache
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>ipaddr
+            <variablelist>a 32-bit integer representing an internet host address</variablelist>
+          </indexterm><indexterm>ignore-cache
+            <variablelist>This argument is ignored (it is accepted forcompatibility with Franz Allegro)</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Converts a 32-bit unsigned IP address into a host name
+string</para>
+      </sect2>
+
+      <sect2 id="LOOKUP-HOSTNAME">
+        <para>LOOKUP-HOSTNAME</para>
+        <informalfigure>lookup-hostname</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>LOOKUP-HOSTNAME &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+lookup-hostname
+	  host
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>host
+            <variablelist>Specifies the host. It can be either a host namestring such as "clozure.com", or a dotted addressstring such as "192.168.0.1", or a 32-bit unsignedIP address such as 3232235521.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Converts a host spec in any of the acceptable formats into a
+32-bit unsigned IP address</para>
+      </sect2>
+
+      <sect2 id="LOOKUP-PORT">
+        <para>LOOKUP-PORT</para>
+        <informalfigure>lookup-port</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>LOOKUP-PORT &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+lookup-port
+	  port protocol
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>port
+            <variablelist>Specifies the port. It can be either a string, such as"http" or a symbol, such as :http, or an unsignedport number. Note that a string is case-sensitive. A symbolis lowercased before lookup.</variablelist>
+          </indexterm><indexterm>protocol
+            <variablelist>Must be one of "tcp" or "udp".</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Finds the port number for the specified port and protocol</para>
+      </sect2>
+
+      <sect2 id="RECEIVE-FROM">
+        <para>RECEIVE-FROM</para>
+        <informalfigure>receive-from</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>RECEIVE-FROM &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+receive-from
+	  (socket udp-socket) size &amp;key buffer
+	  extract offset
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket to read from</variablelist>
+          </indexterm><indexterm>size
+            <variablelist>Maximum number of bytes to read. If the packet islarger than this, any extra bytes are discarded.</variablelist>
+          </indexterm><indexterm>buffer
+            <variablelist>If specified, must be either a string or a byte vectorwhich will be used to read in the data. If not specified, anew buffer will be created (of type determined bysocket-format).</variablelist>
+          </indexterm><indexterm>extract
+            <variablelist>If true, the subsequence of the buffer correspondingonly to the data read in is extracted and returned as thefirst value. If false (the default) the original buffer isreturned even if it is only partially filled.</variablelist>
+          </indexterm><indexterm>offset
+            <variablelist>Specifies the start offset into the buffer at whichdata is to be stored. The default is 0.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Reads a UDP packet from a socket. If no packets are
+available, waits for a packet to arrive. Returns four values:</para>
+        <varlistentry numeration="arabic">
+          <variablelist>The buffer with the data</variablelist>
+          <variablelist>The number of bytes read</variablelist>
+          <variablelist>The 32-bit unsigned IP address of the sender of the data</variablelist>
+          <variablelist>The port number of the sender of the data</variablelist>
+        </varlistentry>
+      </sect2>
+
+      <sect2 id="SEND-TO">
+        <para>SEND-TO</para>
+        <informalfigure>send-to</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SEND-TO &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+send-to
+	  (socket udp-socket) buffer size &amp;key remote-host
+	  remote-port offset
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket to write to</variablelist>
+          </indexterm><indexterm>buffer
+            <variablelist>A vector containing the data to send. It must beeither a string or a byte vector (either one is acceptableregardless of the stream format).</variablelist>
+          </indexterm><indexterm>size
+            <variablelist>Number of bytes to send</variablelist>
+          </indexterm><indexterm>remote-host
+            <variablelist>The host to send the packet to, in any formatacceptable to lookup-hostname. The default is the remotehost specified in the call to make-socket.</variablelist>
+          </indexterm><indexterm>remote-port
+            <variablelist>The port to send the packet to, in any formatacceptable to lookup-port. The default is the remote portspecified in the call to make-socket.</variablelist>
+          </indexterm><indexterm>offset
+            <variablelist>The offset in the buffer where the packet data starts</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Send a UDP packet over a socket.</para>
+      </sect2>
+
+      <sect2 id="SHUTDOWN">
+        <para>SHUTDOWN</para>
+        <informalfigure>shutdown</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SHUTDOWN &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+shutdown
+	  socket &amp;key direction
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket to shut down (typically a tcp-stream)</variablelist>
+          </indexterm><indexterm>direction
+            <variablelist>One of :input to disallow further input, or :output todisallow further output.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Shuts down part of a bidirectional connection. This is
+useful if e.g. you need to read responses after sending an
+end-of-file signal.</para>
+      </sect2>
+
+      <sect2 id="SOCKET-OS-FD">
+        <para>SOCKET-OS-FD</para>
+        <informalfigure>socket-os-fd</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SOCKET-OS-FD &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+socket-os-fd
+	  socket
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the native OS's representation of the socket, or
+NIL if the socket is closed. On Unix, this is the Unix 'file
+descriptor', a small non-negative integer. Note that it is
+rather dangerous to mess around with tcp-stream fd's, as there
+is all sorts of buffering and asynchronous I/O going on above the
+OS level. listener-socket and udp-socket fd's are safer to
+mess with directly as there is less magic going on.</para>
+      </sect2>
+
+      <sect2 id="REMOTE-HOST">
+        <para>REMOTE-HOST</para>
+        <informalfigure>remote-host</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>REMOTE-HOST &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+remote-host
+	  socket
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the 32-bit unsigned IP address of the remote host,
+or NIL if the socket is not connected.</para>
+      </sect2>
+
+      <sect2 id="REMOTE-PORT">
+        <para>REMOTE-PORT</para>
+        <informalfigure>remote-port</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>REMOTE-PORT &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+remote-port
+	  socket
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the remote port number, or NIL if the socket is not
+connected.</para>
+      </sect2>
+
+      <sect2 id="LOCAL-HOST">
+        <para>LOCAL-HOST</para>
+        <informalfigure>local-host</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>LOCAL-HOST &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+local-host
+	  socket
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns 32-bit unsigned IP address of the local host.</para>
+      </sect2>
+
+      <sect2 id="LOCAL-PORT">
+        <para>LOCAL-PORT</para>
+        <informalfigure>local-port</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>LOCAL-PORT &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+local-port
+	  socket
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the local port number</para>
+      </sect2>
+
+      <sect2 id="SOCKET-ADDRESS-FAMILY">
+        <para>SOCKET-ADDRESS-FAMILY</para>
+        <informalfigure>socket-address-family</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SOCKET-ADDRESS-FAMILY &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+socket-address-family
+	  socket
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns :internet or :file, as appropriate.</para>
+      </sect2>
+
+      <sect2 id="SOCKET-CONNECT">
+        <para>SOCKET-CONNECT</para>
+        <informalfigure>socket-connect</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SOCKET-CONNECT &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+socket-connect
+	  socket
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns :active for tcp-stream, :passive for
+listener-socket, and NIL for udp-socket</para>
+      </sect2>
+
+      <sect2 id="SOCKET-FORMAT">
+        <para>SOCKET-FORMAT</para>
+        <informalfigure>socket-format</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SOCKET-FORMAT &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+socket-format
+	  socket
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the socket format as specified by the :format
+argument to make-socket.</para>
+      </sect2>
+
+      <sect2 id="SOCKET-TYPE">
+        <para>SOCKET-TYPE</para>
+        <informalfigure>socket-type</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SOCKET-TYPE &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+socket-type
+	  socket
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>returns :stream for tcp-stream and listener-socket, and
+:datagram for udp-socket.</para>
+      </sect2>
+
+      <sect2 id="SOCKET-ERROR">
+        <para>SOCKET-ERROR</para>
+        <informalfigure>socket-error</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SOCKET-ERROR &mdash;</para>
+        <para>Class</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>The class of OS errors signaled by socket functions</para>
+        <bridgehead renderas="sect3">Superclasses</bridgehead>
+        <para>simple-error</para>
+      </sect2>
+
+      <sect2 id="SOCKET-ERROR-CODE">
+        <para>SOCKET-ERROR-CODE</para>
+        <informalfigure>socket-error-code</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SOCKET-ERROR-CODE &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+socket-error-code
+	  socket-error
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket-error
+            <variablelist>the condition</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>The OS error code of the error</para>
+      </sect2>
+
+      <sect2 id="SOCKET-ERROR-IDENTIFIER">
+        <para>SOCKET-ERROR-IDENTIFIER</para>
+        <informalfigure>socket-error-identifier</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SOCKET-ERROR-IDENTIFIER &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+socket-error-identifier
+	  socket-error
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket-error
+            <variablelist>the condition</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>A symbol representing the error code in a more
+OS-independent way.</para>
+        <para>One of: :address-in-use :connection-aborted :no-buffer-space
+:connection-timed-out :connection-refused :host-unreachable
+:host-down :network-down :address-not-available :network-reset
+:connection-reset :shutdown :access-denied or :unknown.</para>
+      </sect2>
+
+      <sect2 id="SOCKET-ERROR-SITUATION">
+        <para>SOCKET-ERROR-SITUATION</para>
+        <informalfigure>socket-error-situation</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SOCKET-ERROR-SITUATION &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+socket-error-situation
+	  socket-error
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket-error
+            <variablelist>the condition</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>A string describing the context where the error happened. On
+Linux, this is the name of the system call which returned the
+error.</para>
+      </sect2>
+
+      <sect2 id="CLOSE">
+        <para>CLOSE</para>
+        <informalfigure>close</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CLOSE &mdash;</para>
+        <para>Method</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+close
+	  (socket socket) &amp;key abort
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>socket
+            <variablelist>The socket to close</variablelist>
+          </indexterm><indexterm>abort
+            <variablelist>If false (the default), closes the socket in anorderly fashion, finishing up any buffered pending I/O,before closing the connection. If true, aborts/ignorespending I/O. (For listener and udp sockets, this argument iseffectively ignored since there is never any buffered I/O toclean up).</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>The close generic function can be applied to sockets. It
+releases the operating system resources associated with the
+socket.</para>
+      </sect2>
+
+      <sect2 id="WITH-OPEN-SOCKET">
+        <para>WITH-OPEN-SOCKET</para>
+        <informalfigure>with-open-socket</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>WITH-OPEN-SOCKET &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+with-open-socket
+	  (var . make-socket-args) &amp;body body
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>var
+            <variablelist>variable to bind</variablelist>
+          </indexterm><indexterm>make-socket-args
+            <variablelist>arguments suitable for passing to make-socket</variablelist>
+          </indexterm><indexterm>body
+            <variablelist>body to execute</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>executes body with var bound to the result of applying
+make-socket to make-socket-args. The socket gets closed on exit.</para>
+      </sect2>
+    </sect1>
+  </chapter>
+
+  <chapter id="Running-Other-Programs-as-Subprocesses">
+    <title>Running Other Programs as Subprocesses</title>
+
+    <sect1 id="Subprocess-Overview">
+      <title>Overview</title>
+      <para>OpenMCL provides primitives to run external Unix programs,
+      to select and connect Lisp streams to their input and output
+      sources, to (optionally) wait for their completion and to check
+      their execution and exit status.</para>
+      <para>All of the global symbols described below are exported
+      from the CCL package.</para>
+      <para>This implementation is modeled on - and uses some code
+      from - similar facilities in CMUCL.</para>
+    </sect1>
+
+    <sect1 id="Subprocess-Examples">
+      <title>Examples</title>
+      <programlisting>
+;;; Capture the output of the "uname" program in a lisp string-stream
+;;; and return the generated string (which will contain a trailing
+;;; newline.)
+? (with-output-to-string (stream)
+    (run-program "uname" '("-r") :output stream))
+;;; Write a string to *STANDARD-OUTPUT*, the hard way.
+? (run-program "cat" () :input (make-string-input-stream "hello") :output t)
+;;; Find out that "ls" doesn't expand wildcards.
+? (run-program "ls" '("*.lisp") :output t)
+;;; Let the shell expand wildcards.
+? (run-program "sh" '("-c" "ls *.lisp") :output t)
+</programlisting>
+      <para>These last examples will only produce output if OpenMCL's
+      current directory contains .lisp files, of course.</para>
+    </sect1>
+
+    <sect1 id="Limitations-and-known-bugs">
+      <para>Limitations and known bugs</para>
+      <itemizedlist>
+        <listitem><para>OpenMCL and the external processs may get
+        confused about whoowns which streams when input, output, or
+        error are specified as T and wait is specified as
+        NIL.</para></listitem>
+        <listitem><para>External processes that need to talk to a
+        terminal device may not work properly; the environment (SLIME,
+        ILISP) under which OpenMCL is run can affect
+        this.</para></listitem>
+      
+      </itemizedlist>
+    </sect1>
+
+    <sect1 id="External-Program-Dictionary">
+      <title>External-Program Dictionary</title>
+
+      <sect2 id="RUN-PROGRAM">
+        <para>RUN-PROGRAM</para>
+        <informalfigure>run-program</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>RUN-PROGRAM &mdash; Invokes an external program as an OS subprocess
+of lisp.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+run-program
+	    program args &amp;key (wait t) pty input
+	    if-input-does-not-exist output (if-output-exists :error) (error
+	    :output) (if-error-exists :error) status-hook
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>program
+            <variablelist>A string or pathname which denotes an executable file.The PATH environment variable is used to find programs whosename doesn't contain a directory component.</variablelist>
+          </indexterm><indexterm>args
+            <variablelist>A list of simple-strings</variablelist>
+          </indexterm><indexterm>wait
+            <variablelist>Indicates whether or not run-program should wait forthe EXTERNAL-PROCESS to complete or should returnimmediately.</variablelist>
+          </indexterm><indexterm>pty
+            <variablelist>This option is accepted but currently ignored;it's intended to make it easier to run external programsthat need to interact with a terminal device.</variablelist>
+          </indexterm><indexterm>input
+            <variablelist>Selects the input source used by the EXTERNAL-PROCESS.May be any of the following:
+              <listitem mark="bullet">
+                <variablelist>NIL Specifies that a null input stream (e.g.,/dev/null) should be used.</variablelist>
+                <variablelist>T Specifies that the EXTERNAL-PROCESS should usethe input source with which OpenMCL was invoked.</variablelist>
+                <variablelist>A string or pathname. Specifies that theEXTERNAL-PROCESS should receive its input from the namedexisting file.</variablelist>
+                <variablelist>:STREAM Creates a Lisp stream opened for characteroutput. Any data written to this stream (accessible asthe EXTERNAL-PROCESS-INPUT-STREAM of theEXTERNAL-PROCESS object) appears as input to theexternal process.</variablelist>
+                <variablelist>A stream. Specifies that the lisp stream shouldprovide input to the EXTERNAL-PROCESS.</variablelist>
+              
+              </listitem>
+</variablelist>
+          </indexterm><indexterm>if-input-does-not-exist
+            <variablelist>If the input argument specifies the name of anexisting file, this argument is used as theif-does-not-exist argument to OPEN when that file is opened.</variablelist>
+          </indexterm><indexterm>output
+            <variablelist>Specifies where standard output from the externalprocess should be sent. Analogous to input above.</variablelist>
+          </indexterm><indexterm>if-output-exists
+            <variablelist>If output is specified as a string or pathname, thisargument is used as the if-exists argument to OPEN when thatfile is opened.</variablelist>
+          </indexterm><indexterm>error
+            <variablelist>Specifies where error output from the external processshould be sent. In addition to the values allowed foroutput, the keyword :OUTPUT can be used to indicate thaterror output should be sent where standard output goes.</variablelist>
+          </indexterm><indexterm>if-error-exists
+            <variablelist>Analogous to if-output-exists.</variablelist>
+          </indexterm><indexterm>status-hook
+            <variablelist>A user-defined function of one argument (theEXTERNAL-PROCESS structure.) This function is calledwhenever OpenMCL detects a change in the staus of theEXTERNAL-PROCESS.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Runs the specified program in an external (Unix) process,
+returning an object of type EXTERNAL-PROCESS if successful.</para>
+      </sect2>
+
+      <sect2 id="SIGNAL-EXTERNAL-PROCESS">
+        <para>SIGNAL-EXTERNAL-PROCESS</para>
+        <informalfigure>signal-external-process</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SIGNAL-EXTERNAL-PROCESS &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+signal-external-process
+	    proc signal-number
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>proc
+            <variablelist>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.</variablelist>
+          </indexterm><indexterm>signal
+            <variablelist>A small integer.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Sends the specified "signal" to the specified
+external process. (Typically, it would only be useful tocall
+this function if the EXTERNAL-PROCESS was created with :WAIT
+NIL. ) Returns T if successful; signals an error otherwise.</para>
+      </sect2>
+
+      <sect2 id="EXTERNAL-PROCESS-ID">
+        <para>EXTERNAL-PROCESS-ID</para>
+        <informalfigure>external-process-id</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>EXTERNAL-PROCESS-ID &mdash; Returns the "process ID" of an OS subprocess,
+a positive integer which identifies it.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+external-process-id
+	    proc
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>proc
+            <variablelist>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the <emphasis>process id</emphasis> assigned to
+the external process by the operating system. This is typically
+a positive, 16-bit number.</para>
+      </sect2>
+
+      <sect2 id="EXTERNAL-PROCESS-INPUT-STREAM">
+        <para>EXTERNAL-PROCESS-INPUT-STREAM</para>
+        <informalfigure>external-process-input-stream</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>EXTERNAL-PROCESS-INPUT-STREAM &mdash; Returns the lisp stream which is used to write
+input to a given OS subprocess, if it has one.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+external-process-input-stream
+	    proc
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>proc
+            <variablelist>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the stream created when the input argument to
+run-program is specified as :STREAM.</para>
+      </sect2>
+
+      <sect2 id="EXTERNAL-PROCESS-OUTPUT-STREAM">
+        <para>EXTERNAL-PROCESS-OUTPUT-STREAM</para>
+        <informalfigure>external-process-output-stream</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>EXTERNAL-PROCESS-OUTPUT-STREAM &mdash; Returns the lisp stream which is used to read
+output from an OS subprocess, if there is one.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+external-process-output-stream
+	    proc
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>proc
+            <variablelist>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the stream created when the output argument to
+run-program is specified as :STREAM.</para>
+      </sect2>
+
+      <sect2 id="EXTERNAL-PROCESS-ERROR-STREAM">
+        <para>EXTERNAL-PROCESS-ERROR-STREAM</para>
+        <informalfigure>external-process-error-stream</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>EXTERNAL-PROCESS-ERROR-STREAM &mdash; Returns the stream which is used to read
+"error" output from a given OS subprocess, if it has
+one.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+external-process-error-stream
+	    proc
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>proc
+            <variablelist>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the stream created when the error argument to
+run-program is specified as :STREAM.</para>
+      </sect2>
+
+      <sect2 id="EXTERNAL-PROCESS-STATUS">
+        <para>EXTERNAL-PROCESS-STATUS</para>
+        <informalfigure>external-process-status</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>EXTERNAL-PROCESS-STATUS &mdash; Returns information about whether an OS
+subprocess is running; or, if not, why not; and what its
+result code was if it completed.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+external-process-status
+	    proc
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>proc
+            <variablelist>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns, as multiple values, a keyword denoting the status
+of the external process (one of :running, :stopped, :signaled, or
+:exited), and the exit code or terminating signal if the first
+value is other than :running.</para>
+      </sect2>
+    </sect1>
+  </chapter>
+
+  <chapter id="Creating-Your-Own-Stream-Classes-with-Gray-Streams">
+    <title>Creating Your Own Stream Classes with Gray Streams</title>
+
+    <sect1 id="Streams-Overview">
+      <title>Overview</title>
+      <para>This chapter is still being written and revised, because
+      it is woefully incomplete.  The dictionary section currently
+      only lists a couple functions.  Caveat lector.</para>
+      <para>Gray streams are an extension to Common Lisp.  They were
+      proposed for standardization by David Gray (the astute reader
+      now understands their name) quite some years ago, but not
+      accepted, because they had not been tried sufficiently to find
+      conceptual problems with them.</para>
+      <para>They have since been implemented by quite a few modern
+      Lisp implementations.  However, they do indeed have some
+      inadequacies, and each implementation has addressed these in
+      different ways.  The situation today is that it's difficult to
+      even find out how to get started using Gray streams.  This is
+      why standards are important.</para>
+      <para>Here's a list of some classes which you might wish for
+      your new stream class to inherit from:</para>
+      <colspec>
+        <thead cols="1">
+          <tbody colwidth="100*"></tbody>
+          <row>
+            <abstract>
+              <entry>fundamental-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>fundamental-input-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>fundamental-output-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>fundamental-character-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>fundamental-binary-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>fundamental-character-input-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>fundamental-character-output-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>fundamental-binary-input-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>fundamental-binary-output-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::buffered-stream-mixin</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::buffered-input-stream-mixin</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::buffered-output-stream-mixin</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::buffered-io-stream-mixin</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::buffered-character-input-stream-mixin</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::buffered-character-output-stream-mixin</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::buffered-character-io-stream-mixin</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::buffered-binary-input-stream-mixin</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::buffered-binary-output-stream-mixin</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::buffered-binary-io-stream-mixin</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>file-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>file-input-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>file-output-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>file-io-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>file-character-input-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>file-character-output-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>file-charcter-io-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>file-binary-input-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>file-binary-output-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>file-binary-io-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::fd-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::fd-input-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::fd-output-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::fd-io-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::fd-character-input-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::fd-character-output-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::fd-character-io-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::fd-binary-input-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::fd-binary-output-stream</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::fd-binary-io-stream</entry>
+            
+            </abstract>
+          </row>
+        </thead>
+      </colspec>
+      <para>All of these are defined in ccl/level-1/l1-streams.lisp, except for
+the ccl:file-* ones, which are in ccl/level-1/l1-sysio.lisp.</para>
+      <para>According to the original Gray streams proposal, you should inherit
+from the most specific of the
+fundamental-* classes which applies.  Using OpenMCL, though, if you
+want
+buffering for better performance, which, unless you know of some
+reason you wouldn't, you do,
+you should instead inherit from the appropriate ccl::buffered-* class
+The buffering you get this way is exactly the same as the
+buffering which is used on ordinary, non-Gray streams, and force-output
+will work properly on it.</para>
+      <para>Notice that -mixin suffix in the names of all the ccl::buffered-*
+classes?
+The suffix means that this class
+is not "complete"
+by itself; you still need to inherit from a fundamental-* stream,
+even if you also inherit from a *-mixin stream.  You might consider
+making your own class like this.  ....  Except that they do
+inherit from the fundamental-* streams, that's weird.</para>
+      <para>If you want to be able to create an instance of your class with the
+:class argument to (open) and (with-open-file), you should make it
+inherit from one of the file-* classes.  If you do this, it's not
+necessary to inherit from any of the other classes (though it won't
+hurt anything), since the file-* classes already do.</para>
+      <para>When you inherit from the file-* classes, you can use
+(call-next-method) in any of your methods to get the standard
+behaviour.  This is especially useful if you want to create a class
+which performs some simple filtering operation, such
+as changing everything to uppercase or to a different character
+encoding.  If you do this, you will definitely need to specialize
+ccl::select-stream-class.  Your method on ccl::stream-select-class
+should accept an instance of the class, but pay no attention to its
+contents, and return a symbol naming the
+class to actually be instantiated.</para>
+      <para>If you need to make your functionality generic across all the
+different types of stream, probably the best way
+to implement it is to make it a mixin, define classes with all the
+variants of input, output, io, character, and binary, which inherit
+both from your mixin and from the appropriate other class, then
+define a method on ccl::select-stream-class which chooses from among
+those classes.</para>
+      <para>Note that some of these classes are internal
+to the CLL package.  If you try to inherit from those ones without
+the ccl:: prefix, you'll get an error which may confuse you, calling
+them "forward-referenced classes".  That just means you used the
+wrong symbol, so add the prefix.</para>
+      <para>Here's a list of some generic functions which you might wish to
+specialize for your new stream class, and which ought to be
+documented at some point.</para>
+      <colspec>
+        <thead cols="1">
+          <tbody colwidth="100*"></tbody>
+          <row>
+            <abstract>
+              <entry>stream-direction stream =></entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-device stream direction =></entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-length stream <literal>&amp;optional</literal>new =></entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-position stream <literal>&amp;optional</literal>new =></entry>
+            
+            </abstract>
+            <abstract>
+              <entry>streamp stream => boolean</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-write-char output-stream char =></entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-write-entire-string output-stream string =></entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-read-char input-stream =></entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-unread-char input-stream char =></entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-force-output output-stream => nil</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-maybe-force-output output-stream => nil</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-finish-output output-stream => nil</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-clear-output output-stream => nil</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>close stream <literal>&amp;key</literal>abort => boolean</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-fresh-line stream => t</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-line-length stream => length</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>interactive-stream-p stream => boolean</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-clear-input input-stream => nil</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-listen input-stream => boolean</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-filename stream => string</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>ccl::select-stream-class instance in-p out-p char-p =>class</entry>
+            
+            </abstract>
+          </row>
+        </thead>
+      </colspec>
+      <para>The following functions are standard parts of Common Lisp, but
+behave in special ways with regard to Gray streams.</para>
+      <colspec>
+        <thead cols="1">
+          <tbody colwidth="100*"></tbody>
+          <row>
+            <abstract>
+              <entry>open-stream-p stream => generalized-boolean</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>input-stream-p stream => generalized-boolean</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>output-stream-p stream => generalized-boolean</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-element-type stream =></entry>
+            
+            </abstract>
+            <abstract>
+              <entry>stream-error-stream =></entry>
+            
+            </abstract>
+            <abstract>
+              <entry>open</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>close</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>with-open-file</entry>
+            
+            </abstract>
+          </row>
+        </thead>
+      </colspec>
+      <para>Specifically, (open) and (with-open-file) accept a new keyword
+argument, :class, which may be a symbol naming a class; the class
+itself; or an instance of it.  The class so given must be a subtype
+of 'stream, and an instance of it with no particular contents will
+be passed to ccl::select-stream-class to determine what class to
+actually instantiate.</para>
+      <para>The following are standard, and do not behave specially with
+regard to Gray streams, but probably should.</para>
+      <colspec>
+        <thead cols="1">
+          <tbody colwidth="100*"></tbody>
+          <row>
+            <abstract>
+              <entry>stream-external-format</entry>
+            
+            </abstract>
+          </row>
+        </thead>
+      </colspec>
+    </sect1>
+
+    <sect1 id="Extending-READ-SEQUENCE-and-WRITE-SEQUENCE">
+      <title>Extending READ-SEQUENCE and WRITE-SEQUENCE</title>
+
+      <sect2 id="extending-read-write-overview">
+        <title>Overview</title>
+	<para>The "Gray Streams" API is based on an informal proposal that was
+	made before ANSI CL adopted the READ-SEQUENCE and WRITE-SEQUENCE
+	functions; as such, there is no "standard" way for the author of a Gray
+	stream class to improve the performance of these functions by exploiting
+	knowledge of the stream's internals (e.g., the buffering mechanism it
+	uses.)</para>
+        <para>In the absence of any such knowledge, READ-SEQUENCE and
+        WRITE-SEQUENCE are effectively just convenient shorthand for a
+        loop which calls READ-CHAR/READ-BYTE/WRITE-CHAR/WRITE-BYTE as
+        appropriate. The mechanism described below allows subclasses
+        of FUNDAMENTAL-STREAM to define more specialized (and
+        presumably more efficient) behavior.</para>
+      </sect2>
+
+      <sect2 id="Notes">
+	<title>Notes</title>
+        <para>READ-SEQUENCE and WRITE-SEQUENCE do a certain amount of
+        sanity-checking and normalization of their arguments before
+        dispatching to one of the methods above. If an individual
+        method can't do anything particularly clever, CALL-NEXT-METHOD
+        can be used to handle the general case.</para>
+      </sect2>
+
+      <sect2 id="Example">
+        <title>Example</title>
+        <programlisting>
+(defclass my-string-input-stream (fundamental-character-input-stream)
+  ((string :initarg :string :accessor my-string-input-stream-string)
+   (index :initform 0 :accessor my-string-input-stream-index)
+   (length)))
+
+(defmethod stream-read-vector ((stream my-string-input-stream) vector start end)
+  (if (not (typep vector 'simple-base-string))
+      (call-next-method)
+      (with-slots (string index length)
+        (do* ((outpos start (1+ outpos)))
+             ((or (= outpos end)
+                  (= index length))
+              outpos))
+          (setf (schar vector outpos)
+                (schar string index))
+          (incf index)))))
+</programlisting>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Multibyte-I-O">
+      <title>Multibyte I/O</title>
+      <para>All heap-allocated objects in OpenMCL that cannot contain
+      pointers to lisp objects are represented as
+      <emphasis>ivectors</emphasis>. OpenMCL provides low-level
+      functions, and , to efficiently transfer data between buffered
+      streams and ivectors. There's some overlap in functionality
+      between the functions described here and the ANSI CL
+      READ-SEQUENCE and WRITE-SEQUENCE functions.</para>
+      <para>As used here, the term "octet" means roughly the same
+      thing as the term "8-bit byte". The functions described below
+      transfer a specified sequence of octets between a buffered
+      stream and an ivector, and don't really concern themselves with
+      higher-level issues (like whether that octet sequence is within
+      bounds or how it relates to the logical contents of the
+      ivector.) For these reasons, these functions are generally less
+      safe and more flexible than their ANSI counterparts.</para>
+    </sect1>
+
+    <sect1 id="Gray-Streams-Dictionary">
+      <title>Gray Streams Dictionary</title>
+
+      <sect2 id="CCL-STREAM-READ-LIST">
+        <para>CCL:STREAM-READ-LIST</para>
+        <informalfigure>stream-read-list</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL:STREAM-READ-LIST &mdash;</para>
+        <para>Generic Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+stream-read-list
+	  stream list count
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>stream
+            <variablelist>a stream, presumably a fundamental-input-stream.</variablelist>
+          </indexterm><indexterm>list
+            <variablelist>a list. When a STREAM-READ-LIST method is called byREAD-SEQUENCE, this argument is guaranteed to be a properlist.</variablelist>
+          </indexterm><indexterm>count
+            <variablelist>a non-negative integer. When a STREAM-READ-LIST methodis called by READ-SEQUENCE, this argument is guaranteed notto be greater than the length of the list.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Should try to read up to count elements from stream into the
+list list, returning the number of elements actually read (which
+may be less than count in case of a premature end-of-file.)</para>
+      </sect2>
+
+      <sect2 id="CCL-STREAM-WRITE-LIST">
+        <para>CCL:STREAM-WRITE-LIST</para>
+        <informalfigure>stream-write-list</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL:STREAM-WRITE-LIST &mdash;</para>
+        <para>Generic Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+stream-write-list
+	  stream list count
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>stream
+            <variablelist>a stream, presumably a fundamental-ouput-stream.</variablelist>
+          </indexterm><indexterm>list
+            <variablelist>a list. When a STREAM-WRITE-LIST method is called byWRITE-SEQUENCE, this argument is guaranteed to be a properlist.</variablelist>
+          </indexterm><indexterm>count
+            <variablelist>a non-negative integer. When a STREAM-WRITE-LISTmethod is called by WRITE-SEQUENCE, this argument isguaranteed not to be greater than the length of the list.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>should try to write the first count elements of list to
+stream. The return value of this method is ignored.</para>
+      </sect2>
+
+      <sect2 id="CCL-STREAM-READ-VECTOR">
+        <para>CCL:STREAM-READ-VECTOR</para>
+        <informalfigure>stream-read-vector</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL:STREAM-READ-VECTOR &mdash;</para>
+        <para>Generic Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+stream-read-vector
+	  stream vector start end
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>stream
+            <variablelist>a stream, presumably a fundamental-input-stream</variablelist>
+          </indexterm><indexterm>vector
+            <variablelist>a vector. When a STREAM-READ-VECTOR method is calledby READ-SEQUENCE, this argument is guaranteed to be a simpleone-dimensional array.</variablelist>
+          </indexterm><indexterm>start
+            <variablelist>a non-negative integer. When a STREAM-READ-VECTORmethod is called by READ-SEQUENCE, this argument isguaranteed to be no greater than end and not greater thanthe length of vector.</variablelist>
+          </indexterm><indexterm>end
+            <variablelist>a non-negative integer. When a STREAM-READ-VECTORmethod is called by READ-SEQUENCE, this argument isguaranteed to be no less than end and not greater than thelength of vector.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>should try to read successive elements from stream into
+vector, starting at element start (inclusive) and continuing
+through element end (exclusive.) Should return the index of the
+vector element beyond the last one stored into, which may be less
+than end in case of premature end-of-file.</para>
+      </sect2>
+
+      <sect2 id="CCL-STREAM-WRITE-VECTOR">
+        <para>CCL:STREAM-WRITE-VECTOR</para>
+        <informalfigure>stream-write-vector</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL:STREAM-WRITE-VECTOR &mdash;</para>
+        <para>Generic Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+stream-write-vector
+	  stream vector start end
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>stream
+            <variablelist>a stream, presumably a fundamental-output-stream</variablelist>
+          </indexterm><indexterm>vector
+            <variablelist>a vector. When a STREAM-WRITE-VECTOR method is calledby WRITE-SEQUENCE, this argument is guaranteed to be asimple one-dimensional array.</variablelist>
+          </indexterm><indexterm>start
+            <variablelist>a non-negative integer. When a STREAM-WRITE-VECTORmethod is called by WRITE-SEQUENCE, this argument isguaranteed to be no greater than end and not greater thanthe length of vector.</variablelist>
+          </indexterm><indexterm>end
+            <variablelist>a non-negative integer. When a STREAM-WRITE-VECTORmethod is called by WRITE-SEQUENCE, this argument isguaranteed to be no less than end and not greater than thelength of vector.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>should try to write successive elements of vector to stream,
+starting at element start (inclusive) and continuing through
+element end (exclusive.)</para>
+      </sect2>
+
+      <sect2 id="CCL--STREAM-DEVICE">
+        <para>CCL::STREAM-DEVICE</para>
+        <informalfigure>stream-device</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::STREAM-DEVICE &mdash; Returns the OS file descriptor associated with a
+given lisp stream.</para>
+        <para>Generic Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+ccl::stream-device
+	  s direction
+</programlisting>
+        <bridgehead renderas="sect3">Method Signatures</bridgehead>
+        <programlisting>
+ccl::stream-device
+	  (s stream) direction => fd
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>s
+            <variablelist>a stream.</variablelist>
+          </indexterm><indexterm>direction
+            <variablelist>either :INPUT or :OUTPUT.</variablelist>
+          </indexterm><indexterm>fd
+            <variablelist>a file descriptor, which is a non-negative integerused by the OS to refer to an open file, socket, or similarI/O connection.  NIL if there is no file descriptor associatedwith <literal>s</literal> in the direction given by<literal>direction</literal>.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the file descriptor associated with
+<literal>s</literal> in the direction given by
+<literal>direction</literal>.  It is necessary to specify
+<literal>direction</literal> because the input and output
+file descriptors may be different; the most common case is when
+one of them has been redirected by the Unix shell.</para>
+      </sect2>
+
+      <sect2 id="STREAM-READ-IVECTOR">
+        <para>STREAM-READ-IVECTOR</para>
+        <informalfigure>stream-read-ivector</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>STREAM-READ-IVECTOR &mdash;</para>
+        <para>Generic Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+stream-read-ivector
+	  stream ivector start-octet max-octets
+</programlisting>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Reads up to max-octets octets from stream into ivector,
+storing them at start-octet. Returns the number of octets actually
+read.</para>
+        <bridgehead renderas="sect3">Arguments</bridgehead>
+        <term><indexterm>stream
+            <variablelist>An input stream. The method defined onBUFFERED-INPUT-STREAMs requires that the size in octets ofan instance of the stream's element type is 1.</variablelist>
+          </indexterm><indexterm>ivector
+            <variablelist>Any ivector.</variablelist>
+          </indexterm><indexterm>start-octet
+            <variablelist>A non-negative integer.</variablelist>
+          </indexterm><indexterm>max-octets
+            <variablelist>A non-negative integer. The return value may be lessthan the value of this parameter if EOF was encountered.</variablelist>
+          </indexterm>
+        </term>
+      </sect2>
+
+      <sect2 id="STREAM-WRITE-IVECTOR">
+        <para>STREAM-WRITE-IVECTOR</para>
+        <informalfigure>stream-write-ivector</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>STREAM-WRITE-IVECTOR &mdash;</para>
+        <para>Generic Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+stream-write-ivector stream
+	  ivector start-octet max-octets
+</programlisting>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Writes max-octets octets to stream from ivector, starting at
+start-octet. Returns max-octets.</para>
+        <bridgehead renderas="sect3">Arguments</bridgehead>
+        <term><indexterm>stream
+            <variablelist>An input stream. The method defined onBUFFERED-OUTPUT-STREAMs requires that the size in octets ofan instance of the stream's element type is 1.</variablelist>
+          </indexterm><indexterm>ivector
+            <variablelist>Any ivector</variablelist>
+          </indexterm><indexterm>start-octet
+            <variablelist>A non-negative integer.</variablelist>
+          </indexterm><indexterm>max-octet
+            <variablelist>A non-negative integer.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Examples</bridgehead>
+        <programlisting>
+;;; Write the contents of a (SIMPLE-ARRAY(UNSIGNED-BYTE 16) 3)
+;;; to a character file stream. Read back the characters.
+(let* ((a (make-array 3
+                     :element-type '(unsigned-byte 16)
+                     :initial-contents '(26725 27756 28449))))
+  (with-open-file (s "junk"
+                   :element-type 'character
+                   :direction :io
+                   :if-does-not-exist :create
+                   :if-exists :supersede)
+    ;; Write six octets (three elements).
+    (stream-write-ivector s a 0 6)
+    ;; Rewind, then read a line
+    (file-position s 0)
+    (read-line s)))
+
+;;; Write a vector of DOUBLE-FLOATs. Note that (to maintain
+;;; alignment) there are 4 octets of padding before the 0th
+;;; element of a (VECTOR DOUBLE-FLOAT) in 32-bit OpenMCL.
+;;; (Note that (= (- ppc32::misc-dfloat-offset
+;;;                  ppc32::misc-data-offset) 4))
+(defun write-double-float-vector
+  (stream vector &amp;key (start 0) (end (length vector)))
+  (check-type vector (vector double-float))
+  (let* ((start-octet (+ (* start 8)
+                         (- target::misc-dfloat-offset
+                         target::misc-data-offset)))
+         (num-octets (* 8 (- end start))))
+    (stream-write-ivector stream vector start-octet num-octets)))
+</programlisting>
+      </sect2>
+    </sect1>
+  </chapter>
+
+  <chapter id="Writing-Portable-Extensions-to-the-Object-System-using-the-MetaObject-Protocol">
+    <title>Writing Portable Extensions to the Object System  using the MetaObject Protocol</title>
+
+    <sect1 id="MOP-Overview">
+      <title>Overview</title>
+      <para>OpenMCL supports a fairly large subset of the
+      semi-standard MetaObject Protocol (MOP) for CLOS, as defined in
+      chapters 5 and 6 of "The Art Of The Metaobject Protocol",
+      (Kiczales et al, MIT Press 1991, ISBN 0-262-61074-4); this
+      specification is also available online at
+      http://www.alu.org/mop/index.html.</para>
+    </sect1>
+
+    <sect1 id="MOP-Implementation-status">
+      <title>Implementation status</title>
+      <para>The keyword :openmcl-partial-mop is on *FEATURES* to
+      indicate the presence of this functionality.</para>
+
+      <para>All of the symbols defined in the MOP specification
+      (whether implemented or not) are exported from the "CCL" package
+      and from an "OPENMCL-MOP" package.</para>
+      <para><informaltable><tgroup cols="2" colsep="1"
+      rowsep="1"><colspec align="center" colname="col0" /><colspec
+      align="center" colname="col1" /><thead><row><entry
+      align="center" valign="top"><para>construct</para></entry><entry
+      align="center"
+      valign="top"><para>status</para></entry></row></thead><tbody><row><entry
+      align="center"
+      valign="top"><para>accessor-method-slot-definition</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>add-dependent</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>add-direct-method</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>add-direct-subclass</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>add-method</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>class-default-initargs</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>class-direct-default-initargs</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>class-direct-slots</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>class-direct-subclasses</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>class-direct-superclasses</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>class-finalized-p</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>class-prototype</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>class-slots</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>compute-applicable-methods</para></entry><entry
+      align="center"
+      valign="top"><para>-</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>compute-applicable-methods-using-classes</para></entry><entry
+      align="center"
+      valign="top"><para>-</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>compute-class-precedence-list</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>compute-direct-initargs</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>compute-discriminating-function</para></entry><entry
+      align="center"
+      valign="top"><para>-</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>compute-effective-method</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>compute-effective-slot-definition</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>compute-slots</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>direct-slot-definition-class</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>effective-slot-definition-class</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>ensure-class</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>ensure-class-using-class</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>ensure-generic-function-using-class</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>eql-specializer-object</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>extract-lambda-list</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>extract-specializer-names</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>finalize-inheritance</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>find-method-combination</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>funcallable-standard-instance-access</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>generic-function-argument-precedence-order</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>generic-function-declarations</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>generic-function-lambda-list</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>generic-function-method-class</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>generic-function-method-combination</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>generic-function-methods</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>generic-function-name</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>intern-eql-specializer</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>make-method-lambda</para></entry><entry
+      align="center"
+      valign="top"><para>-</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>map-dependents</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>method-function</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>method-generic-function</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>method-lambda-list</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>method-qualifiers</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>method-specializers</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>reader-method-class</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>remove-dependent</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>remove-direct-method</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>remove-direct-subclass</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>remove-method</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>set-funcallable-instance-function</para></entry><entry
+      align="center"
+      valign="top"><para>-</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>slot-boundp-using-class</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>slot-definition-allocation</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>slot-definition-initargs</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>slot-definition-initform</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>slot-definition-initfunction</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>slot-definition-location</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>slot-definition-name</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>slot-definition-readers</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>slot-definition-type</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>slot-definition-writers</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>slot-makunbound-using-class</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>slot-value-using-class</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>specializer-direct-generic-functions</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>specializer-direct-methods</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>standard-instance-access</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>update-dependent</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>validate-superclass</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row><row><entry
+      align="center"
+      valign="top"><para>writer-method-class</para></entry><entry
+      align="center"
+      valign="top"><para>+</para></entry></row></tbody></tgroup></informaltable></para>
+      
+      <para>Note that those generic functions whose status is "-" in
+      the table above deal with the internals of generic function
+      dispatch and method invocation (the "Generic Function Invocation
+      Protocol".) Method functions are implemented a bit differently
+      in OpenMCL from what the MOP expects, and it's not yet clear if
+      or how this subprotocol can be well-supported.</para>
+      <para>Those constructs that are marked as "+" in the table above
+      are nominally implemented as the MOP document specifies
+      (deviations from the specification should be considered bugs;
+      please report them as such.) Note that some CLOS implementations
+      in widespread use (e.g., PCL) implement some things
+      (ENSURE-CLASS-USING-CLASS comes to mind) a bit differently from
+      what the MOP specifies.</para>
+    </sect1>
+
+    <sect1 id="Concurrency-issues">
+      <title>Concurrency issues</title>
+      <para>The entire CLOS class and generic function hierarchy is
+      effectively a (large, complicated) shared data structure; it's
+      not generally practical for a thread to request exclusive access
+      to all of CLOS, and the effects of volitional modification of
+      the CLOS hierarchy (via clas redefinition, CHANGE-CLASS, etc) in
+      a multithreaded environment aren't always tractable.</para>
+      <para>Native threads exacerbate this problem (in that they
+      increase the opportunities for concurrent modification and
+      access.) The implementation should try to ensure that a thread's
+      view of any subset of the CLOS hierarchy is consistent (to the
+      extent that that's possible) and should try to ensure that
+      incidental modifications of the hierarchy (cache updates, etc.)
+      happen atomically; it's not generally possible for the
+      implementation to guarantee that a thread's view of things is
+      correct and current.</para>
+      <para>If you are loading code and defining classes in the most
+      usual way, which is to say, via the compiler, using only a
+      single thread, these issues are probably not going to affect you
+      much.</para>
+      <para>If, however, you are making finicky changes to the class
+      hierarchy while you're running multiple threads which manipulate
+      objects related to each other, more care is required.  Before
+      doing such a thing, you should know what you're doing and
+      already be aware of what precautions to take, without being
+      told.  That said, if you do it, you should seriously consider
+      what your application's critical data is, and use locks for
+      critical code sections.</para>
+    </sect1>
+  </chapter>
+
+  <chapter id="The-Foreign-Function-Interface">
+    <title>The Foreign-Function Interface</title>
+
+    <sect1 id="Specifying-And-Using-Foreign-Types">
+      <title>Specifying And Using Foreign Types</title>
+
+      <sect2 id="Overview-foreign-types">
+	<title>Overview</title>
+        <para>OpenMCL provides a fairly rich language for defining and
+        specifying foreign data types (this language is derived from
+        CMUCL's "alien type" system.)</para>
+        <para>In practice, most foreign type definitions are
+        introduced into OpenMCL via its interface database (see ),
+        though it's also possible to define foreign types
+        interactively and/or programmatically.</para>
+        <para>OpenMCL's foreign type system is "evolving" (a polite
+        word for not-quite-complete): there are some inconsistencies
+        involving package usage, for instance. Symbols used in foreign
+        type specifiers <emphasis>should</emphasis> be keywords, but
+        this convention isn't always enforced.</para>
+        <para>Foreign type, record, and field names are
+        case-sensitive; OpenMCL uses some escaping conventions (see )
+        to allow keywords to be used to denote these names.</para>
+      </sect2>
+
+      <sect2 id="Syntax-of-Foreign-Type-Specifiers">
+        <title>Syntax of Foreign Type Specifiers</title>
+        <itemizedlist>
+          <listitem>
+	    <para>Some foreign types are builtin: keywords denote
+	    primitive,builtin types such as the IEEE-double-float type
+	    (denoted:DOUBLE-FLOAT), in much the same way as certain
+	    symbols(CONS, FIXNUM,etc.) define primitive CL
+	    types.</para>
+	  </listitem>
+          <listitem>
+	    <para>Constructors such as :SIGNED and :UNSIGNED can be
+	    used to denotesigned and unsigned integer subtypes
+	    (analogous to the CL typespecifiers SIGNED-BYTE and
+	    UNSIGNED-BYTE.) :SIGNED is shorthand for(:SIGNED 32) and
+	    :UNSIGNED is shorthand for (:UNSIGNED 32).</para>
+	  </listitem>
+          <listitem>
+	    <para>Aliases for other (perhaps more complicated) types
+	    can bedefined via CCL:DEF-FOREIGN-TYPE (sort of like
+	    CL:DEFTYPE or the Ctypedef facility). The type :CHAR is
+	    defined as an alias for (:SIGNED8) on some platforms, as
+	    (:UNSIGNED 8) on others.</para>
+	  </listitem>
+          <listitem>
+	    <para>The construct (:STRUCT <emphasis>name</emphasis>)
+	    can be used torefer to a named structure type; (:UNION
+	    <emphasis>name</emphasis>)can be used to refer to a named
+	    union type. It isn't necessary toenumerate a structure or
+	    union type's fields in order to refer tothe type.</para>
+	  </listitem>
+          <listitem>
+	    <para>If <emphasis>X</emphasis> is a valid foreign type
+	    reference,then (:* <emphasis>X</emphasis>) denotes the
+	    foreign type "pointerto<emphasis> X</emphasis>". By
+	    convention, (:* T) denotes ananonymous pointer type,
+	    vaguely equivalent to "void*" in C.</para>
+	  </listitem>
+          <listitem>
+	    <para>If a fieldlist is a list of lists, each of whose CAR
+	    is a foreign field name (keyword) and whose CADR is a
+	    foreign type specifier, then (:STRUCT
+	    <emphasis>name</emphasis> ,@fieldlist) is adefinition of
+	    the structure type <emphasis>name</emphasis>,
+	    and (:UNION<emphasis> name</emphasis> ,@fieldlist) is a
+	    definition of theunion type
+	    <emphasis>name</emphasis>. Note that it's necessary
+	    todefine a structure or union type in order to include
+	    that type in a structure, union, or array, but only
+	    necessary to "refer to" a strucure or union type in order
+	    to define a type alias or a pointer type.</para>
+	  </listitem>
+	  <listitem>
+	    <para>If <emphasis>X</emphasis> is a defined foreign type
+	    , then (:array <emphasis>X</emphasis> &amp;rest dims)
+	    denotes the foreigntype "array of
+	    <emphasis>X</emphasis>". Although multiplearray dimensions
+	    are allowed by the :array constructor,
+	    only single-dimensioned arrays are (at all) well-supported
+	    in OpenMCL.</para>
+	  </listitem>
+        </itemizedlist>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Foreign-Function-Calls">
+      <title>Foreign Function Calls</title>
+
+      <sect2 id="Overview-foreign-calls">
+	<title>Overview</title>
+        <para>OpenMCL provides a number of constructs for calling
+        foreign functions from Lisp code (all of them based on the
+        function CCL:%FF-CALL).  In many cases, OpenMCL's interface
+        translator (see ) provides information about the foreign
+        function's entrypoint name and argument and return types; this
+        enables the use of the #_ reader macro (described below),
+        which may be more concise and/or more readable than other
+        constructs.</para>
+        <para>OpenMCL also provides a mechanism for defining
+        <emphasis>callbacks</emphasis>: lisp functions which can be
+        called from foreign code.</para>
+        <para>There's no supported way to directly pass lisp data to
+        foreign functions: scalar lisp data must be coerced to an
+        equivalent foreign representatation, and lisp arrays (notably
+        strings) must be copied to non-GCed memory.</para>
+
+        <sect3 id="Type-Designators-for-Arguments-and-Return-Values">
+	  <title>Type Designators for Arguments and Return Values</title>
+          <para>The types of foreign argument and return values in foreign
+	  function calls and callbacks can be specified by any of the following
+keywords:</para>
+	  <variablelist>
+	    <varlistentry>
+	      <term>:UNSIGNED-BYTE</term>
+
+	      <listitem>
+		<para>The argument/return value is of type (UNSIGNED-BYTE 8)</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
+	      <term>:SIGNED-BYTE</term>
+
+	      <listitem>
+		<para>The argument/return value is of type (SIGNED-BYTE 8)</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
+	      <term>:UNSIGNED-HALFWORD</term>
+
+	      <listitem>
+		<para>The argument/return value is of type (UNSIGNED-BYTE 16)</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
+	      <term>:SIGNED-HALFWORD</term>
+
+	      <listitem>
+		<para>The argument/return value is of type (SIGNED-BYTE 16)</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
+	      <term>:UNSIGNED-FULLWORD</term>
+
+	      <listitem>
+		<para>The argument/return value is of type (UNSIGNED-BYTE 32)</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
+	      <term>:SIGNED-FULLWORD</term>
+
+	      <listitem>
+		<para>The argument/return value is of type (SIGNED-BYTE 32)</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
+	      <term>:UNSIGNED-DOUBLEWORD</term>
+
+	      <listitem>
+		<para>The argument/return value is of type (UNSIGNED-BYTE 64)</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
+	      <term>:SIGNED-DOUBLEWORD</term>
+
+	      <listitem>
+		<para>The argument/return value is of type (SIGNED-BYTE 64)</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
+	      <term>:SINGLE-FLOAT</term>
+
+	      <listitem>
+		<para>The argument/return value is of type SINGLE-FLOAT</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
+	      <term>:DOUBLE-FLOAT</term>
+
+	      <listitem>
+		<para>The argument/return value is of type DOUBLE-FLOAT</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
+	      <term>:ADDRESS</term>
+
+	      <listitem>
+		<para>The argument/return values
+		is <link linkend="arb24">a MACPTR</link>.</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
+	      <term>:VOID</term>
+
+	      <listitem>
+		<para>or NIL Not valid as an argument type specifier; specifies
+		that there is no meaningful return value</para>
+	      </listitem>
+	    </varlistentry>
+	  </variablelist>
+
+          <para>On some platforms, a small positive integer
+          <emphasis>N</emphasis> can also be used as an argument
+          specifier; it indicates that the corresponding argument is a
+          pointer to an <emphasis>N</emphasis>-word structure or union
+          which should be passed by value to the foreign
+          function.  Exactly which foreign structures are passed
+	  by value and how is very dependent on the Application
+	  Binary Interface (ABI) of the platform; unless you're
+	  very familar with ABI detatils (some of which are quite
+	  baroque), it's often easier to let higher-level constructs
+	  deal with these details.</para>
+        </sect3>
+
+        <sect3 id="External-Entrypoints-and-Named-External-Entrypoints">
+	  <title>External Entrypoints and Named External Entrypoints</title>
+          <para>PowerPC machine instructions are always aligned on
+          32-bit boundaries, so the two least significant bits of the
+          first instruction ("entrypoint") of a foreign function are
+          always 0. OpenMCL often represents an entrypoint address as
+          a fixnum that's binary-equivalent to the entrypoint address:
+          if<emphasis> E</emphasis> is an entrypoint address expressed
+          as a signed 32-bit integer, then (ash <emphasis>E</emphasis>
+          -2) is an equivalent fixnum representation of that
+          address. An entrypoint address can also be encapsulated in a
+          MACPTR (see FIXTHIS), but that's somewhat less efficient.</para>
+          <para>Although it's possible to use fixnums or macptrs to
+          represent entrypoint addresses, it's somewhat cumbersome to
+          do so. OpenMCL can cache the addresses of named external
+          functions in structure-like objects of type
+          CCL:EXTERNAL-ENTRY-POINT (sometimes abbreviated as EEP).
+          Through the use of LOAD-TIME-VALUE, compiled lisp functions
+          are able to reference EEPs as constants; the use of an
+          indirection allows OpenMCL runtime system to ensure that the
+          EEP's address is current and correct.</para>
+        </sect3>
+      </sect2>
+
+      <sect2 id="Return-Conventions-for-C-Structures">
+	<title>Return Conventions for C Structures</title>
+        <para> On some platforms, C functions that are defined to
+        return structures do so by reference: they actually
+        accept a first parameter of type "pointer to returned
+        struct/union" - which must be allocated by the caller - and
+        don't return a meaningful value.</para>
+	<para><emphasis>Exactly</emphasis> how a C function that's
+	defined to return a foreign structure does so is dependent on
+	the ABI (and on the size ad composition of the structure/union
+	in many cases.)</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Referencing-and-Using-Foreign-Memory-Addresses">
+      <title>Referencing and Using Foreign Memory Addresses</title>
+
+      <sect2 id="Overview-memory-addresses">
+        <title>Overview</title>
+
+        <sect3 id="Basics">
+	  <title>Basics</title>
+          <para>For a variety of technical reasons, it isn't generally
+          possible to directly reference arbitrary absolute addresses
+          (such as those returned by the C library function malloc(),
+          for instance) in OpenMCL. In OpenMCL (and in MCL), such
+          addresses need to be <emphasis>encapsulated</emphasis> in
+          objects of type CCL:MACPTR; one can think of a MACPTR as
+          being a specialized type of structure whose sole purpose is
+          to provide a way of referring to an underlying "raw"
+          address.</para>
+          <para>It's sometimes convenient to blur the distinction
+          between a MACPTR and the address it represents; it's
+          sometimes necessary to maintain that distiction. It's
+          important to remember that a MACPTR is (generally) a
+          first-class Lisp object in the same sense that a CONS cell
+          is: it'll get GCed when it's no longer possible to reference
+          it. The "lifetime" of a MACPTR doesn't generally have
+          anything to do with the lifetime of the block of memory its
+          address points to.</para>
+          <para>It might be tempting to ask "How does one obtain the
+          address encapsulated by a MACPTR ?". The answer to that
+          question is that one doesn't do that (and there's no way to
+          do that): addresses aren't first-class objects, and there's
+          no way to refer to one.</para>
+          <para>Two MACPTRs that encapsulate the same address are EQL
+          to each other.</para>
+          <para>There are a small number of ways to directly create a
+          MACPTR (and there's a fair amount of syntactic sugar built
+          on top of of those primitives.) These primitives will be
+          discussed in greater detail below, but they include:</para>
+
+	  <itemizedlist>
+            <listitem>
+	    <para>Creating a MACPTR with a specified address, usually
+	    via thefunction CCL:%INT-TO-PTR.</para>
+	    </listitem>
+            <listitem>
+	      <para>Referencing the return valueof a foreign function
+	      call (see )that's specified to return an address.</para>
+	    </listitem>
+            <listitem>
+	      <para>Referencing a memory location that's specified to
+	      contain an address.</para>
+	    </listitem>
+	  </itemizedlist>
+
+          <para>All of these primitive MACPTR-creating operations are
+          usually open-coded by the compiler; it has a fairly good
+          notion of what low-level operations "produce" MACPTRs and
+          which operations "consume" the addresses that the
+          encapsulate, and will usually optimize out the introduction
+          of intermediate MACPTRs in a simple expression.</para>
+          <para>One consequence of the use of MACPTR objects to
+          encapsulate foreign addresses is that (naively)
+          <emphasis>every reference to a foreign address causes a
+          MACPTR to be allocated.</emphasis></para>
+          <para>Consider a code fragment like the following:</para>
+          <programlisting>
+(defun get-next-event ()
+  "get the next event from a hypothetical window system"
+  (loop
+    (let* ((event (#_get_next_window_system_event))) ; via an FF-CALL
+          (unless (null-event-p event)
+            (handle-event event)))))
+</programlisting>
+          <para>As this is written, each call to the (hypothetical)
+          foreign function #_get_next_window_system_event will return
+          a new MACPTR object.  Ignoring for the sake of argument the
+          question of whether this code fragment exhibits a good way
+          to poll for external events (it doesn't), it's not hard to
+          imagine that this loop could execute several millon times
+          per second (producing several million MACPTRs per second.)
+          Clearly, the "naive" approach is impractical in many
+          cases.</para>
+        </sect3>
+
+        <sect3 id="Stack-allocation-of---and-destructive-operations-on---MACPTRs-">
+          <title>Stack allocation of - and destructive operations on - MACPTRs.</title>
+	  <para>If certain conditions held in the environment in which
+	  GET-NEXT-EVENT ran - namely, if it was guaranteed that
+	  neither NULL-EVENT-P nor HANDLE-EVENT cached or otherwise
+	  retained their arguments (the "event" pointer) - there'd be
+	  a few alternatives to the naive approach. One of those
+	  approaches would be to use the primitive function
+	  %SETF-MACPTR (described in greater detail below) to
+	  destructively modify a MACPTR (to change the value of the
+	  address it encapsulates.) The GET-NEXT-EVENT example could
+	  be re-written as:</para>
+          <programlisting>
+(defun get-next-event ()
+  (let* ((event (%int-to-ptr 0))) ; create a MACPTR with address 0
+    (loop
+      (%setf-macptr event (#_get_next_window_system_event)) ; re-use it
+      (unless (null-event-p event)
+        (handle-event event)))))
+</programlisting>
+          <para>That version's a bit more realistic: it allocates a
+          single MACPTR outside if the loop, then changes its address
+          to point to the current address of the hypothetical event
+          structure on each loop iteration. If there are a million
+          loop iterations per call to GET-NEXT-EVENT, we're allocating
+          a million times fewer MACPTRs per call; that sounds like a
+          Good Thing.</para>
+          <para>An Even Better Thing would be to advise the compiler
+          that the initial value (the null MACPTR) bound to the
+          variable event has dynamic extent (that value won't be
+          referenced once control leaves the extent of the binding of
+          that variable.) Common Lisp allows us to make such an
+          assertion via a DYNAMIC-EXTENT declaration; OpenMCL's
+          compiler can recognize the "primitive MACPTR-creating
+          operation" involved and can replace it with an equivalent
+          operation that stack-allocates the MACPTR object. If we're
+          not worried about the cost of allocating that MACPTR on
+          every iteration (the cost is small and there's no hidden GC
+          cost), we could move the binding back inside the
+          loop:</para>
+          <programlisting>
+(defun get-next-event ()
+  (loop
+    (let* ((event (%null-ptr))) ; (%NULL-PTR) is shorthand for (%INT-TO-PTR 0)
+      (declare (dynamic-extent event))
+      (%setf-macptr event (#_get_next_window_system_event))
+      (unless (null-event-p event)
+        (handle-event event)))))
+</programlisting>
+          <para>The idiom of binding one or more variables to
+          stack-allocated MACPTRs, then destructively modifying those
+          MACPTRs before executing a body of code is common enough
+          that OpenMCL provides a macro (WITH-MACPTRS) that handles
+          all of the gory details. The following version of
+          GET-NEXT-EVENT is semantically equivalent to the previous
+          version, but hopefully a bit more concise:</para>
+          <programlisting>
+(defun get-next-event ()
+  (loop
+    (with-macptrs ((event (#_get_next_window_system_event)))
+      (unless (null-event-p event)
+        (handle-event event)))))
+</programlisting>
+        </sect3>
+
+        <sect3 id="Stack-allocated-memory--and-stack-allocated-pointers-to-it--">
+          <title>Stack-allocated memory (and stack-allocated pointers to it.)</title>
+	  <para>Fairly often, the blocks of foreign memory (obtained
+	  by malloc or something similar) have well-defined lifetimes
+	  (they can safely be freed at some point when it's known that
+	  they're no longer needed and it's known that they're no
+	  longer referenced.) A common idiom might be:</para>
+          <programlisting>
+(with-macptrs (p (#_allocate_foreign_memory size))
+  (unwind-protect
+    (use-foreign-memory p)
+    (#_deallocate_foreign_memory p)))
+</programlisting>
+          <para>That's not unreasonable code, but it's fairly
+          expensive for a number of reasons: foreign functions calls
+          are themselves fairly expensive (as is UNWIND-PROTECT), and
+          most library routines for allocating and deallocating
+          foreign memory (things like malloc and free) can be fairly
+          expensive in their own right.</para>
+          <para>In the idiomatic code above, both the MACPTR P and the
+          block of memory that's being allocated and freed have
+          dynamic extent and are therefore good candidates for stack
+          allocation. OpenMCL provides the %STACK-BLOCK macro, which
+          executes a body of code with one or more variables bound to
+          stack-allocated MACPTRs which encapsulate the addresses of
+          stack-allocated blocks of foreign memory. Using
+          %STACK-BLOCK, the idiomatic code is:</para>
+          <programlisting>
+(%stack-block ((p size))
+  (use-foreign-memory p))
+</programlisting>
+          <para>which is a bit more efficient and a bit more concise
+          than the version presented earlier.</para>
+          <para>%STACK-BLOCK is used as the basis for slightly
+          higher-level things like RLET. (See FIXTHIS for more information
+          about RLET.)</para>
+        </sect3>
+
+        <sect3 id="Caveats-">
+	  <title>Caveats.</title>
+          <para>Reading from, writing to, allocating, and freeing
+          foreign memory are all potentially dangerous operations;
+          this is no less true when these operations are performed in
+          OpenMCL than when they're done in C or some other
+          lower-level language. In addition, destructive operations on
+          Lisp objects be dangerous, as can stack allocation if it's
+          abused (if DYNAMIC-EXTENT declarations are violated.)
+          Correct use of the constructs and primitives described here
+          is reliable and safe; slightly incorrect use of these
+          constructs and primitives can crash OpenMCL.</para>
+        </sect3>
+      </sect2>
+
+      <sect2 id="Foreign-Memory-Addresses-Dictionary">
+	<title>Foreign-Memory-Addresses Dictionary</title>
+        <para>Unless otherwise noted, all of the symbols mentioned
+        below are exported from the CCL package.</para>
+
+        <sect3 id="Scalar-memory-reference">
+          <title>Scalar memory reference</title>
+	  <variablelist>
+	    <varlistentry>
+	      <term>Syntax</term>
+
+	      <listitem>
+		<para>%get-signed-byte ptr &#38;optional (offset 0)</para>
+
+		<para>%get-unsigned-byte ptr &#38;optional (offset 0)</para>
+
+		<para>%get-signed-word ptr &#38;optional (offset 0)</para>
+
+		<para>%get-unsigned-word ptr &#38;optional (offset 0)</para>
+
+		<para>%get-signed-long ptr &#38;optional (offset 0)</para>
+
+		<para>%get-unsigned-long ptr &#38;optional (offset 0)</para>
+
+		<para>%%get-signed-longlong ptr &#38;optional (offset 0)</para>
+
+		<para>%%get-unsigned-longlong ptr &#38;optional (offset 0)</para>
+
+		<para>%get-ptr ptr &#38;optional (offset 0)</para>
+
+		<para>%get-single-float ptr &#38;optional (offset 0)</para>
+
+		<para>%get-double-float ptr &#38;optional (offset 0)</para>
+	      </listitem>
+	    </varlistentry>
+	    <varlistentry>
+	      <term>Description</term>
+
+	      <listitem>
+		<para>References and returns the signed or unsigned 8-bit byte,
+		signed or unsigned 16-bit word, signed or unsigned 32-bit long
+		word, signed or unsigned 64-bit long long word, 32-bit address,
+		32-bit single-float, or 64-bit double-float at the effective byte
+		address formed by adding offset to the address encapsulated by
+		ptr.</para>
+	      </listitem>
+	    </varlistentry>
+
+	    <varlistentry>
+	      <term>Arguments</term>
+
+	      <listitem>
+
+		<variablelist>
+		  <varlistentry>
+		    <term>ptr</term>
+
+		    <listitem>
+		      <para>A MACPTR</para>
+		    </listitem>
+		  </varlistentry>
+
+		  <varlistentry>
+		    <term>offset</term>
+
+		    <listitem>
+		      <para>A fixnum</para>
+		    </listitem>
+		  </varlistentry>
+		</variablelist>
+	      </listitem>
+	    </varlistentry>
+	  </variablelist>
+
+          <para>All of the memory reference primitives described above can be</para>
+          <para>used with SETF.</para>
+        </sect3>
+
+        <sect3 id="iget-bit--Function-">
+          <para>%get-bit [Function]</para>
+          <term><indexterm>Syntax
+              <variablelist>%get-bit ptr bit-offset</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>References and returns the bit-offsetth bit at the addressencapsulated by ptr. (Bit 0 at a given address is the mostsignificant bit of the byte at that address.) Can be used withSETF.</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist> 
+                <term><indexterm>ptr
+                    <variablelist>A MACPTR</variablelist>
+                  </indexterm><indexterm>bit-offset
+                    <variablelist>A fixnum</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="iget-bitfield--Function-">
+          <para>%get-bitfield [Function]</para>
+          <term><indexterm>Syntax
+              <variablelist>%get-bitfield ptr bit-offset width</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>References and returns an unsigned integer composed from thewidth bits found bit-offsetbits from the address encapsulated byptr. (The least significant bit of the result is the value of(%get-bit ptr (1- (+ bit-offset width)))). Can be used with SETF.</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist> </variablelist>
+            </indexterm><indexterm>ptr
+              <variablelist>A MACPTR
+                <term><indexterm>bit-offset
+                    <variablelist>A fixnum</variablelist>
+                  </indexterm><indexterm>width
+                    <variablelist>A positive fixnum</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="iint-to-ptr--Function-">
+          <para>%int-to-ptr [Function]</para>
+          <term><indexterm>Syntax
+              <variablelist>%int-to-ptr int</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Creates and returns a MACPTR whose address matches int.</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist> 
+                <term><indexterm>int
+                    <variablelist>An (unsigned-byte 32)</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="iinc-ptr--Function-">
+          <para>%inc-ptr [Function]</para>
+          <term><indexterm>Syntax
+              <variablelist>%inc-ptr ptr &amp;optional (delta 1)</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Creates and returns a MACPTR whose address is the address ofptr plus delta. The idiom (%inc-ptr ptr 0) is sometimes used tocopy a MACPTR, e.g., to create a new MACPTR encapsulating the sameaddress as ptr.</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist> 
+                <term><indexterm>ptr
+                    <variablelist>A MACPTR</variablelist>
+                  </indexterm><indexterm>delta
+                    <variablelist>A fixnum</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="iptr-to-int--Function-">
+          <para>%ptr-to-int [Function]</para>
+          <term><indexterm>Syntax
+              <variablelist>%ptr-to-int ptr</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Returns the address encapsulated by ptr, as an(unsigned-byte 32).</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist> 
+                <term><indexterm>ptr
+                    <variablelist>A MACPTR</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="inull-ptr--Macro-">
+          <para>%null-ptr [Macro]</para>
+          <term><indexterm>Syntax
+              <variablelist>%null-ptr</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Equivalent to (%ptr-to-int 0).</variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="inull-ptr-p--Function-">
+          <para>%null-ptr-p [Function]</para>
+          <term><indexterm>Syntax
+              <variablelist>%null-ptr-p ptr</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Returns T If ptr is a MACPTR encapsulating the address 0,NIL if ptr encapsulates some other address.</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist> 
+                <term><indexterm>ptr
+                    <variablelist>A MACPTR</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="isetf-macptr--Function-">
+          <para>%setf-macptr [Function]</para>
+          <term><indexterm>Syntax
+              <variablelist>%setf-macptr dest-ptr src-ptr</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Causes dest-ptr to encapsulate the same address that src-ptrdoes, then returns dest-ptr.</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist> 
+                <term><indexterm>dest-ptr
+                    <variablelist>A MACPTR</variablelist>
+                  </indexterm><indexterm>src-ptr
+                    <variablelist>A MACPTR</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="iincf-ptr--Macro-">
+          <para>%incf-ptr [Macro]</para>
+          <term><indexterm>Syntax
+              <variablelist>%incf-ptr ptr &amp;optional (delta 1)</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Destructively modifies ptr, by adding delta to the addressit encapsulates. Returns ptr.</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist> 
+                <term><indexterm>ptr
+                    <variablelist>A MACPTR</variablelist>
+                  </indexterm><indexterm>delta
+                    <variablelist>A fixnum</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="with-macptrs--Macro-">
+          <para>with-macptrs [Macro]</para>
+          <term><indexterm>Syntax
+              <variablelist>with-macptrs (var expr)* &amp;body body</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Executes body in an environment in which each var is boundto a stack-allocated macptr which encapsulates the foreign addressyielded by the corresponding expr. Returns whatever value(s) bodyreturns.</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist> 
+                <term><indexterm>var
+                    <variablelist>A symbol (variable name)</variablelist>
+                  </indexterm><indexterm>expr
+                    <variablelist>A MACPTR-valued expression</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="istack-block--Macro-">
+          <para>%stack-block [Macro]</para>
+          <term><indexterm>Syntax
+              <variablelist>%stack-block (var expr)* &amp;body body</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Executes body in an environment in which each var is boundto a stack-allocated macptr which encapsulates the address of astack-allocated region of size expr bytes. Returns whatevervalue(s) body returns.</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist> 
+                <term><indexterm>var
+                    <variablelist>A symbol (variable name)</variablelist>
+                  </indexterm><indexterm>expr
+                    <variablelist>An expression which should evaluate to a non-negativefixnum</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="make-cstring--Function-">
+          <para>make-cstring [Function]</para>
+          <term><indexterm>Syntax
+              <variablelist>make-cstring string</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Allocates a block of memory (via malloc) of length (1+(length string)). Copies the string to this block and appends atrailing NUL byte; returns a MACPTR to the block.</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist> 
+                <term><indexterm>string
+                    <variablelist>A lisp string</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="with-cstrs--Macro-">
+          <para>with-cstrs [Macro]</para>
+          <term><indexterm>Syntax
+              <variablelist>with-cstrs (var string)* &amp;body body</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Executes body in an environment in which each var is boundto a stack-allocated macptr which encapsulates the %address of astack-allocated region of into which each string (and a trailingNUL byte) has been copied. Returns whatever value(s) body returns.</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist> 
+                <term><indexterm>var
+                    <variablelist>A symbol (variable name)</variablelist>
+                  </indexterm><indexterm>string
+                    <variablelist>An expression which should evaluate to a lisp string</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="iget-cstring--Function-">
+          <para>%get-cstring [Function]</para>
+          <term><indexterm>Syntax
+              <variablelist>%get-cstring ptr</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Interprets ptr as a pointer to a (NUL -terminated) C string;returns an equivalent lisp string.</variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist>
+                <term><indexterm>ptr
+                    <variablelist>A MACPTR</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+
+        <sect3 id="istr-from-ptr--Function-">
+          <para>%str-from-ptr [Function]</para>
+          <term><indexterm>Syntax
+              <variablelist>%str-from-ptr ptr length</variablelist>
+            </indexterm><indexterm>Description
+              <variablelist>Returns a lisp string of length <literal>length</literal>,whose contents are initialized from the bytes at<literal> ptr.</literal></variablelist>
+            </indexterm><indexterm>Arguments
+              <variablelist>
+                <term><indexterm>ptr
+                    <variablelist>AMACPTR</variablelist>
+                  </indexterm><indexterm>length
+                    <variablelist>anon-negative fixnum</variablelist>
+                  </indexterm>
+                </term></variablelist>
+            </indexterm>
+          </term>
+        </sect3>
+      </sect2>
+    </sect1>
+
+    <sect1 id="The-Interface-Database">
+      <title>The Interface Database</title>
+
+      <sect2 id="interface-database-Overview">
+	<title>Overview</title>
+        <para>OpenMCL uses a set of database files which contain
+        foreign type, record, constant, and function definitions
+        derived from the operating system's header files, be that
+        Linux or Darwin.  An archive containing these database files
+        (and the shell scripts which were used in their creation) is
+        available; see the Distributions page for information about
+        obtaining current interface database files.</para>
+        <para>Not surprisingly, different platforms use different database files.</para>
+        <para>OpenMCL defines reader macros that consult these databases:</para>
+        <listitem mark="bullet">
+          <variablelist>#$foo looks up the value of the constant definition of FIXTHIS</variablelist>
+          <variablelist>#_foo looks up the foreign function definition for FIXTHIS</variablelist>
+        
+        </listitem>
+        <para>In both cases, the symbol foo is interned in the "OS"
+        package. The #$ reader macro has the side-effect of defining
+        foo as a constant (as if via DEFCONSTANT); the #_ reader macro
+        has the side effect of defining foo as a macro which will
+        expand into an (EXTERNAL-CALL form.)</para>
+        <para>It's important to remember that the side-effect happens
+        when the form containing the reader macro is
+        read. Macroexpansion functions that expand into forms which
+        contain instances of those reader macros don't do what one
+        might think that they do, unless the macros are expanded in
+        the same lisp session as the reader macro was read in.</para>
+        <para>In addition, references to foreign type,
+        structure/union, and field names (when used in the RREF/PREF
+        and RLET macros) will cause these database files to be
+        consulted.</para>
+        <para>Since the OpenMCL sources contain instances of these
+        reader macros (and references to foreign record types and
+        fields), compiling OpenMCL from those sources depends on the
+        ability to find and use (see <xref
+        linkend="Building-the-heap-image"/>).</para>
+      </sect2>
+
+      <sect2 id="Other-issues">
+        <title>Other issues:</title>
+        <itemizedlist>
+          <listitem>
+	    <para>OpenMCL now preserves the case of external symbols
+	    in itsdatabase files. See for information about case in
+	    foreign symbol names.</para>
+	  </listitem>
+	  <listitem>
+	    <para>The Linux databases are derived from a somewhat
+	    arbitrary set of Linux header files. Linux is enough of a
+	    moving target that it may be difficult to define a standard,
+	    reference set of interfaces from which to derive a standard,
+	    reference set of database files.This seems to be less of
+	    an issue with Darwin and FreeBSD.</para>
+	  </listitem>
+	</itemizedlist>
+        <para>For information about building the database files,
+	see <xref linkend="The-Interface-Translator"/>.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Using-Interface-Directories">
+      <title>Using Interface Directories</title>
+
+      <sect2 id="Interface-Directory-Overview">
+	<title>Overview</title>
+        <para>As distributed, the "ccl:headers;" (for LinuxPPC)
+        directory is organized like:</para>
+        <programlisting>
+headers/
+headers/gl/
+headers/gl/C/
+headers/gl/C/populate.sh
+headers/gl/constants.cdb
+headers/gl/functions.cdb
+headers/gl/records.cdb
+headers/gl/objc-classes.cdb
+headers/gl/objc-methods.cdb
+headers/gl/types.cdb
+headers/gnome/
+headers/gnome/C/
+headers/gnome/C/populate.sh
+headers/gnome/constants.cdb
+headers/gnome/functions.cb
+headers/gnome/records.cdb
+headers/gnome/objc-classes.cdb
+headers/gnome/objc-methods.cdb
+headers/gnome/types.cdb
+headers/gtk/
+headers/gtk/C/
+headers/gtk/C/populate.sh
+headers/gtk/constants.cdb
+headers/gtk/functions.cdb
+headers/gtk/records.cdb
+headers/gtk/objc-classes.cdb
+headers/gtk/objc-methods.cdb
+headers/gtk/types.cdb
+headers/libc/
+headers/libc/C/
+headers/libc/C/populate.sh
+headers/libc/constants.cdb
+headers/libc/functions.cdb
+headers/libc/records.cdb
+headers/libc/objc-classes.cdb
+headers/libc/objc-methods.cdb
+headers/libc/types.cdb
+</programlisting>
+        <para>e.g, as a set of parallel subdirectories, each with a
+        lowercase name and each of which contains a set of 6 database
+        files and a "C" subdirectory which contains a shell script
+        used in the database creation process.</para>
+        <para>As one might assume, the database files in each of these
+        subdirectories contain foreign type, constant, and function
+        definitions - as well as ObjC class and method info -that
+        correspond (roughly) to the information contained in the
+        header files associated with a "-dev" package in a Linux
+        distribution.  "libc" corresponds pretty closely to the
+        interfaces associated with "glibc/libc6" header files, "gl"
+        corresponds to an "openGL+GLUT" developmnent package, "gtk"
+        and "gnome" contain interface information from the GTK+1.2 and
+        GNOME libraries, respectively.</para>
+        <para>For Darwin, the "ccl:darwin-headers" directory contains
+        a "libc" subdirectory, whose contents roughly correspond to
+        those of "/usr/include" under Darwin, as well as
+        subdirectories corresponding to the MacOSX Carbon and Cocoa
+        frameworks.</para>
+        <para>To see the precise set of .h files used to generate the
+        database files in a given interface directory, consult the
+        corresponding "populate.sh" shell script (in the interface
+        directory's "C" subdirectory.)</para>
+        <para>The intent is that this initial set can be augmented to
+        meet local needs, and that this can be done in a fairly
+        incremental fashion: one needn't have unrelated header files
+        installed in order to generate interface databases for a
+        package of interest.</para>
+        <para>Hopefully, this scheme will also make it easier to
+        distribute patches and bug fixes.</para>
+        <para>OpenMCL maintains a list of directories; when looking
+        for a foreign type, constant, function, or record definition,
+        it'll consult the database files in each directory on that
+        list. Initially, the list contains an entry for the "libc"
+        interface directory. OpenMCL needs to be explicitly told to
+        look in other interface directories should it need to do
+        so.</para>
+      </sect2>
+
+      <sect2 id="Creating-new-interface-directories">
+	<title>Creating new interface directories</title>
+        <para>This example refers to "ccl:headers;", which is
+        appropriate for LinuxPPC. The procedure's analogous under
+        Darwin, where the "ccl:darwin-headers;" directory would be
+        used instead.</para>
+        <para>To create a new interface directory, "foo", and a set of
+        database files in that directory:</para>
+        <varlistentry numeration="arabic">
+          <variablelist>Create a subdirectory of "ccl:headers;" named"foo".</variablelist>
+          <variablelist>Create a subdirectory of "ccl:headers;foo;" named"C".</variablelist>
+          <variablelist>Create a file in "ccl:headers;foo;C;" named"populate.sh".One way of accomplishing the above steps is:
+            <programlisting>
+? (close (open "ccl:headers;foo;C;populate.sh" :direction :output :
+               if-does-not-exist :create :if-exists :overwrite))
+</programlisting></variablelist>
+          <variablelist>Edit the file created above, using the "populate.sh"files in the distribution as guidelines.The file might wind up looking something like:
+            <programlisting>
+#/bin/sh
+h-to-ffi.sh `foo-config -cflags` /usr/include/foo/foo.h
+</programlisting></variablelist>
+        </varlistentry>
+        <para>Refer to 
+for information about running the
+interface translator and .ffi parser.</para>
+        <para>Assuming that all went well, there should now be .cdb files in
+"ccl:headers;foo;". You can then do
+<code>(use-interface-dir :foo)</code> whenever you need to
+access the foreign type information in those database files.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Using-Shared-Libraries">
+      <para>Using Shared Libraries</para>
+
+      <sect2 id="Overview--13-">
+        <para>Overview
+OpenMCL provides facilities to open and close shared libraries.</para>
+        <para>"Opening" a shared library, which is done with
+, maps the library's
+code and
+data into OpenMCL's address space and makes its exported symbols
+accessible to OpenMCL.</para>
+        <para>"Closing" a shared library, which is done with
+, unmaps the
+library's code and
+data and removes the library's symbols from the global namespace.</para>
+        <para>A small number of shared libraries (including libc, libm, libdl
+under Linux, and the "system" library under Darwin) are opened by
+the lisp kernel and can't be closed.</para>
+        <para>OpenMCL uses data structures of type EXTERNAL-ENTRY-POINT to map a
+foreign function name (string) to that foreign function's
+<emphasis>current<</emphasis> address. (A function's address may
+vary from session to session as different versions of shared libraries may
+load at different addresses; it may vary within a session for similar
+reasons.)</para>
+        <para>An EXTERNAL-ENTRY-POINT whose address is known is said to be
+<emphasis>resolved</emphasis>. When an external entry point is resolved,
+the shared library which defines that entry point is noted; when a shared
+library is closed, the entry points that it defines are made unresolved.
+An EXTERNAL-ENTRY-POINT must be in the resolved state in order to be
+FF-CALLed; calling an unresolved entry point causes a "last
+chance" attempt to resolve it. Attempting to resolve an entrypoint
+that was defined in a closed library will cause an attempt to reopen that
+library.</para>
+        <para>OpenMCL keeps track of all libraries that have been opened in a lisp
+session. When a saved application is first started, an attempt is made to
+reopen all libraries that were open when the image was saved, and an
+attempt is made to resolve all entrypoints that had been referenced when
+the image was saved. Either of these attempts can fail "quietly",
+leaving some entry points in an unresolved state.</para>
+        <para>Linux shared libraries can be referred to either by a string which
+describes their full pathname or by their <emphasis>soname</emphasis>, a
+shorter string that can be defined when the library is created. The
+dynamic linker mechanisms used in Linux make it possible (through a series
+of filesystem links and other means) to refer to a library via several
+names; the library's soname is often the most appropriate identifier.</para>
+        <para>sonames are often less version-specific than other names for
+libraries; a program that refers to a library by the name
+"libc.so.6" is more portable than one which refers to
+"libc-2.1.3.so" or to "libc-2.2.3.so", even though the
+latter two names might each be platform-specific aliases of the first.</para>
+        <para>All of the global symbols described below are exported from the CCL
+package.</para>
+      </sect2>
+
+      <sect2 id="Limitations-and-known-bugs--1-">
+        <para>Limitations and known bugs</para>
+        <listitem mark="bullet">
+          <variablelist>Don't get me started.</variablelist>
+          <variablelist>The underlying functionality has a poor notion of dependency;it's not always possible to open libraries that depend on unopenedlibraries, but it's possible to close libraries on which otherlibraries depend.It <emphasis>may</emphasis> be possible to generate moreexplicit dependency information by parsing the output of the Linux lddand ldconfig programs.</variablelist>
+        
+        </listitem>
+      </sect2>
+
+      <sect2 id="Darwin-Notes">
+        <para>Darwin Notes
+Darwin shared libraries come in two (basic) flavors:</para>
+        <listitem mark="bullet">
+          <variablelist>"dylibs" (which often have the extension".dylib") are primarily intended to be linked against atcompile/link time. They can be loaded dynamically,<emphasis>but can't be unloaded</emphasis>. Accordingly,OPEN-SHARED-LIBRARY can be used to open a .dylib-style library;calling CLOSE-SHARED-LIBRARY on the result of such a callproduces a warning, and has no other effect.It appears that (due to an OS bug) attempts to open .dylibshared-libraries that are already open can cause memory corruptionunless the full pathname of the .dylib file is specified on thefirst and all subsequent calls.</variablelist>
+          <variablelist>"bundles" are intended to serve as applicationextensions; they can be opened multiple times (creating multipleinstances of the library!) and closed properly.</variablelist>
+        
+        </listitem>
+        <para>Thanks to Michael Klingbeil for getting both kinds of Darwin shared
+libraries working in OpenMCL.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="The-Interface-Translator">
+      <para>The Interface Translator</para>
+
+      <sect2 id="Overview--14-">
+        <para>Overview
+OpenMCL uses an interface translation system based on the FFIGEN
+system, which is described at
+http://www.ccs.neu.edu/home/lth/ffigen/.
+The interface translator makes
+the constant, type, structure, and function definitions in a set of
+C-language header files available to lisp code.</para>
+        <para>The basic idea of the FFIGEN scheme is to use the C compiler's
+frontend and parser to translate .h files into semantically equivalent
+.ffi files, which represent the definitions from the headers using a
+syntax based on S-expressions.
+Lisp code can then concentrate on
+the .ffi representation, without having to concern itself with the
+semantics of header file inclusion or the arcana of C parsing.</para>
+        <para>The original FFIGEN system used a modified version of the LCC C
+compiler to produce .ffi files. Since many LinuxPPC header files contain
+GCC-specific constructs, OpenMCL's translation system uses a modified
+version of GCC (called, somewhat confusingly, ffigen.)</para>
+        <para>A version of ffigen based on GCC-4.0 was developed during the spring
+and summer of 2005.  Sources (diffs relative to the GCC-4.0 release)
+are available here, and
+binaries are available for
+DarwinPPC
+and for
+LinuxPPC.
+These versions should be insensitive to to the version of GCC (and its
+preprocessor) installed on the system.</para>
+        <para>An older version was developed in 2001-2002; it depended on the installed
+version of GCC being 2.95.  It may still be of interest for people unable
+to run the GCC-4.0-based version for whatever reason.</para>
+        <para>A LinuxPPC binary of this older version is available at ftp://clozure.com/pub/ffigen-0.1.tar.gz,
+and LinuxPPC source differences are at ftp://clozure.com/pub/ffigen-src.tar.gz.</para>
+        <para>For Darwin, the binary of the older FFIGEN is available at ftp://clozure.com/pub/ffigen-darwin.tar.gz,
+and the source differences are at ftp://clozure.com/pub/ffigen-darwin-src.tar.gz.</para>
+        <para>A shell script (distributed with the source and binary packages)
+called h-to-ffi.sh  reads a specified .h file (and optional
+preprocessor arguments) and writes a (hopefully) equivalent .ffi file to
+standard output, calling the installed C preprocessor and the ffigen
+program with appropriate arguments.</para>
+        <para>For each interface directory (see )
+<emphasis>subdir</emphasis> distributed with OpenMCL, a shell script
+(distributed with OpenMCL as "ccl:headers;<emphasis>subdir</emphasis>;C;populate.sh"
+("ccl:darwin-headers;<emphasis>subdir</emphasis>;C;populate.sh"
+for Darwin)) calls h-to-ffi.sh on a large number of the header files in
+/usr/include (or some other <emphasis>system header path</emphasis>) and
+creates a parallel directory tree in "ccl:headers;<emphasis>subdir</emphasis>;C;<emphasis>system</emphasis>;<emphasis>header</emphasis>;<emphasis>path</emphasis>;"
+(or "ccl:darwin-headers;<emphasis>subdir</emphasis>;C;<emphasis>system</emphasis>;<emphasis>header</emphasis>;<emphasis>path</emphasis>;"),
+populating that directory with .ffi files.</para>
+        <para>A lisp function defined in "ccl:library;parse-ffi.lisp"
+reads the .ffi files in a specified interface directory
+<emphasis>subdir</emphasis> and generates new versions of the databases
+(files with the extension .cdb).</para>
+        <para>The CDB databases are used by the #$ and #_ reader macros and are
+used in the expansion of RREF, RLET, and related macros.</para>
+      </sect2>
+
+      <sect2 id="Details--rebuilding-the-CDB-databases--step-by-step">
+        <para>Details: rebuilding the CDB databases, step by step</para>
+        <varlistentry numeration="arabic">
+          <variablelist>Ensure that the FFIGEN program is installed. See the"README" file in the source or binary archive for specificinstallation instructions.This example assumes LinuxPPC; for 32-bit DarwinPPC, substitute"ccl:darwin-headers;" for "ccl:headers;".   For 64-bit DarwinPPC,substitute "ccl:darwin-headers64;".</variablelist>
+          <variablelist>Edit the "ccl:headers;<emphasis>subdir</emphasis>;C;populate.sh"shell script. When you're confident that the files andpreprocessor options match your environment, cd to the"ccl:headers;<emphasis>subdir</emphasis>;C;" directory andinvoke ./populate.sh. Repeat this step until you're able tocleanly translate all files refrenced in the shell script.</variablelist>
+          <variablelist>Run OpenMCL:
+            <programlisting>
+? (require "PARSE-FFI")
+PARSE-FFI
+
+? (parse-standard-ffi-files :SUBDIR)
+;;; lots of output ... after a while, shiny new .cdb files should
+;;; appear in "ccl:headers;subdir;"
+;;; (or "ccl:darwin-headers;subdir;" under Darwin)
+</programlisting></variablelist>
+        </varlistentry>
+        <para>PARSE-STANDARD-FFI-FILES accepts a :PREPEND-UNDERSCORES keyword
+argument. Darwin (and some other platforms) use a convention wherein the
+symbols associated with C-visible external function and variables have
+underscore characters prepended to their names. When this argument is
+true, PARSE-STANDARD-FFI-FILES will prepend underscores to all foreign
+function names written to the database, so that (#_foo ...) expands into
+an EXTERNAL-CALL to "_foo".</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Case-sensitivity-of-foreign-names-in-OpenMCL">
+      <para>Case-sensitivity of foreign names in OpenMCL</para>
+
+      <sect2 id="Overview--15-">
+        <para>Overview
+As of release 0.11, OpenMCL addresses the fact that foreign type,
+constant, record, field, and function nams are case-sensitive and provides
+mechanisms to refer to these names via lisp symbols.</para>
+        <para>Previous versions of OpenMCL have tried to ignore that fact, under
+the belief that case conflicts were rare and that many users (and
+implementors) would prefer not to deal with case-related issues. The fact
+that some information in the interface databases was incomplete or
+inaccessable because of this policy made it clearer that the policy was
+untenable. I can't claim that the approach described here is
+aesthetically pleasing, but I can honestly say that it's less
+unpleasant than other approaches that I'd thought of. I'd be
+interested to hear alternate proposals.</para>
+        <para>The issues described here have to do with how lisp symbols are used
+to denote foreign functions, constants, types, records, and fields. It
+doesn't affect how other lisp objects are sometimes used to denote
+foreign objects. For instance, the first argument to the EXTERNAL-CALL
+macros is now and has always been a case-sensitive string.</para>
+      </sect2>
+
+      <sect2 id="Foreign-constant-and-function-names">
+        <para>Foreign constant and function names
+The primary way of referring to foreign constant and function names
+in OpenMCL is via the #$ and #_ reader macros. These reader macro
+functions each read a symbol into the "OS" package, look up its
+constant or function definition in the interface database, and assign the
+value of the constant to the symbol or install a macroexpansion function
+on the symbol.</para>
+        <para>In order to observe case-sensitivity, the reader-macros now read the
+symbol with (READTABLE-CASE :PRESERVE) in effect.</para>
+        <para>This means that it's necessary to type the foreign constant or
+function name in correct case, but it isn't necessary to use any
+special escaping constructs when writing the variable name. For instance:</para>
+        <programlisting>
+(#_read fd buf n) ; refers to foreign symbol "read"
+(#_READ fd buf n) ; refers to foreign symbol "READ", which may
+; not exist ...
+#$o_rdonly ; Probably doesn't exist
+#$O_RDONLY ; Exists on most platforms
+</programlisting>
+      </sect2>
+
+      <sect2 id="Foreign-type--record--and-field-names">
+        <para>Foreign type, record, and field names
+Constructs like RLET expect a foreign type or record name to be
+denoted by a symbol (typically a keyword); RREF (and PREF) expect an
+"accessor" form, typically a keyword formed by concatenating a
+foreign type or record name with a sequence of one or more foreign field
+names, separated by dots. These names are interned by the reader as other
+lisp symbols are, with an arbitrary value of READTABLE-CASE in effect
+(typically :UPCASE.) It seems like it would be very tedious to force users
+to manually escape (via vertical bar or backslash syntax) all lowercase
+characters in symbols used to specify foreign type, record, and field
+names (especially given that many traditional POSIX structure, type, and
+field names are entirely lowercase.)</para>
+        <para>The approach taken by OpenMCL is to allow the symbols (keywords)
+used to denote foreign type, record, and field names to contain angle
+brackets (< and >). Such symbols are translated to foreign names
+via the following set of conventions:</para>
+        <listitem mark="bullet">
+          <variablelist>All instances of < and > in the symbol's pname arebalanced and don't nest.</variablelist>
+          <variablelist>Any alphabetic characters in the symbol's pname thataren't enclosed in angle brackets are treated as lower-case,regardless of the value of READTABLE-CASE and regardless of the casein which they were written.</variablelist>
+          <variablelist>Alphabetic characters that appear within angle brackets aremapped to upper-case, again regardless of how they were written orinterned.</variablelist>
+        
+        </listitem>
+        <para>There may be many ways of "escaping" (with angle brackets)
+sequences of upper-case and non-lower-case characters in a symbol used to
+denote a foreign name. When translating in the other direction, OpenMCL
+always escapes the longest sequence that starts with an upper-case
+character and doesn't contain a lower-case character.</para>
+        <para>It's often preferable to use this canonical form of a foreign
+type name.</para>
+        <para>The accessor forms used by PREF/RREF should be viewed as a series of
+foreign type/record and field names; upper-case sequences in the component
+names should be escaped with angle brackets, but those sequences
+shouldn't span components. (More simply, the separating dots
+shouldn't be enclosed, even if both surrounding characters need to
+be.)</para>
+        <para>Older POSIX code tends to use lower-case exclusively for type,
+record, and field names; there are only a few cases in the OpenMCL sources
+where mixed-case names need to be escaped.</para>
+      </sect2>
+
+      <sect2 id="Examples--1-">
+        <para>Examples</para>
+        <programlisting>
+;;; Allocate a record of type "window".
+(rlet ((w :window)) ...)
+;;; Allocate a record of type "Window", which is probably a
+;;;  different type
+(rlet ((w :<w>indow)) ...)
+;;; This is equivalent to the last example
+(rlet ((w :<w>INDOW)))
+</programlisting>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Tutorial--Using-Basic-Calls-and-Types">
+      <para>Tutorial: Using Basic Calls and Types
+This tutorial is meant to cover the basics of OpenMCL for calling
+external C functions and passing data back and forth.  These basics
+will provide the foundation for more advanced techniques which will
+allow access to the various external libraries and toolkits.</para>
+      <para>The first step is to start with a simple C dynamic library in order to
+actually observe what is actually passing between OpenMCL and C.  So,
+some C code is in order:</para>
+      <para>Create the file typetest.c, and put the following code into it:</para>
+      <programlisting>
+
+#include <stdio.h>
+
+void
+void_void_test(void)
+{
+    printf("Entered %s:\n", __FUNCTION__);
+    printf("Exited  %s:\n", __FUNCTION__);
+}
+
+signed char
+sc_sc_test(signed char data)
+{
+    printf("Entered %s:\n", __FUNCTION__);
+    printf("Data In: %d\n", (signed int)data);
+    printf("Exited  %s:\n", __FUNCTION__);
+    return data;
+}
+
+unsigned char
+uc_uc_test(unsigned char data)
+{
+    printf("Entered %s:\n", __FUNCTION__);
+    printf("Data In: %d\n", (signed int)data);
+    printf("Exited  %s:\n", __FUNCTION__);
+    return data;
+}
+</programlisting>
+      <para>This defines three functions.  If you're familiar with C, notice
+that there's no <literal>main()</literal>, because we're just
+building a library, not an executable.</para>
+      <para>The function <literal>void_void_test()</literal> doesn't take
+any parameters, and doesn't return anything, but it prints two
+lines to let us know it was called.
+<literal>sc_sc_test()</literal> takes a signed char as a
+parameter, prints it, and returns it.
+<literal>uc_uc_test()</literal> does the same thing, but with
+an unsigned char.  Their purpose is just to prove to us
+that we really can call C functions, pass them values, and get
+values back from them.</para>
+      <para><inlinemediaobject name="arb36"></inlinemediaobject></para>
+      <para>This code is compiled into a dynamic library on OS X 10.3.4 with the
+command:</para>
+      <programlisting>
+
+gcc -dynamiclib -Wall -o libtypetest.dylib typetest.c \
+    -install_name ./libtypetest.dylib
+</programlisting>
+      <para>The -dynamiclib tells gcc that we will be compiling this into a
+dynamic library and not an executable binary program.  The output
+filename is "libtypetest.dylib".  Notice that we chose a name which
+follows the normal OS X convention, being in the form
+"libXXXXX.dylib", so that other programs can link to the library.
+OpenMCL doesn't need it to be this way, but it is a good idea to
+adhere to existing conventions.</para>
+      <para>The -install_name flag is primarily used when
+building OS X "bundles".  In this case, we are not using it, so we
+put a placeholder into it, "./libtypetest.dylib".  If we wanted
+to use typetest in a bundle, the -install_name argument would
+be a relative path from some "current" directory.</para>
+      <para>After creating this library, the first step is to tell OpenMCL to open
+the dynamic library.  This is done by calling
+.</para>
+      <programlisting>
+
+Welcome to OpenMCL Version (Beta: Darwin) 0.14.2-040506!
+
+? (open-shared-library "/Users/andewl/openmcl/libtypetest.dylib")
+#<SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
+</programlisting>
+      <para>You should use an absolute path here; using a relative one, such
+as just "libtypetest.dylib", would appear to work, but there are
+subtle problems which occur after reloading it.  See the Darwin
+notes on
+ for details.  It would be
+a bad idea anyway, because software should never rely on its
+starting directory being anything in particular.</para>
+      <para>This command returns a reference to the opened shared library, and
+OpenMCL also adds one to the global variable
+<literal>ccl::*shared-libraries*</literal>:</para>
+      <programlisting>
+
+? ccl::*shared-libraries*
+(#<SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
+ #<SHLIB /usr/lib/libSystem.B.dylib #x606179E>)
+</programlisting>
+      <para>Before we call anything, let's check that the individual functions can
+actually be found by the system.  We don't have to do this, but
+it helps to know how to find out whether this is the problem,
+when something goes wrong.
+We use :</para>
+      <programlisting>
+
+? (external "_void_void_test")
+#<EXTERNAL-ENTRY-POINT "_void_void_test" (#x000CFDF8) /Users/andewl/openmcl/libtypetest.dylib #x638EDF6>
+
+? (external "_sc_sc_test")
+#<EXTERNAL-ENTRY-POINT "_sc_sc_test" (#x000CFE50) /Users/andewl/openmcl/libtypetest.dylib #x638EB3E>
+
+? (external "_uc_uc_test")
+#<EXTERNAL-ENTRY-POINT "_uc_uc_test" (#x000CFED4) /Users/andewl/openmcl/libtypetest.dylib #x638E626>
+</programlisting>
+      <para>Notice that the actual function names have
+been "mangled" by the C linker.  The first function was named
+"void_void_test" in typetest.c, but in
+libtypetest.dylib, it has an underscore (a "_" symbol) before
+it: "_void_void_test".  So, this is the name which you have to use.
+The mangling - the way the name is changed - may be different for
+other operating systems or other versions, so you need to "just know"
+how it's done...</para>
+      <para>Also, pay particular attention to the fact
+that a hexadecimal value appears in the EXTERNAL-ENTRY-POINT.
+(#x000CFDF8, for example - but what it is doesn't matter.)
+These hex numbers mean that the
+function can be dereferenced.  Functions which aren't found will
+not have a hex number.  For example:</para>
+      <programlisting>
+
+? (external "functiondoesnotexist")
+#<EXTERNAL-ENTRY-POINT "functiondoesnotexist" {unresolved}  #x638E3F6>
+</programlisting>
+      <para>The "unresolved" tells us that OpenMCL wasn't able to find this
+function, which means you would get an error, "Can't resolve foreign
+symbol," if you tried to call it.</para>
+      <para>These
+external function references also are stored in a hash table which is
+accessible through a global variable, <literal>ccl::*eeps*</literal>.</para>
+      <para>At this point, we are ready to try our first external function
+call:</para>
+      <programlisting>
+
+? (external-call "_void_void_test" :void)
+Entered void_void_test:
+Exited  void_void_test:
+NIL
+</programlisting>
+      <para>We used , which is
+is the normal mechanism for
+accessing externally linked code.  The "_void_void_test"
+is the mangled name of the external function.
+The :void
+refers to the return type of the function.</para>
+      <para>If you're using ILISP to run OpenMCL inside of Emacs, you won't
+see the "Entered" and "Exited" lines until you quit (as of
+July 2004).  It's not
+clear why this is, but it's a pity.  If you want to see them, run
+OpenMCL from Terminal.app or in some other way.</para>
+      <para>The next step is to try passing a value to C, and getting one
+back:</para>
+      <programlisting>
+
+? (external-call "_sc_sc_test" :signed-byte -128 :signed-byte)
+Entered sc_sc_test:
+Data In: -128
+Exited  sc_sc_test:
+-128
+</programlisting>
+      <para>The first :signed-byte gives the type of the first argument,
+and then -128 gives the value to pass for it.  The second
+:signed-byte
+gives the return type.  The return type is always given by the
+last argument to .</para>
+      <para>Everything looks good.  Now, let's try a number outside
+the range which fits in one byte:</para>
+      <programlisting>
+
+? (external-call "_sc_sc_test" :signed-byte -567 :signed-byte)
+Entered sc_sc_test:
+Data In: -55
+Exited  sc_sc_test:
+-55
+</programlisting>
+      <para>Hmmmm.  A little odd.  Let's look at the unsigned stuff
+to see how it reacts:</para>
+      <programlisting>
+
+? (external-call "_uc_uc_test" :unsigned-byte 255 :unsigned-byte)
+Entered uc_uc_test:
+Data In: 255
+Exited  uc_uc_test:
+255
+</programlisting>
+      <para>That looks okay.  Now, let's go outside the valid range again:</para>
+      <programlisting>
+
+? (external-call "_uc_uc_test" :unsigned-byte 567 :unsigned-byte)
+Entered uc_uc_test:
+Data In: 55
+Exited  uc_uc_test:
+55
+
+? (external-call "_uc_uc_test" :unsigned-byte -567 :unsigned-byte)
+Entered uc_uc_test:
+Data In: 201
+Exited  uc_uc_test:
+201
+</programlisting>
+      <para>Since a signed byte can only hold values from -128 through 127, and
+an unsigned one can only hold values from 0 through 255, any number
+outside that range gets "clipped": only the low eight bits of it
+are used.</para>
+      <para>What is important to remember is that <emphasis>external
+function calls have
+very few safety checks.</emphasis>
+Data outside the valid range for its type will silently do
+very strange things; pointers outside the valid range can very well
+crash the system.</para>
+      <para>That's it for our first example library.  If you're still following
+along, let's add some more C code to look at the rest of the
+primitive types.  Then we'll need to recompile the dynamic library,
+load it again, and then we can see what happens.</para>
+      <para>Add the following code to typetest.c:</para>
+      <programlisting>
+
+int
+si_si_test(int data)
+{
+    printf("Entered %s:\n", __FUNCTION__);
+    printf("Data In: %d\n", data);
+    printf("Exited  %s:\n", __FUNCTION__);
+    return data;
+}
+
+long
+sl_sl_test(long data)
+{
+    printf("Entered %s:\n", __FUNCTION__);
+    printf("Data In: %ld\n", data);
+    printf("Exited  %s:\n", __FUNCTION__);
+    return data;
+}
+
+long long
+sll_sll_test(long long data)
+{
+    printf("Entered %s:\n", __FUNCTION__);
+    printf("Data In: %lld\n", data);
+    printf("Exited  %s:\n", __FUNCTION__);
+    return data;
+}
+
+float
+f_f_test(float data)
+{
+    printf("Entered %s:\n", __FUNCTION__);
+    printf("Data In: %e\n", data);
+    printf("Exited  %s:\n", __FUNCTION__);
+    return data;
+}
+
+double
+d_d_test(double data)
+{
+    printf("Entered %s:\n", __FUNCTION__);
+    printf("Data In: %e\n", data);
+    printf("Exited  %s:\n", __FUNCTION__);
+    return data;
+}
+</programlisting>
+      <para>The command line to compile the dynamic library is the same as before:</para>
+      <programlisting>
+
+gcc -dynamiclib -Wall -o libtypetest.dylib typetest.c \
+    -install_name ./libtypetest.dylib
+</programlisting>
+      <para>Now, restart OpenMCL.  This step is required because OpenMCL cannot
+close and reload a dynamic library on OS X.</para>
+      <para>Have you restarted?  Okay, try out the new code:</para>
+      <programlisting>
+
+Welcome to OpenMCL Version (Beta: Darwin) 0.14.2-040506!
+
+? (open-shared-library "/Users/andewl/openmcl/libtypetest.dylib")
+#<SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
+
+? (external-call "_si_si_test" :signed-fullword -178965 :signed-fullword)
+Entered si_si_test:
+Data In: -178965
+Exited  si_si_test:
+-178965
+
+? ;; long is the same size as int
+(external-call "_sl_sl_test" :signed-fullword -178965 :signed-fullword)
+Entered sl_sl_test:
+Data In: -178965
+Exited  sl_sl_test:
+-178965
+
+? (external-call "_sll_sll_test"
+                 :signed-doubleword -973891578912 :signed-doubleword)
+Entered sll_sll_test:
+Data In: -973891578912
+Exited  sll_sll_test:
+-973891578912
+</programlisting>
+      <para>Okay, everything seems to be acting as expected.  However, just to
+remind you that most of this stuff has no safety net, here's
+what happens if somebody mistakes <literal>sl_sl_test()</literal>
+for <literal>sll_sll_test()</literal>, thinking that a long is
+actually a doubleword:</para>
+      <programlisting>
+
+? (external-call "_sl_sl_test"
+                 :signed-doubleword -973891578912 :signed-doubleword)
+Entered sl_sl_test:
+Data In: -227
+Exited  sl_sl_test:
+-974957576192
+</programlisting>
+      <para>Ouch.  The C function changes the value with no warning that something
+is wrong.  Even worse, it manages to pass the original value back to
+OpenMCL, which hides the fact that something is wrong.</para>
+      <para>Finally, let's take a look at doing this with floating-point numbers.</para>
+      <programlisting>
+
+Welcome to OpenMCL Version (Beta: Darwin) 0.14.2-040506!
+
+? (open-shared-library "/Users/andewl/openmcl/libtypetest.dylib")
+#<SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
+
+? (external-call "_f_f_test" :single-float -1.256791e+11 :single-float)
+Entered f_f_test:
+Data In: -1.256791e+11
+Exited  f_f_test:
+-1.256791E+11
+
+? (external-call "_d_d_test" :double-float -1.256791d+290 :double-float)
+Entered d_d_test:
+Data In: -1.256791e+290
+Exited  d_d_test:
+-1.256791D+290
+</programlisting>
+      <para>Notice that the number ends with "...e+11" for the single-float,
+and "...d+290" for the
+double-float.  Lisp has both of these float types itself, and the
+d instead of the e is how you specify which to create.  If
+you tried to pass :double-float 1.0e2 to external-call, Lisp would
+be nice enough to notice and give you a type error.  Don't get the
+:double-float wrong, though, because then there's no protection.</para>
+      <para>Congratulations!  You now know how to call external C functions from
+within OpenMCL, and pass numbers back and forth.  Now that the basic
+mechanics of calling and passing work, the next step is to examine how
+to pass more complex data structures around.</para>
+
+      <sect2 id="Acknowledgement">
+        <para>Acknowledgement
+This chapter was generously contributed by
+Andrew P. Lentvorski Jr.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Tutorial--Allocating-Foreign-Data-on-the-Lisp-Heap">
+      <para>Tutorial: Allocating Foreign Data on the Lisp Heap
+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>
+      <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>
+      <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 your program
+leaks enough memory it will eventually use up all of it!  So, you
+need to be careful to not lose your pointers.</para>
+      <para>That disadvantage, though, is also an advantage for using
+foreign functions.  Since the garbage collector doesn't know about
+this memory, it will never move it around.  External C code
+needs this, because it doesn't know how to follow it to where it
+moved, the way that Lisp code does.  If you allocate data manually,
+you can pass it to foreign code and know that no matter what that
+code needs to do with it, it will be able to, until you
+deallocated it.  Of course, you'd better be sure it's done before
+you do.  Otherwise, your program will be unstable and might crash
+sometime in the future, and you'll have trouble figuring out what
+caused
+the trouble, because there won't be anything pointing
+back and saying "you deallocated this too soon."</para>
+      <para>And, so, on to the code...</para>
+      <para>As in the last tutorial, our first step
+is to create a local dynamic library in order to help show
+what is actually going on between OpenMCL and C.  So, create the file
+ptrtest.c, with the following code:</para>
+      <programlisting>
+#include <stdio.h>
+
+void reverse_int_array(int * data, unsigned int dataobjs)
+{
+  int i, t;
+
+  for(i=0; i<dataobjs/2; i++)
+    {
+      t = *(data+i);
+      *(data+i) = *(data+dataobjs-1-i);
+      *(data+dataobjs-1-i) = t;
+    }
+}
+
+void reverse_int_ptr_array(int **ptrs, unsigned int ptrobjs)
+{
+  int *t;
+  int i;
+
+  for(i=0; i<ptrobjs/2; i++)
+    {
+      t = *(ptrs+i);
+      *(ptrs+i) = *(ptrs+ptrobjs-1-i);
+      *(ptrs+ptrobjs-1-i) = t;
+    }
+}
+
+void
+reverse_int_ptr_ptrtest(int **ptrs)
+{
+  reverse_int_ptr_array(ptrs, 2);
+
+  reverse_int_array(*(ptrs+0), 4);
+  reverse_int_array(*(ptrs+1), 4);
+}
+</programlisting>
+      <para>This defines three functions.  <literal>reverse_int_array</literal>
+takes a pointer to an array of <literal>int</literal>s, and a count
+telling how many items are in the array, and loops through it
+putting the elements in reverse.
+<literal>reverse_int_ptr_array</literal> does the same thing,
+but with an array of pointers to <literal>int</literal>s.  It only
+reverses the order the pointers are in; each pointer still points to
+the same thing.
+<literal>reverse_int_ptr_ptrtest</literal>
+takes an array of pointers to arrays of <literal>int</literal>s.  (With me?)
+It doesn't need to be told their sizes;
+it just assumes that the array of pointers has two items,
+and that both of those are arrays which have four items.  It
+reverses the array of pointers, then it reverses each of the two
+arrays of <literal>int</literal>s.</para>
+      <para>Now, compile ptrtest.c into a dynamic library using the command:</para>
+      <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 OpenMCL 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 (= (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>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 OpenMCL
+object in heap memory.  It returns both an array reference, which can
+be used directly from OpenMCL, and a <literal>macptr</literal>, which can
+be used to access the underlying memory directly.  For example:</para>
+      <programlisting>
+? ;; Create an array of 3 4-byte-long integers
+(multiple-value-bind (la lap)
+    (make-heap-ivector 3 '(unsigned-byte 32))
+  (setq a la)
+  (setq ap lap))
+;Compiler warnings :
+;   Undeclared free variable A, in an anonymous lambda form.
+;   Undeclared free variable AP, in an anonymous lambda form.
+#<A Mac Pointer #x10217C>
+
+? a
+#(1396 2578 97862649)
+
+? ap
+#<A Mac Pointer #x10217C>
+</programlisting>
+      <para>It's important to realize that the contents of the
+<literal>ivector</literal> we've just created
+haven't been initialized,
+so their values are unpredictable,
+and you should be sure not to
+read from them before you set them, to avoid confusing results.</para>
+      <para>At this point, <literal>a</literal> references an object which
+works just
+like a normal array.  You can refer to any item of it with
+the standard <literal>aref</literal> function, and set them
+by combining that with <literal>setf</literal>.
+As noted
+above, the <literal>ivector</literal>'s
+contents haven't been initialized,
+so that's the next order of business:</para>
+      <programlisting>
+? a
+#(1396 2578 97862649)
+
+? (aref a 2)
+97862649
+
+? (setf (aref a 0) 3)
+3
+
+? (setf (aref a 1) 4)
+4
+
+? (setf (aref a 2) 5)
+5
+
+? a
+#(3 4 5)
+</programlisting>
+      <para>In addition, the <literal>macptr</literal> allows direct access to the same
+memory:</para>
+      <programlisting>
+? (setq *byte-length-of-long* 4)
+4
+
+? (%get-signed-long ap (* 2 *byte-length-of-long*))
+5
+
+? (%get-signed-long ap (* 0 *byte-length-of-long*))
+3
+
+? (setf (%get-signed-long ap (* 0 *byte-length-of-long*)) 6)
+6
+
+? (setf (%get-signed-long ap (* 2 *byte-length-of-long*)) 7)
+7
+
+? ;; Show that a actually got changed through ap
+a
+#(6 4 7)
+</programlisting>
+      <para>So far, there is nothing about this object that could not be done much
+better with standard Lisp.  However, the <literal>macptr</literal> can be
+used to pass this chunk of memory off to a C function.  Let's use
+the C
+code to reverse the elements in the array:</para>
+      <programlisting>
+? ;; Insert the full path to your copy of libptrtest.dylib
+(open-shared-library "/Users/andrewl/openmcl/openmcl/gtk/libptrtest.dylib")
+#<SHLIB /Users/andrewl/openmcl/openmcl/gtk/libptrtest.dylib #x639D1E6>
+
+? a
+#(6 4 7)
+
+? ap
+#<A Mac Pointer #x10217C>
+
+? (external-call "_reverse_int_array" :address ap :unsigned-int (length a) :address)
+#<A Mac Pointer #x10217C>
+
+? a
+#(7 4 6)
+
+? ap
+#<A Mac Pointer #x10217C>
+</programlisting>
+      <para>The array gets passed correctly to the C function,
+<literal>reverse_int_array</literal>.  The C function
+reverses the contents of the array in-place; that is, it doesn't make
+a new array, just keeps the same one and reverses what's in it.
+Finally, the C function
+passes control back to OpenMCL.  Since the allocated array memory has
+been directly modifed, OpenMCL reflects those changes directly in the
+array as well.</para>
+      <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>
+      <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,
+you need to make sure that when whatever you were doing with the
+hash table is done, those ivectors all get freed.  Unless there's
+still something somewhere else which refers to them, of course!
+Exactly what strategy to take depends on the situation,
+so just try to keep things simple unless you know better.</para>
+      <para>The simplest situation is when you have things set up so that a Lisp
+object "encapsulates" a pointer to foreign data, taking care of all
+the
+details of using it.  In this case, you don't want those two things
+to have different lifetimes: You want to make sure your Lisp object
+exists as long as the foreign data does, and no longer; and you want
+to make sure the foreign data doesn't get deallocated while your
+Lisp object still refers to it.</para>
+      <para>If you're willing to accept a few limitations, you can make this
+easy.  First, you can't let foreign code keep a permanent pointer
+to the
+memory; it has to always finish what it's doing, then return, and
+not refer to that memory again.  Second, you can't let any Lisp
+code that isn't part of your encapsulating "wrapper" refer to the
+pointer directly.  Third, nothing, either foreign code or Lisp
+code, should explicitly deallocate the memory.</para>
+      <para>If you can make sure all of these are true, you can at least
+ensure that the foreign
+pointer is deallocated when the encapsulating object is about to
+become
+garbage, by using OpenMCL's nonstandard "termination" mechanism,
+which is essentially the same as what Java and other languages
+call "finialization".</para>
+      <para>Termination is a way of asking the garbage collector to let you know
+when it's about to destroy an object which isn't used anymore.
+Before destroying the object, it calls a function which you write,
+called a terminator.</para>
+      <para>So, you can use termination to find out when a particular
+<literal>macptr</literal> is about to become garbage.
+That's not quite
+as helpful as it might seem:  It's not exactly the same thing as
+knowing that the block of memory it points to is unreferenced.
+For example, there could be another <literal>macptr</literal> somewhere
+to the
+same block; or, if it's a struct, there could be a
+<literal>macptr</literal> to one of its fields.  Most problematically,
+if the address of that memory has been passed to foreign code,
+it's sometimes hard to know whether that code has kept the
+pointer.  Most foreign functions don't, but it's not hard to think of
+exceptions.</para>
+      <para>You can use code such as this to make all this happen:</para>
+      <programlisting>
+(defclass wrapper (whatever)
+  ((element-type :initarg :element-type)
+   (element-count :initarg :element-count)
+   (ivector)
+   (macptr)))
+
+(defmethod initialize-instance ((wrapper wrapper) &amp;rest initargs)
+  (declare (ignore initargs))
+  (call-next-method)
+  (ccl:terminate-when-unreachable wrapper)
+  (with-slots (ivector macptr element-type element-count) wrapper
+    (multiple-value-bind (new-ivector new-macptr)
+        (make-heap-ivector element-count element-type)
+      (setq ivector new-ivector
+            macptr new-macptr))))
+
+(defmethod ccl:terminate ((wrapper wrapper))
+  (with-slots (ivector macptr) wrapper
+    (when ivector
+      (dispose-heap-ivector ivector macptr)
+      (setq ivector nil
+            macptr nil))))
+</programlisting>
+      <para>The <literal>ccl:terminate</literal> method will be called on
+some arbitrary thread
+sometime (hopefully soon) after the GC has decided that there are no
+strong references to an object which has been the argument of a
+<literal>ccl:terminate-when-unreachable</literal> call.</para>
+      <para>If it makes sense to say that the foreign object should live as long
+as there's Lisp code that references it (through the encapsulating
+obect) and no longer, this is one way of doing that.</para>
+      <para>Now we've covered passing basic types back and forth with C, and
+we've done the same with pointers.  You may think this is all...
+but we've only done pointers to basic types.  Join us next time
+for pointers... to pointers.</para>
+
+      <sect2 id="Acknowledgement--1-">
+        <para>Acknowledgement
+Much of this chapter was generously contributed by
+Andrew P. LentvorskiJr.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="The-Foreign-Function-Interface-Dictionary">
+      <para>The Foreign-Function-Interface Dictionary</para>
+
+      <sect2 id="DEF-FOREIGN-TYPE">
+        <para>DEF-FOREIGN-TYPE</para>
+        <informalfigure>def-foreign-type</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>DEF-FOREIGN-TYPE &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    def-foreign-type name foreign-type-spec
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>name
+            <variablelist>NIL or a keyword; the keyword may containescaping constructs (see ).</variablelist>
+          </indexterm><indexterm>foreign-type-spec
+            <variablelist>A foreign type specifier, whose syntax is (loosely)defined above.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>If name is non-NIL, defines name to be an alias for the
+foreign type specified by foreign-type-spec. If foreign-type-spec
+is a named structure or union type, additionally defines that
+structure or union type.</para>
+        <para>If name is NIL, foreign-type-spec must be a named foreign
+struct or union definition, in which case the foreign structure
+or
+union definition is put in effect.</para>
+        <para>Note that there are two separate namespaces for foreign
+type names, one for the names of ordinary types and one for
+the names of structs and unions.  Which one
+<literal>name</literal> refers to depends on
+<literal>foreign-type-spec</literal> in the obvious manner.</para>
+      </sect2>
+
+      <sect2 id="MAKE-RECORD">
+        <para>MAKE-RECORD</para>
+        <informalfigure>make-record</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>MAKE-RECORD &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    make-record typespec
+	    &amp;rest initforms => result
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>typespec
+            <variablelist>A foreign type specifier, or a keyword which is usedas the name of a foreign struct or union.</variablelist>
+          </indexterm><indexterm>initforms
+            <variablelist>If the type denoted by <literal>typespec</literal>is scalar, a single value appropriate for that type;otherwise, a list of alternating field names andvalues appropriate for the types of those fields.</variablelist>
+          </indexterm><indexterm>result
+            <variablelist>A <literal>macptr</literal> which encapsulates the address of anewly-allocated record on the foreign heap.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Expands into code which allocates and initalizes
+an instance of the type
+denoted by <literal>typespec</literal>, on the foreign
+heap.  The record is allocated using the C function
+<literal>malloc</literal>, and the user of
+<literal>make-record</literal> must explicitly call
+the C function <literal>free</literal> to deallocate the
+record, when it is no longer needed.</para>
+        <para>If <literal>initforms</literal> is provided, its value
+or values are used in the initialization.  When the type
+is a scalar, <literal>initforms</literal> is either a single
+value which can be coerced to that type, or no value, in which
+case binary 0 is used.  When the type is a <literal>struct</literal>,
+<literal>initforms</literal> is a list, giving field names
+and the values for each.  Each field is treated in the same way
+as a scalar is: If a value for it is given, it must be
+coerceable to the field's type; if not, binary 0 is used.</para>
+        <para>When the type is an array, <literal>initforms</literal> may
+not be provided, because <literal>make-record</literal>
+cannot initialize its values.  <literal>make-record</literal>
+is also unable to initialize fields of a <literal>struct</literal>
+which are themselves
+<literal>struct</literal>s.  The user of
+<literal>make-record</literal> should set these values
+by another means.</para>
+        <para>A possibly-significant limitation is that it must be possible to
+find the foreign type at the time the macro is expanded;
+<literal>make-record</literal> signals an error if this is
+not the case.</para>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para>It is inconvenient that <literal>make-record</literal> is a
+macro, because this means that <literal>typespec</literal>
+cannot be a variable; it must be an immediate value.</para>
+        <para>If it weren't for this requirement,
+<literal>make-record</literal> could be a function.  However,
+that would mean that any stand-alone application using it would
+have to include a copy of the interface database
+(see The Interface Database), which is undesireable
+because it's large.</para>
+      </sect2>
+
+      <sect2 id="RLET">
+        <para>RLET</para>
+        <informalfigure>rlet</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>RLET &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    rlet (var typespec &amp;rest initforms)*
+	    &amp;body body
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>var
+            <variablelist>A symbol (a lisp variable)</variablelist>
+          </indexterm><indexterm>typespec
+            <variablelist>A foreign type specifier or foreign record name.</variablelist>
+          </indexterm><indexterm>initforms
+            <variablelist>As described above, for</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Executes <literal>body</literal>
+in an environment in which each var is bound
+to a MACPTR (see ) encapsulating the
+address of a stack-allocated foreign memory block, allocated and
+initialized from typespec and initforms as per
+.
+Returns whatever value(s) <literal>body</literal>
+returns.</para>
+        <para>Record fields that aren't explicitly initialized have
+unspecified contents.</para>
+      </sect2>
+
+      <sect2 id="RLETZ">
+        <para>RLETZ</para>
+        <informalfigure>rletz</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>RLETZ &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    rletz (var typespec &amp;rest initforms)*
+	    &amp;body body
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>var
+            <variablelist>A symbol (a lisp variable)</variablelist>
+          </indexterm><indexterm>typespec
+            <variablelist>A foreign type specifier or foreign record name.</variablelist>
+          </indexterm><indexterm>initforms
+            <variablelist>As described above, for ccl:make-record</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Executes body in an environment in which each var is bound
+to a MACPTR (see ) encapuslating the
+address of a stack-allocated foreign memory block, allocated and
+initialized from typespec and initforms as
+ccl:make-record.</para>
+        <para>Returns whatever value(s) body returns.</para>
+        <para>Unlike rlet, record fields that aren't explicitly
+initialized are set to binary 0.</para>
+      </sect2>
+
+      <sect2 id="PREF">
+        <para>PREF</para>
+        <informalfigure>pref</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>PREF &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    pref ptr accessor-form
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>ptr
+            <variablelist>a MACPTR (see ).</variablelist>
+          </indexterm><indexterm>accessor-form
+            <variablelist>a keyword which names a foreign type or record, asdescribed in .</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>References an instance of a foreign type (or a component of
+a foreign type) accessible via ptr.</para>
+        <para>Expands into code which references the indicated scalar type
+or component, or returns a pointer to a composite type.</para>
+        <para>PREF can be used with SETF.</para>
+        <para>RREF is a deprecated alternative to PREF. It accepts a
+:STORAGE keyword and rather loudly ignores it.</para>
+      </sect2>
+
+      <sect2 id="OPEN-SHARED-LIBRARY">
+        <para>OPEN-SHARED-LIBRARY</para>
+        <informalfigure>open-shared-library</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>OPEN-SHARED-LIBRARY &mdash; Asks the operating system to load a shared library
+for OpenMCL to use.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    open-shared-library name => library
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>name
+            <variablelist>A SIMPLE-STRING which is presumed to be the so-name ofor a filesystem path to the library.</variablelist>
+          </indexterm><indexterm>library
+            <variablelist>An object of type SHLIB which describes thelibrary denoted by <literal>name</literal>.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>If the library denoted by <literal>name</literal> can
+be loaded by the
+operating system, returns an object of type SHLIB that describes
+the library; if the library is already open, increments a
+reference count. If the library can't be loaded, signals a
+SIMPLE-ERROR which contains an often-cryptic message from the
+operating system.</para>
+        <bridgehead renderas="sect3">Examples</bridgehead>
+        <programlisting>
+;;; Try to do something simple.
+? (open-shared-library "libgtk.so")
+> Error: Error opening shared library "libgtk.so": /usr/lib/libgtk.so: undefined symbol: gdk_threads_mutex
+> While executing: OPEN-SHARED-LIBRARY
+
+;;; Grovel around, curse, and try to find out where "gdk_threads_mutex"
+;;; might be defined. Then try again:
+
+? (open-shared-library "libgdk.so")
+#<SHLIB libgdk.so #x3046DBB6>
+
+? (open-shared-library "libgtk.so")
+#<SHLIB libgtk.so #x3046DC86>
+
+;;; Reference an external symbol defined in one of those libraries.
+
+? (external "gtk_main")
+#<EXTERNAL-ENTRY-POINT "gtk_main" (#x012C3004) libgtk.so #x3046FE46>
+
+;;; Close those libraries.
+
+? (close-shared-library "libgtk.so")
+T
+
+? (close-shared-library "libgdk.so")
+T
+
+;;; Reference the external symbol again.
+
+? (external "gtk_main")
+#<EXTERNAL-ENTRY-POINT "gtk_main" {unresolved} libgtk.so #x3046FE46>
+</programlisting>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para>It would be helpful to describe what an soname is and give
+examples of one.</para>
+        <para>Does the SHLIB still get returned if the library is
+already open?</para>
+      </sect2>
+
+      <sect2 id="CLOSE-SHARED-LIBRARY">
+        <para>CLOSE-SHARED-LIBRARY</para>
+        <informalfigure>close-shared-library</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CLOSE-SHARED-LIBRARY &mdash; Stops using a shared library, informing the operating
+system that it can be unloaded if appropriate.</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    close-shared-library library &amp;key
+	  completely
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>library
+            <variablelist>either an object of type SHLIB, or a string whichdesignates one by its so-name.</variablelist>
+          </indexterm><indexterm>completely
+            <variablelist>a boolean.  The default is T.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>If <literal>completely</literal> is T, sets the
+reference count of <literal>library</literal> to 0.  Otherwise,
+decrements it by 1.  In either case, if the reference count
+becomes 0, <literal>close-shared-library</literal>
+frees all memory resources consumed <literal>library</literal>
+and
+causes any EXTERNAL-ENTRY-POINTs known to be defined by it to
+become unresolved.</para>
+      </sect2>
+
+      <sect2 id="EXTERNAL">
+        <para>EXTERNAL</para>
+        <informalfigure>external</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>EXTERNAL &mdash; Resolves a reference to an external symbol which
+is defined in a shared library.</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    external name => entry
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>name
+            <variablelist>a simple-string which names an external symbol.Case-sensitive.</variablelist>
+          </indexterm><indexterm>entry
+            <variablelist>an object of type EXTERNAL-ENTRY-POINT which maintainsthe address of the foreign symbol named by<literal>name</literal>.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>If there is already an EXTERNAL-ENTRY-POINT for
+the symbol named by <literal>name</literal>, finds it and
+returns it.  If not, creates one and returns it.</para>
+        <para>Tries to resolve the entry point to a memory address,
+and identify the containing library.</para>
+        <para>Be aware that under Darwin, external functions which
+are callable from C have underscores prepended to their names,
+as in "_fopen".</para>
+      </sect2>
+
+      <sect2 id="iFF-CALL">
+        <para>%FF-CALL</para>
+        <informalfigure>%ff-call</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>%FF-CALL &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    %ff-call entrypoint
+	    {arg-type-keyword arg}* &amp;optional result-type-keyword
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>entrypoint
+            <variablelist>A fixnum or MACPTR</variablelist>
+          </indexterm><indexterm>arg-type-keyword
+            <variablelist>One of the foreign argument-type keywords, describedabove</variablelist>
+          </indexterm><indexterm>arg
+            <variablelist>A lisp value of type indicated by the correspondingarg-type-keyword</variablelist>
+          </indexterm><indexterm>result-type-keyword
+            <variablelist>One of the foreign argument-type keywords, describedabove</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Calls the foreign function at address entrypoint passing the
+values of each arg as a foreign argument of type indicated by the
+corresponding arg-type-keyword. Returns the foreign function
+result (coerced to a Lisp object of type indicated by
+result-type-keyword), or NIL if result-type-keyword is :VOID or
+NIL</para>
+      </sect2>
+
+      <sect2 id="FF-CALL">
+        <para>FF-CALL</para>
+        <informalfigure>ff-call</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>FF-CALL &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    ff-call entrypoint
+	    {arg-type-specifier arg}* &amp;optional result-type-specifier
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>entrypoint
+            <variablelist>A fixnum or MACPTR</variablelist>
+          </indexterm><indexterm>arg-type-specifer
+            <variablelist>One of the foreign argument-type keywords, describedabove, or an equivalent foreigntype specifier (see ).</variablelist>
+          </indexterm><indexterm>arg
+            <variablelist>A lisp value of type indicated by the correspondingarg-type-specifier</variablelist>
+          </indexterm><indexterm>result-type-specifier
+            <variablelist>One of the foreign argument-type keywords, describedabove, or an equivalent foreigntype specifier (see ).</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Calls the foreign function at address entrypoint passing the
+values of each arg as a foreign argument of type indicated by the
+corresponding arg-type-specifier. Returns the foreign function
+result (coerced to a Lisp object of type indicated by
+result-type-specifier), or NIL if result-type-specifer is :VOID or
+NIL</para>
+      </sect2>
+
+      <sect2 id="iREFERENCE-EXTERNAL-ENTRY-POINT">
+        <para>%REFERENCE-EXTERNAL-ENTRY-POINT</para>
+        <informalfigure>%reference-external-entry-point</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>%REFERENCE-EXTERNAL-ENTRY-POINT &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    %reference-external-entry-point eep
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>eep
+            <variablelist>An EXTERNAL-ENTRY-POINT, as obtained by the EXTERNALmacro.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Tries to resolve the address of the EXTERNAL-ENTRY-POINT
+eep; returns a fixnum representation of that address if
+successful, else signals an error.</para>
+      </sect2>
+
+      <sect2 id="EXTERNAL-CALL">
+        <para>EXTERNAL-CALL</para>
+        <informalfigure>external-call</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>EXTERNAL-CALL &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    external-call name
+	    {arg-type-specifier arg}* &amp;optional result-type-specifier
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>name
+            <variablelist>A lisp string. See external, above.</variablelist>
+          </indexterm><indexterm>arg-type-specifer
+            <variablelist>One of the foreign argument-type keywords, describedabove, or an equivalent foreigntype specifier (see ).</variablelist>
+          </indexterm><indexterm>arg
+            <variablelist>A lisp value of type indicated by the correspondingarg-type-specifier</variablelist>
+          </indexterm><indexterm>result-type-specifier
+            <variablelist>One of the foreign argument-type keywords, describedabove, or an equivalent foreigntype specifier (see ).</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Calls the foreign function at the address obtained by
+resolving the external-entry-point associated with name, passing
+the values of each arg as a foreign argument of type indicated by
+the corresponding arg-type-specifier. Returns the foreign function
+result (coerced to a Lisp object of type indicated by
+result-type-specifier), or NIL if result-type-specifer is :VOID or
+NIL</para>
+      </sect2>
+
+      <sect2 id="FOREIGN-SYMBOL-ENTRY">
+        <para>FOREIGN-SYMBOL-ENTRY</para>
+        <informalfigure>foreign-symbol-entry</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>FOREIGN-SYMBOL-ENTRY &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    foreign-symbol-entry name
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>name
+            <variablelist>A lisp string.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Tries to resolve the address of the foreign symbol name. If
+successful, returns a fixnum representation of that address, else
+returns NIL.</para>
+      </sect2>
+
+      <sect2 id="FOREIGN-SYMBOL-ADDRESS">
+        <para>FOREIGN-SYMBOL-ADDRESS</para>
+        <informalfigure>foreign-symbol-address</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>FOREIGN-SYMBOL-ADDRESS &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    foreign-symbol-address name
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>name
+            <variablelist>A lisp string.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Tries to resolve the address of the foreign symbol name. If
+successful, returns that address encapsulated
+in a MACPTR (see ), else returns
+NIL.</para>
+      </sect2>
+
+      <sect2 id="DEFCALLBACK">
+        <para>DEFCALLBACK</para>
+        <informalfigure>defcallback</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>DEFCALLBACK &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    defcallback name
+	    ({arg-type-specifier var}* &amp;optional result-type-specifier)
+	    &amp;body body
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>name
+            <variablelist>A symbol which can be made into a special variable</variablelist>
+          </indexterm><indexterm>arg-type-specifer
+            <variablelist>One of the foreign argument-type keywords, describedabove, or an equivalent foreigntype specifier (see ).In addition, if the keyword:WITHOUT-INTERRUPTS is specified, the callback will beexecuted with lisp interrupts disabled if the correspondingvar is non-NIL. If :WITHOUT-INTERRUPTS is specified morethan once, the rightmost instance wins.</variablelist>
+          </indexterm><indexterm>var
+            <variablelist>A symbol (lisp variable), which will be bound to avalue of the specified type.</variablelist>
+          </indexterm><indexterm>body
+            <variablelist>A sequence of lisp forms, which should return a valuewhich can be coerced to the specified result-type.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Proclaims <literal>name</literal>
+to be a special variable; sets its value to a
+MACPTR which, when called by foreign code, calls a lisp function
+which expects foreign arguments of the specified types and which
+returns a foreign value of the specified result type. Any argument
+variables which correspond to foreign arguments of type :ADDRESS
+are bound to stack-allocated MACPTRs.</para>
+        <para>If <literal>name</literal>
+is already a callback function pointer, its value is
+not changed; instead, it's arranged
+that an
+updated version of the lisp callback function will be called.
+This feature allows for callback functions to be redefined
+incrementally, just like Lisp functions are.</para>
+        <para><literal>defcallback</literal>
+returns the callback pointer, e.g., the
+value of <literal>name</literal>.</para>
+      </sect2>
+
+      <sect2 id="SHARP-UNDERSCORE">
+        <para>SHARP-AMPERSAND</para>
+        <informalfigure>#_</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>#_ &mdash;</para>
+        <para>Reader Macro</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Reads a symbol from the current input stream, with *PACKAGE*
+bound to the "OS" package and with readtable-case preserved.</para>
+        <para>Does a lookup on that symbol
+in the OpenMCL interface database (see ),
+signalling
+an error if no foreign function information can be found for the
+symbol in any
+active interface directory (see ).</para>
+        <para>Notes the foreign function information, including the foreign
+function's return type, the number and type of the foreign
+function's required arguments, and an indication of whether or
+not the function accepts additional arguments (via e.g., the
+"varargs" mechanism in C).</para>
+        <para>Defines a macroexpansion function on the symbol, which expand
+macro calls involving the symbol into EXTERNAL-CALL forms where
+foreign argument type specifiers for required arguments and the
+return value specifer are provided from the information ind the
+database.</para>
+        <para>Returns the symbol.</para>
+        <para>The effect of these steps is that it's possible to call
+foreign functions that take fixed numbers of arguments by simply
+providing argument values, as in:</para>
+        <programlisting>
+(#_isatty fd)
+(#_read fd buf n)
+</programlisting>
+        <para>and to call foreign functions that take variable numbers of
+arguments by specifying the types of non-required args, as in:</para>
+        <programlisting>
+(with-cstrs ((format-string "the answer is: %d"))
+  (#_printf format-string :int answer))
+</programlisting>
+      </sect2>
+
+      <sect2 id="SHARP-AMPERSAND">
+        <para>SHARP-AMPERSAND</para>
+        <informalfigure>SHARP-AMPERSAND</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>#&amp; &mdash;</para>
+        <para>Reader Macro</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>In OpenMCL 1.0 and later, the #&amp; reader macro <tip><para>This
+functionality was introduced as #? in 0.14.2, but ANSI CL requires
+that #? be reserved for the user.  #? is still supported as an alias
+to #&amp;, but that will change in the next release.</para></tip> can be used to
+access foreign variables; this functionality depends on the presence
+of "vars.cdb" files in the interface database. The current behavior of
+the #&amp; reader macro is to:</para>
+        <para>Read a symbol from the current input stream, with *PACKAGE*
+bound to the "OS" package and with readtable-case preserved.</para>
+        <para>Use that symbol's pname to access the OpenMCL interface
+database, signalling an error if no appropriate foreign variable
+information can be found with that name in any active interface
+directory.</para>
+        <para>Use type information recorded in the database to construct a
+form which can be used to access the foreign variable, and return
+that form.</para>
+        <para>Please note that the set of foreign variables declared in header files
+may or may not match the set of foreign variables exported from
+libraries (we're generally talking about C and Unix here ...). When
+they do match, the form constructed by the #&amp; reader macro manages the
+details of resolving and tracking changes to the foreign variable's
+address.</para>
+        <para>Future extensions (via prefix arguments to the reader macro) may
+offer additional behavior; it might be convenient (for instance) to be
+able to access the address of a foreign variable without dereferencing
+that address.</para>
+        <para>Foreign variables in C code tend to be platform- and
+package-specific (the canonical example - "errno" - is typically
+not a variable when threads are involved. )</para>
+        <para>In LinuxPPC,</para>
+        <programlisting>
+? #&amp;stderr
+</programlisting>
+        <para>returns a pointer to the stdio error stream ("stderr" is a
+macro under OSX/Darwin).</para>
+        <para>On both LinuxPPC and DarwinPPC,</para>
+        <programlisting>
+? #&amp;sys_errlist
+</programlisting>
+        <para>returns a pointer to a C array of C error message strings.</para>
+      </sect2>
+
+      <sect2 id="USE-INTERFACE-DIR">
+        <para>USE-INTERFACE-DIR</para>
+        <informalfigure>use-interface-dir</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>USE-INTERFACE-DIR &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    use-interface-dir dir-id
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>dir-id
+            <variablelist>A keyword whose pname, mapped to lower case, names asubdirectory of "ccl:headers;" (or"ccl:darwin-headers;")</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Tells OpenMCL to add the interface directory denoted by
+dir-id to the list of interface directories which it consults for
+foreign type and function information. Arranges that that
+directory is searched before any others.</para>
+        <para>Note that <literal>use-interface-dir</literal>
+merely adds an entry
+to a search list.
+If the named directory doesn't exist in the file system
+or doesn't
+contain a set of database files, a runtime error may occur
+when OpenMCL
+tries to open some database file in that directory, and it
+will try to
+open such a database file whenever it needs to find any
+foreign type or
+function information. 
+may come in
+handy in that case.</para>
+        <bridgehead renderas="sect3">Examples</bridgehead>
+        <para>One typically wants interface information to be
+available at compile-time (or, in many cases, at read-time).
+A typical idiom would be:</para>
+        <programlisting>
+(eval-when (:compile-toplevel :execute)
+  (use-interface-dir :GTK))
+</programlisting>
+        <para>Using the :GTK interface directory makes available
+information on
+foreign types, functions, and constants.  It's generally
+necessary to
+load foreign libraries before actually calling the
+foreign code, which for GTK can be done like this:</para>
+        <programlisting>
+(load-gtk-libraries)
+</programlisting>
+        <para>It should now be possible to do things like:</para>
+        <programlisting>
+(#_gtk_widget_destroy w)
+</programlisting>
+      </sect2>
+
+      <sect2 id="UNUSE-INTERFACE-DIR">
+        <para>UNUSE-INTERFACE-DIR</para>
+        <informalfigure>unuse-interface-dir</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>UNUSE-INTERFACE-DIR &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    unuse-interface-dir dir-id
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>dir-id
+            <variablelist>A keyword whose pname, mapped to lower case, names asubdirectory of "ccl:headers;" (or"ccl:darwin-headers;")</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Tells OpenMCL to remove the interface directory denoted by
+dir-id from the list of interface directories which are
+consulted for
+foreign type and function information. Returns T if the directory
+was on the search list, NIL otherwise.</para>
+      </sect2>
+
+      <sect2 id="TERMINATE-WHEN-UNREACHABLE">
+        <para>TERMINATE-WHEN-UNREACHABLE</para>
+        <informalfigure>terminate-when-unreachable</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>TERMINATE-WHEN-UNREACHABLE &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    terminate-when-unreachable object
+
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>object
+            <variablelist>A CLOS object of a class for which there existsa method of the generic function<literal>ccl:terminate</literal>.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>The "termination" mechanism is a way to have the garbage
+collector run a function right before an object is about to
+become garbage.  It is very similar to the "finalization"
+mechanism which Java has.  It is not standard Common Lisp,
+although other Lisp implementations have similar features.
+It is useful when there is some sort of special cleanup,
+deallocation, or releasing of resources which needs to happen
+when a certain object is no longer being used.</para>
+        <para>When the garbage collector discovers that an object is no
+longer referred to anywhere in the program, it deallocates
+that object, freeing its memory.  However, if
+<literal>ccl:terminate-when-unreachable</literal> has been
+called on the object at any time, the garbage collector first
+invokes the generic function <literal>ccl:terminate</literal>,
+passing it the object as a parameter.</para>
+        <para>Therefore, to make termination do something useful, you need to
+define a method on <literal>ccl:terminate</literal>.</para>
+        <para>Because calling
+<literal>ccl:terminate-when-unreachable</literal> only
+affects a single object, rather than all objects of its
+class, you
+may wish to put a call to it in the
+<literal>initialize-instance</literal> method of a
+class.  Of course, this is only appropriate if you do in fact
+want to use termination for all objects of a given class.</para>
+        <bridgehead renderas="sect3">Example</bridgehead>
+        <programlisting>
+(defclass resource-wrapper ()
+  ((resource :accessor resource)))
+
+(defmethod initialize-instance :after ((x resource-wrapper) &amp;rest initargs)
+  (ccl:terminate-when-unreachable x))
+
+(defmethod ccl:terminate ((x resource-wrapper))
+  (when (resource x)
+    (deallocate (resource x))))
+</programlisting>
+        <bridgehead renderas="sect3">See Also</bridgehead>
+        <para role="continues">Tutorial: Allocating Foreign Data on the Lisp Heap</para>
+      </sect2>
+    </sect1>
+  </chapter>
+
+  <chapter id="The-Objective-C-Bridge">
+    <para>The Objective-C Bridge
+OS X APIs use a language called "Objective C", which is built on C.
+The Objective-C bridge makes it possible to work with ObjC
+objects and classes from Lisp, and to define classes in Lisp which
+can be used by ObjC.</para>
+    <para>The ultimate
+purpose of the ObjC and Cocoa bridges is to make Cocoa as
+easy as possible to use from OpenMCL, in order to support the
+development of GUI applications and IDEs.  The eventual goal,
+which is much closer than it used to be, is complete integration of
+Cocoa into CLOS (whatever that means).</para>
+    <para>The current release provides Lisp-like syntax and naming
+conventions for the basic ObjC operations, with automatic
+type processing and messages checked for validity at
+compile-time.  It also provides some convenience facilities
+for working with Cocoa.</para>
+
+    <sect1 id="Using-Objective-C-Classes">
+      <para>Using Objective-C Classes
+The class of most "standard" CLOS classes is the
+class named STANDARD-CLASS. In the Objective-C object model, each
+class is an instance of a (usually unique) metaclass, which is
+itself an instance of a "base" metaclass (often the
+metaclass of the class named "NSObject".) So, the
+Objective-C class named "NSWindow" and the ObjC class
+"NSArray" are (sole) instances of their distinct
+metaclasses whose names are also "NSWindow" and
+"NSArray", respectively. (In the Objective-C world,
+it's much more common and useful to specialize class behavior
+such as instance allocation.)</para>
+      <para>When foreign libraries containing Objective-C classes are first
+loaded, the classes they contain are identified. The foreign class
+name, such as "NSWindow", is mapped to an external symbol in the
+"NS" package via the bridge's translation rules, such as NS:NS-WINDOW.
+A similar transformation happens to the
+metaclass name, with a "+" prepended, yielding something like
+NS:+NS-WINDOW.</para>
+      <para>These classes are integrated into CLOS such that the
+metaclass is an instance of the class OBJC:OBJC-METACLASS and
+the class
+is an instance of the metaclass. SLOT-DESCRIPTION metaobjects are
+created for each instance variable, and the class and metaclass go
+through something very similar to the "standard" CLOS class
+initialization protocol (with a difference being that these classes
+have already been allocated.)</para>
+      <para>Performing all this initialization, which is done when you
+(require "COCOA"), currently takes several
+seconds; it could conceivably be sped up some, but it's never likely
+to be fast.</para>
+      <para>When the process is complete, CLOS is aware of several hundred
+new ObjC classes and their metaclasses. OpenMCL's runtime system can
+reliably recognize MACPTRs to ObjC classes as being CLASS objects, and
+can (fairly reliably but heuristically) recognize instances of those
+classes (though there are complicating factors here; see below.)
+SLOT-VALUE can be used to access (and, with care, set) instance
+variables in ObjC instances. To see this, do:</para>
+      <programlisting>
+? (require "COCOA")
+</programlisting>
+      <para>and, after waiting a bit longer for a Cocoa listener window to
+appear, activate that Cocoa listener and do:</para>
+      <programlisting>? (describe (ccl::send ccl::*NSApp* 'key-window))
+</programlisting>
+      <para>This sends a message asking for the key window, which is the window
+that has the input focus (often the frontmost), and then describes
+it. As we can see, NS:NS-WINDOWs have lots of interesting slots.</para>
+    </sect1>
+
+    <sect1 id="Instantiating-Objective-C-Objects">
+      <para>Instantiating Objective-C Objects
+Making an instance of an ObjC class (whether the class in question
+is predefined or defined by the application) involves calling
+MAKE-INSTANCE with the class and a set of initargs as arguments.
+As with STANDARD-CLASS, making an instance involves initializing
+(with INITIALIZE-INSTANCE) an object allocated with
+ALLOCATE-INSTANCE.</para>
+      <para>For example, you can create an ns:ns-number like this:</para>
+      <programlisting>
+? (make-instance 'ns:ns-number :init-with-int 42)
+#<NS-CF-NUMBER 42 (#x85962210)>
+</programlisting>
+      <para>It's worth looking at how this would be done if you were
+writing in Objective C:</para>
+      <programlisting>
+[[NSNumber alloc] initWithInt: 42]
+</programlisting>
+      <para>Allocating an instance of an ObjC class involves sending the
+class an "alloc" message, and then using those initargs that
+<emphasis>don't</emphasis> correspond to slot initags as the
+"init" message to be sent to the newly-allocated instance.  So, the
+example above could have been done more verbosely as:</para>
+      <programlisting>
+? (defvar *n* (ccl::send (find-class 'ns:ns-number) 'alloc))
+*N*
+
+? (setq *n* (ccl::send *n* :init-with-int 42))
+#<NS-CF-NUMBER 42 (#x16D340)>
+</programlisting>
+      <para>That setq is important; this is a case where init
+decides to replace the object and return the new one, instead
+of modifying the existing one.
+In fact, if you leave out the setq and
+then try to view the value of *N*, OpenMCL will freeze.  There's
+little reason to ever do it this way; this is just to show
+what's going on.</para>
+      <para>You've seen that an ObjC initialization method doesn't have to
+return the same object it was passed.  In fact, it doesn't have
+to return any object at all; in this case, the initialization fails
+and make-instance returns nil.</para>
+      <para>In some special cases, such as loading an ns:ns-window-controller
+from a .nib file, it may be necessary for you to pass the
+instance itself as one of the parameters to the initialization
+method.  It goes like this:</para>
+      <programlisting>
+? (defvar *controller*
+          (make-instance 'ns:ns-window-controller))
+*CONTROLLER*
+
+? (setq *controller*
+        (ccl::send *controller*
+                   :init-with-window-nib-name #@"DataWindow"
+                   :owner *controller*))
+#<NS-WINDOW-CONTROLLER <NSWindowController: 0x1fb520> (#x1FB520)>
+</programlisting>
+      <para>This example calls (make-instance) with no initargs.  When you
+do this, the object is only allocated, and not initialized.  It
+then sends the "init" message to do the initialization by hand.</para>
+    </sect1>
+
+    <sect1 id="Calling-Objective-C-Methods">
+      <para>Calling Objective-C Methods
+In Objective-C, methods are called "messages", and there's
+a special syntax to send a message to an object:</para>
+      <programlisting>
+[w alphaValue]
+[w setAlphaValue: 0.5]
+[v mouse: p inRect: r]
+</programlisting>
+      <para>The first line sends the method "alphaValue" to the object
+<literal>w</literal>, with no parameters.  The second line
+sends the method "setAlphaValue", with the parameter 0.5.
+The third line sends the method "mouse:inRect:" - yes, all
+one long word - with the
+parameters <literal>p</literal> and <literal>r</literal>.</para>
+      <para>In Lisp, these same three lines are:</para>
+      <programlisting>
+(send w 'alpha-value)
+(send w :set-alpha-value 0.5)
+(send v :mouse p :in-rect r)
+</programlisting>
+      <para>Notice that when a method has no parameters, its name is an ordinary
+symbol (it doesn't matter what package the symbol is in, as
+only its name is checked).  When a method has parameters,
+each part of its name is a keyword, and the keywords alternate
+with the values.</para>
+      <para>These two lines break those rules, and both  will
+result in error messages:</para>
+      <programlisting>
+(send w :alpha-value)
+(send w 'set-alpha-value 0.5)
+</programlisting>
+      <para>Instead of (send), you can also invoke (send-super), with the
+same interface.  It has roughly the same purpose as CLOS's
+(call-next-method); when you use (send-super), the message is
+handled by the superclass.  This can be used to get at the
+original implementation of a method when it is shadowed by a
+method in your subclass.</para>
+
+      <sect2 id="Type-Coercion-for-ObjC-Method-Calls">
+        <para>Type Coercion for ObjC Method Calls
+OpenMCL's FFI handles many common conversions between Lisp
+and foreign data, such as unboxing floating-point args and
+boxing floating-point results.  The bridge adds a few more
+automatic conversions:</para>
+        <para>NIL is equivalent to (%NULL-PTR) for any message argument that
+requires a pointer.</para>
+        <para>T/NIL are equivalent to #$YES/#$NO for any boolean argument.</para>
+        <para>A #$YES/#$NO returned by any method that returns BOOL will be
+automatically converted to T/NIL.</para>
+        <para>To make this last conversion work, the bridge has to engage
+in a bit of hackery.  The bridge uses ObjC run-time type
+info.  Unfortunately, BOOL is typed as CHAR by ObjC.  Thus,
+a method that returns CHAR might actually return only BOOL,
+or it might return any CHAR.</para>
+        <para>The bridge currently assumes
+that any method that returns CHAR actually returns BOOL.
+But it provides a facility for defining exceptions to this
+assumption: (DEFINE-RETURNS-BOOLEAN-EXCEPTION "charValue").
+Eventually, the best way to handle issues like this is
+probably to get our method type info directly from the
+header files rather than using ObjC's runtime type system.</para>
+        <para>Note that no automatic conversion is currently performed between
+Lisp strings and NSStrings.  However, there is a convenient
+reader macro for creating constant NSStrings:</para>
+        <programlisting>
+(SEND W :SET-TITLE #@"My Window")
+</programlisting>
+        <para>Note that #@"Hello" is a full ObjC object, so
+messages can be sent to it: (SEND #@"Hello" 'LENGTH).</para>
+        <para>To go in the other direction, use the function
+(ccl::lisp-string-from-nsstring).</para>
+        <para>To create variable NSStrings (which you will later
+want to change the
+values of), consider using CCL::NS-LISP-STRING.</para>
+      </sect2>
+
+      <sect2 id="Methods-which-Return-Structures">
+        <para>Methods which Return Structures
+Some Cocoa methods return small structures, such as those used
+to represent points, rects, sizes and ranges. When writing in
+Objective C, the compiler hides the implementation details.
+Unfortunately, in Lisp we must be slightly more aware of them.</para>
+        <para>Methods which return structures are called in a special way;
+the caller allocates space for the result, and passes a pointer
+to it as an extra argument to the method.  This is called a
+Structure Return, or STRET.  Don't look at me; I don't name
+these things.</para>
+        <para>Here's a simple use of this in Objective C.  The first line
+sends the "bounds" message to v1, which returns a rectangle.
+The second line sends the "setBounds" message to v2, passing
+that same rectangle as a parameter.</para>
+        <programlisting>
+NSRect r = [v1 bounds];
+[v2 setBounds r];
+</programlisting>
+        <para>In Lisp, we must explicitly allocate the memory, which is
+done most easily and safely with .
+We do it like this:</para>
+        <programlisting>
+(rlet ((r :<NSR>ect))
+  (send/stret r v1 'bounds)
+  (send v2 :set-bounds r))
+</programlisting>
+        <para>The rlet allocates the storage (but doesn't initialize it),
+and makes sure that it will be deallocated when we're done.
+It binds the variable r to refer to it.
+The call to <literal>send/stret</literal> is just like
+an ordinary call to
+<literal>send</literal>, except that r is passed as an
+extra, first parameter.  The third line, which calls
+<literal>send</literal>, does not need to do anything
+special, because there's nothing complicated about passing
+a structure as a parameter.</para>
+        <para>In order to make STRETs easier to use, the bridge provides two
+conveniences.</para>
+        <para>First, you can use the macros <literal>slet</literal>
+and <literal>slet*</literal> to allocate and
+initialize local variables to foreign structures in one
+step.  The example above could have been written more tersely
+as:</para>
+        <programlisting>
+(slet ((r (send v1 'bounds)))
+  (send v2 :set-bounds r))
+</programlisting>
+        <para>Second, when one call to <literal>send</literal> is made
+inside another, the inner one has an implicit
+<literal>slet</literal> around it.  So, one could in fact
+just write:</para>
+        <programlisting>
+(send v1 :set-bounds (send v2 'bounds))
+</programlisting>
+        <para>There are also several psuedo-functions provided for convenience
+by the ObjC compiler, to make objects of specific types. The
+following are currently supported by the bridge: NS-MAKE-POINT,
+NS-MAKE-RANGE, NS-MAKE-RECT, and NS-MAKE-SIZE.</para>
+        <para>These pseudo-functions can be used within an SLET initform:</para>
+        <programlisting>
+(slet ((p (ns-make-point 100.0 200.0)))
+  (send w :set-frame-origin p))
+</programlisting>
+        <para>Or within a call to <literal>send</literal>:</para>
+        <programlisting>
+(send w :set-origin (ns-make-point 100.0 200.0))
+</programlisting>
+        <para>However, since these aren't real functions, a call like the
+following won't work:</para>
+        <programlisting>
+(setq p (ns-make-point 100.0 200.0))
+</programlisting>
+        <para>To extract fields from these objects, there are also some
+convenience macros: NS-MAX-RANGE, NS-MIN-X,
+NS-MIN-Y, NS-MAX-X, NS-MAX-Y, NS-MID-X, NS-MID-Y,
+NS-HEIGHT, and NS-WIDTH.</para>
+        <para>Note that there is also a <literal>send-super/stret</literal>
+for use within methods.  Like <literal>send-super</literal>,
+it ignores any shadowing methods in a subclass, and calls the
+version of a method which belongs to its superclass.</para>
+      </sect2>
+
+      <sect2 id="Variable-Arity-Messages">
+        <para>Variable-Arity Messages
+There are a few messages in Cocoa which take variable numbers
+of arguments. Perhaps the most common examples involve
+formatted strings:</para>
+        <programlisting>
+[NSClass stringWithFormat: "%f %f" x y]
+</programlisting>
+        <para>In Lisp, this would be written:</para>
+        <programlisting>
+(send (find-class 'ns:ns-string)
+      :string-with-format #@"%f %f"
+      (:double-float x :double-float y))
+</programlisting>
+        <para>Note that it's necessary to specify the foreign types of the
+variables (in this example, :double-float), because the
+compiler has no general way of knowing these types.  (You
+might think that it could parse the format string, but this
+would only work for format strings which are not determined
+at runtime.)</para>
+        <para>Because the ObjC runtime system does not provide any information
+on which messages are variable arity, they must be explicitly
+declared. The standard variable arity messages in Cocoa are
+predeclared by the bridge.  If you need to declare a new
+variable arity message, use
+(DEFINE-VARIABLE-ARITY-MESSAGE "myVariableArityMessage:").</para>
+      </sect2>
+
+      <sect2 id="Optimization">
+        <para>Optimization
+The bridge works fairly hard to optimize message sends, when
+it has enough information to do so.  There are two cases when
+it does.  In either, a message send should be nearly as
+efficient as when writing in Objective C.</para>
+        <para>The first case is when both the message
+and the receiver's class are known at
+compile-time. In general, the only way the receiver's class
+is known is if you declare it, which you can do with
+either a DECLARE or a THE form.  For example:</para>
+        <programlisting>
+(send (the ns:ns-window w) 'center)
+</programlisting>
+        <para>Note that there is no way in ObjC to name the class of a
+class.  Thus the bridge provides a declaration, @METACLASS.
+The
+type of an instance of "NSColor" is ns:ns-color.  The type of
+the <emphasis>class</emphasis>
+"NSColor" is (@metaclass ns:ns-color):</para>
+        <programlisting>
+(let ((c (find-class 'ns:ns-color)))
+  (declare ((ccl::@metaclass ns:ns-color) c))
+  (send c 'white-color))
+</programlisting>
+        <para>The other case that alllows optimization is when only the
+message is known at compile-time, but its type signature
+is unique. Of the more-than-6000 messages currently provided by
+Cocoa, only about 50 of them have nonunique type signatures.</para>
+        <para>An example of a message with a type signature that is not
+unique is SET.  It returns VOID for NSColor, but ID for NSSet.
+In order to optimize sends of messages with nonunique type
+signatures, the class of the receiver must be declared at
+compile-time.</para>
+        <para>If the type signature is nonunique or the message is unknown
+at compile-time, then a slower runtime call must be used.</para>
+        <para>When the receiver's class is unknown, the bridge's ability to
+optimize relies on a type-signature table which it maintains.
+When first loaded, the bridge initializes this table
+by scanning every method of every ObjC class.  When new methods
+are defined later, the table must be updated.  This happens
+automatically when you define methods in Lisp.  After any
+other major change, such as loading an external framework,
+you should rebuild the table:</para>
+        <programlisting>
+? (update-type-signatures)
+</programlisting>
+        <para>Because <literal>send</literal> and its relatives
+<literal>send-super</literal>,
+<literal>send/stret</literal>, and
+<literal>send-super/stret</literal> are macros, they cannot
+be <literal>funcall</literal>ed, <literal>apply</literal>ed,
+or passed as arguments to functions.</para>
+        <para>To work around this,
+there are function equivalents to them:
+<literal>%send</literal>,
+<literal>%send-super</literal>,
+<literal>%send/stret</literal>, and
+<literal>%send-super/stret</literal>.  However, these
+functions should be used only when the macros will not do,
+because they are unable to optimize.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Defining-Objective-C-Classes">
+      <para>Defining Objective-C Classes
+You can define your own foreign classes, which can then be
+passed to foreign functions; the methods which you implement
+in Lisp will be made available to the foreign code as
+callbacks.</para>
+      <para>You can also define subclasses of existing classes, implementing
+your subclass in Lisp even though the parent class was in
+Objective C.  One such subclass is
+CCL::NS-LISP-STRING.
+It is also particularly useful to make subclasses of
+NS-WINDOW-CONTROLLER.</para>
+      <para>We can use the MOP to define new Objective-C classes,
+but we have to do something a little
+funny: the :METACLASS that we'd want to use in a DEFCLASS option
+generally doesn't exist until we've created the class (recall
+that ObjC classes have, for the sake of argument, unique and private
+metaclasses.) We can sort of sleaze our way around this by specifying
+a known ObjC metaclass object name as the value of
+the DEFCLASS :METACLASS object; the metaclass of the root class
+NS:NS-OBJECT, NS:+NS-OBJECT, makes a good choice. To make a subclass
+of NS:NS-WINDOW (that, for simplicity's sake, doesn't define any
+new slots), we could do:</para>
+      <programlisting>
+(defclass example-window (ns:ns-window)
+  ()
+  (:metaclass ns:+ns-object))
+</programlisting>
+      <para>That'll create a new ObjC class named EXAMPLE-WINDOW whose
+metaclass is the class named +EXAMPLE-WINDOW. The class will be an
+object of type OBJC:OBJC-CLASS, and the metaclass will be of type
+OBJC:OBJC-METACLASS.  EXAMPLE-WINDOW will be a subclass of
+NS-WINDOW.</para>
+
+      <sect2 id="Defining-classes-with-foreign-slots">
+        <para>Defining classes with foreign slots
+If a slot specification in an Objective-C class definition
+contains the keyword :FOREIGN-TYPE, the slot will be a "foreign
+slot" (i.e. an ObjC instance variable). Be aware that it is an
+error to redefine an ObjC class so that its foreign slots
+change in any way, and OpenMCL doesn't do anything consistent
+when you try to.</para>
+        <para>The value of the :FOREIGN-TYPE initarg should be a foreign type
+specifier. For example, if we wanted (for some reason) to define a
+subclass of NS:NS-WINDOW that kept track of the number of key events
+it had received (and needed an instance variable to keep that
+information in), we could say:</para>
+        <programlisting>
+(defclass key-event-counting-window (ns:ns-window)
+  ((key-event-count :foreign-type :int
+                    :initform 0
+                    :accessor window-key-event-count))
+  (:metaclass ns:+ns-object))
+</programlisting>
+        <para>Foreign slots are always SLOT-BOUNDP, and the initform
+above is redundant: foreign slots are initialized to binary 0.</para>
+      </sect2>
+
+      <sect2 id="Defining-classes-with-Lisp-slots">
+        <para>Defining classes with Lisp slots
+A slot specification in an ObjC class definition that doesn't
+contain the :FOREIGN-TYPE initarg defines a pretty-much normal lisp
+slot that'll happen to be associated with "an instance of a
+foreign class". For instance:</para>
+        <programlisting>
+(defclass hemlock-buffer-string (ns:ns-string)
+  ((hemlock-buffer :type hi::hemlock-buffer
+                   :initform hi::%make-hemlock-buffer
+                   :accessor string-hemlock-buffer))
+  (:metaclass ns:+ns-object))
+</programlisting>
+        <para>As one might expect, this has memory-management
+implications: we
+have to maintain an association between a MACPTR and a set of lisp
+objects (its slots) as long as the ObjC instance exists, and we have
+to ensure that the ObjC instance exists (does not have its -dealloc
+method called) while lisp is trying to think of it as a first-class
+object that can't be "deallocated" while it's still
+possible to reference it. Associating one or more lisp objects with a
+foreign instance is something that's often very useful; if you
+were to do this "by hand", you'd have to face many of the
+same memory-management issues.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Defining-Objective-C-Methods">
+      <para>Defining Objective-C Methods
+In ObjC, unlike in CLOS, every method belongs to some
+particular class.  This is probably not a strange
+concept to you, because C++ and Java do the same thing.
+When you use Lisp to define ObjC methods, it is only
+possible to define methods belonging to ObjC classes which
+have been defined in Lisp.</para>
+      <para>The macro <literal>define-objc-method</literal> is used
+for this.  As described in , the names
+of ObjC methods are broken into pieces, each piece followed
+by a parameter.  The types of all parameters must be explicitly
+declared.</para>
+      <para>Right now, I'm not sure how to formally describe the usage
+of define-objc-method, so I'm going to do it with some short
+examples.  Let us define a class to use in them:</para>
+      <programlisting>
+(defclass data-window-controller (ns:ns-window-controller)
+  ((window :foreign-type :id :accessor window)
+   (data :initform nil :accessor data))
+  (:metaclass ns:+ns-object))
+</programlisting>
+      <para>There's nothing special about this class.
+It inherits from ns:ns-window-controller.
+It has two slots: <literal>window</literal> is a
+foreign slot, stored in the ObjC world; and
+<literal>data</literal> is an ordinary slot, stored in
+the Lisp world.</para>
+      <para>Here is an example of how to define a method which takes
+no arguments.  It happens to be an initialization method,
+but that's not important:</para>
+      <programlisting>
+ (define-objc-method ((:id get-window)
+                     data-window-controller)
+  (window self))
+</programlisting>
+      <para>The return type of this method is the foreign type :id, which
+is used for all ObjC objects.
+The name of the method is
+<literal>get-window</literal>.  The body of the method is
+the single line (window self).  The variable
+<literal>self</literal> is bound, within the body, to the
+instance which is receiving the message.  The call to
+<literal>window</literal>
+uses the CLOS accessor to get the value of the window field.</para>
+      <para>Here's an example which takes a parameter.  Notice that
+the name of the method without a parameter was an ordinary
+symbol, but with a parameter, it's a keyword:</para>
+      <programlisting>
+(define-objc-method ((:id :init-with-multiplier (:int multiplier))
+                     data-window-controller)
+  (setf (data self) (make-array 100))
+  (dotimes (i 100)
+    (setf (aref (data self) i)
+          (* i multiplier)))
+  self)
+</programlisting>
+      <para>To Objective-C code which uses the class, the name of this
+method is "initWithMultiplier:".  The name of the parameter
+is <literal>multiplier</literal>, and its type is :int.
+The body of the method
+does some meaningless things.  Then it returns
+<literal>self</literal>, because
+this is an initialization method.</para>
+      <para>Here's an example with more than one parameter:</para>
+      <programlisting>
+(define-objc-method ((:id :init-with-multiplier (:int multiplier)
+                          :and-addend (:int addend))
+                     data-window-controller)
+  (setf (data self) (make-array size))
+  (dotimes (i 100)
+    (setf (aref (data self) i)
+          (+ (* i multiplier)
+             addend)))
+  self)
+</programlisting>
+      <para>To Objective-C, the name of this method is
+"initWithMultiplier:andAddend:".  Both parameters are
+of type :int; the first is named <literal>multiplier</literal>,
+and the second is <literal>addend</literal>.  Again, the
+method returns <literal>self</literal>.</para>
+      <para>Here is a method which does not return any value, a so-called
+"void method".  Where our other methods said :id, this one says
+:void for the return type:</para>
+      <programlisting>
+(define-objc-method ((:void :take-action (:id sender))
+                     data-window-controller)
+  (declare (ignore sender))
+  (dotimes (i 100)
+    (setf (aref (data self) i)
+          (- (aref (data self) i)))))
+</programlisting>
+      <para>This method would be called "takeAction:" in ObjC.
+The convention for methods that are going to be used as Cocoa
+actions is that they take one parameter, which is the object
+responsible for triggering the action.  However, this method
+doesn't actually need to use that parameter, so it explicitly
+ignores it to avoid a compiler warning.  As promised, the
+method doesn't return any value.</para>
+      <para>There is also an alternate syntax, illustrated here.  The following two method definitions are equivalent:</para>
+      <programlisting>
+(define-objc-method ("applicationShouldTerminate:"
+                     "LispApplicationDelegate")
+                    (:id sender :<BOOL>)
+  (declare (ignore sender))
+  nil)
+
+(define-objc-method ((:<BOOL>
+                      :application-should-terminate sender)
+                     lisp-application-delegate)
+  (declare (ignore sender))
+  nil)
+</programlisting>
+      <sect2 id="Method-Redefinition-Constraints">
+        <para>Method Redefinition Constraints
+Objective C was not designed, as Lisp was, with runtime
+redefinition in mind.  So, there are a few constraints about
+how and when you can replace the definition of an Objective C
+method.  Currently, if you break these rules, nothing will
+collapse, but the behaviour will be confusing; so don't.</para>
+        <para>Objective C methods can be redefined at runtime, but their
+signatures shouldn't change.  That is, the types of the arguments
+and the return type have to stay the same.  The reason for this
+is that changing the signature changes the selector which is used
+to call the method.</para>
+        <para>When a method has already been defined in one class, and you
+define it in a subclass, shadowing the original method, they
+must both have the same type signature.  There is no such
+constraint, though, if the two classes aren't related and the
+methods just happen to have the same name.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="How-Objective-C-Names-are-Mapped-to-Lisp-Symbols">
+      <para>How Objective-C Names are Mapped to Lisp Symbols
+There is a standard set of naming conventions for Cocoa classes,
+messages, etc.  As long as they are followed, the bridge is fairly
+good at automaticallly translating between ObjC and Lisp names.</para>
+      <para>For example, "NSOpenGLView" becomes ns:ns-opengl-view;
+"NSURLHandleClient" becomes ns:ns-url-handle-client; and
+"nextEventMatchingMask:untilDate:inMode:dequeue:" becomes
+(:next-event-matching-mask :until-date :in-mode :dequeue).
+What a mouthful.</para>
+      <para>To see how a given ObjC or Lisp name will be translated by the
+bridge, you can use the following functions:</para>
+      <colspec>
+        <thead cols="1">
+          <tbody colwidth="100*"></tbody>
+          <row>
+            <abstract>
+              <entry>(ccl::objc-to-lisp-classname string)</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>(ccl::lisp-to-objc-classname symbol)</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>(ccl::objc-to-lisp-message string)</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>(ccl::lisp-to-objc-message string)</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>(ccl::objc-to-lisp-init string)</entry>
+            
+            </abstract>
+            <abstract>
+              <entry>(ccl::lisp-to-objc-init keyword-list)</entry>
+            
+            </abstract>
+          </row>
+        </thead>
+      </colspec>
+      <para>Of course, there will always be exceptions to any naming convention.
+Please tell us on the mailing lists if you come across any
+name translation problems
+that seem to be bugs.  Otherwise, the bridge provides two ways of
+dealing with exceptions:</para>
+      <para>First, you can pass a string as the class name of
+MAKE-OBJC-INSTANCE and as the message to SEND.  These strings will
+be directly interpreted as ObjC names, with no translation. This
+is useful for a one-time exception.  For example:</para>
+      <programlisting>
+(ccl::make-objc-instance "WiErDclass")
+(ccl::send o "WiErDmEsSaGe:WithARG:" x y)
+</programlisting>
+      <para>Alternatively, you can define a special translation rule for your
+exception.  This is useful for an exceptional name that you need
+to use througout your code.  Some examples:</para>
+      <programlisting>
+(ccl::define-classname-translation "WiErDclass" wierd-class)
+(ccl::define-message-translation "WiErDmEsSaGe:WithARG:" (:weird-message :with-arg))
+(ccl::define-init-translation "WiErDiNiT:WITHOPTION:" (:weird-init :option))
+</programlisting>
+      <para>The normal rule in ObjC names is that each word begins with a
+capital letter (except possibly the first).  Using this rule
+literally, "NSWindow" would be translated as N-S-WINDOW, which
+seems wrong.  "NS" is a special word in ObjC that should not be
+broken at each capital letter. Likewise "URL", "PDF", "OpenGL",
+etc. Most common special words used in Cocoa are already defined
+in the bridge, but you can define new ones as follows:</para>
+      <programlisting>
+(ccl::define-special-objc-word "QuickDraw")
+</programlisting>
+      <para>Note that message keywords in a SEND such as
+(SEND V :MOUSE P :IN-RECT R) may
+look like the keyword arguments in a Lisp function call, but they
+really aren't. All keywords must be
+present and the order is significant. Neither (:IN-RECT :MOUSE) nor
+(:MOUSE) translate to "mouse:inRect:"</para>
+      <para>Also, as a special exception, an "init" prefix is optional in the
+initializer keywords, so
+(MAKE-OBJC-INSTANCE 'NS-NUMBER :INIT-WITH-FLOAT 2.7) can also
+be expressed as
+(MAKE-OBJC-INSTANCE 'NS-NUMBER :WITH-FLOAT 2.7)</para>
+    </sect1>
+  </chapter>
+
+  <chapter id="Using-OpenMCL-with-Mac-OS-X--the-Darwin-Kernel--and-the-Cocoa-GUI-API">
+    <para>Using OpenMCL with Mac OS X, the Darwin Kernel,  and the Cocoa GUI API</para>
+
+    <sect1 id="Differences-in-OpenMCL-between-Darwin-and-MacOS-X">
+      <para>Differences in OpenMCL between Darwin and MacOS X
+Most of the documentation and whatever experience you may have in using OpenMCL under LinuxPPC should apply to using it under Darwin/MacOS X. There are some differences between the platforms, and these differences are sometimes exposed in the implementation.</para>
+
+      <sect2 id="FASL-file-segregation-">
+        <para>FASL file segregation.
+99% of the compiled lisp code in the two implementations is
+identical. Since both implementations target the PowerPC, this
+shouldn't be too surprising.</para>
+        <para>The other 1% - code which deals with foreign functions or data or
+which deals directly with the operating system - is very different but
+superficially similar. The effects of running such code compiled for
+the wrong platform range from harmless to catastrophic.</para>
+        <para>During bootstrapping, the 1% proved troublesome enough that it seemed
+wise to strictly separate the two implementations.</para>
+        <para>FASL files have different file types (.dfsl for Darwin, .pfsl for
+LinuxPPC) and contain different identifying information; it's not
+possible to successfully load FASL files compiled for one
+implementation into the other.</para>
+        <para>I think that it's wise to maintain this distinction; I spent a lot
+less time recompiling the 99% of "non-troublesome" code than I'd been
+spending tracking down bugs caused by the other 1%.</para>
+      </sect2>
+
+      <sect2 id="File-system-case">
+        <para>File-system case
+Darwin and MacOS X use HFS+ file systems by default; HFS+ file systems
+are case-insensitive. Most of OpenMCL's filesystem and pathname code
+assumes that the underlying filesystem is case-sensitive; this
+assumption extends to functions like EQUAL, which assumes that #p"FIXTHIS"
+and #p"foo" denote different, un-EQUAL filenames. Since Darwin/MacOS X
+can also use UFS and NFS filesystems, the opposite assumption would be
+no more correct than the one that's currently made.</para>
+        <para>Whatever the best solution to this problem turns out to be, there are
+some practical considerations. Doing:</para>
+        <programlisting>
+? (save-application "DPPCCL")
+</programlisting>
+        <para>has the unfortunate side-effect of trying to overwrite the Darwin
+OpenMCL kernel, "dppccl", on a case-insensitive filesystem.</para>
+        <para>To work around this, the Darwin OpenMCL kernel expects the default
+heap image file name to be the kernel's own filename with the string
+".image" appended, so the idiom would be:</para>
+        <programlisting>? (save-application "dppccl.image")
+</programlisting>
+      </sect2>
+
+      <sect2 id="Line-Termination-Characters">
+        <para>Line Termination Characters
+MacOSX effectively supports two distinct line-termination
+conventions. Programs in its Darwin substrate follow the Unix
+convention of recognizing #\LineFeed as a line terminator; traditional
+MacOS programs use #\Return for this purpose.</para>
+        <para>OpenMCL follows the Unix convention on both Darwin and LinuxPPC,
+but offers (as of version 0.11) some support for reading and writing
+files that use the MacOS convention as well.</para>
+        <para>This support (and anything like it) is by nature heuristic: it
+can successfully hide the distinction between newline conventions
+much of the time, but could mistakenly change the meaning of
+otherwise correct programs (typically when files contain both
+#\Return and #\Linefeed characters or when files contain mixtures of
+text and binary data.) Because of this concern, the default settings
+of some of the variables that control newline translation and
+interpretation are somewhat conservative.</para>
+        <para>Although the issue of multiple newline conventions primarily
+affects MacOSX users, the functionality described here is available
+under LinuxPPC as well (and may occasionally be useful there.)</para>
+        <para>None of this addresses issues related
+to the third newline convention ("CRLF") in widespread use
+(since that convention isn't native to any platform on which
+OpenMCL currently runs). If OpenMCL is ever ported to such a
+platform, that issue might be revisited.</para>
+        <para>Note that some MacOS programs (including some versions of
+commercial MCL) may use HFS file type information to recognize TEXT
+and other file types and so may fail to recognize files created with
+OpenMCL or other Darwin applications (regardless of line termination
+issues.)</para>
+        <para>Unless otherwise noted, the symbols mentioned in this
+documentation are exported from the CCL package.</para>
+      </sect2>
+
+      <sect2 id="Single-precision-trig---transcendental-functions">
+        <para>Single-precision trig &amp; transcendental functions
+Despite what Darwin's man pages say, early versions of its math library
+(up to and including OSX 10.2 (Jaguar) don't implement
+single-precision variants of the transcendental and trig functions
+(#_sinf, #_atanf, etc.) OpenMCL works around this by coercing
+single-precision args to double-precision, calling the
+double-precision version of the math library function, and coercing
+the result back to a SINGLE-FLOAT. These steps can introduce rounding
+errors (and potentially overflow conditions) that might not be present
+or as severe if true 32-bit variants were available.</para>
+      </sect2>
+
+      <sect2 id="Shared-libraries">
+        <para>Shared libraries
+Darwin/MacOS X distinguishes between "shared libraries" and "bundles"
+or "extensions"; Linux doesn't. In Darwin, "shared libraries" have the
+file type "dylib" : the expectation is that this class of file is
+linked against when executable files are created and loaded by the OS
+when the executable is launched. The latter class -
+"bundles/extensions" - are expected to be loaded into and unloaded
+from a running application, via a mechanism like the one used by
+OpenMCL's OPEN-SHARED-LIBRARY function.</para>
+        <para>OpenMCL wants to treat all shared libs as if they were "bundles"; this
+is presumably possible, but none of it's implemented under OpenMCL
+0.10. Ideally, whatever gets implemented will hide the distinction as
+much as possible, but it may not be possible to hide it completely.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Unix-Posix-Darwin-Features">
+      <para>Unix/Posix/Darwin Features
+OpenMCL has several convenience functions which allow you to
+make Posix (portable Unix) calls without having to use the
+foreign-function interface.  Each of these corresponds directly
+to a single Posix function call, as it might be made in C.  There
+is no attempt to make these calls correspond to Lisp idioms, such as
+<literal>setf</literal>.  This means that their behaviour is
+simple and predictable.</para>
+      <para>For working with environment variables, there are
+CCL::GETENV and CCL::SETENV.</para>
+      <para>For working with user and group IDs, there are
+CCL::GETUID, CCL::SETUID,
+and CCL::SETGID.  To find the home directory
+of an arbitrary user, as set in the user database (/etc/passwd),
+there is CCL::GET-USER-HOME-DIR.</para>
+      <para>For process IDs, there
+is CCL::GETPID.</para>
+      <para>For the <literal>system()</literal> function, there is
+CCL::OS-COMMAND.  Ordinarily, it is better -
+both more efficient and more predictable - to use the features
+described in .  However,
+sometimes you may want to specifically ask the shell to invoke a
+command for you.</para>
+    </sect1>
+
+    <sect1 id="Cocoa-Programming-in-OpenMCL">
+      <para>Cocoa Programming in OpenMCL
+Cocoa is one of Apple's APIs for GUI programming; for most purposes,
+development is considerably faster with Cocoa than with the
+alternatives.  You should have a little familiarity with it, to
+better understand this section.</para>
+      <para>A small sample Cocoa program can be invoked by evaluating (REQUIRE
+'TINY) and then (CCL::TINY-SETUP). This program provides a simple
+example of using several of the bridge's capabilities.</para>
+      <para>The Tiny demo creates Cocoa objects dynamically, at runtime, which is
+always an option.  However, for large applications, it is usually more
+convenient to create your objects with Apple Interface Builder, and
+store them in .nib files to be loaded when needed.  Both approaches
+can be freely mixed in a single program.</para>
+
+      <sect2 id="The-Command-Line-and-the-Window-System">
+        <para>The Command Line and the Window System
+OpenMCL is ordinarily a command-line application (it doesn't have a
+connection to the OSX Window server, doesn't have its own menubar or
+dock icon, etc.) By opening some libraries and jumping through some
+hoops, it's able to sort of transform itself into a full-fledged GUI
+application (while retaining its original TTY-based listener.) The
+general idea is that this hybrid environment can be used to test and
+protoype UI ideas and the resulting application can eventually be
+fully transformed into a bundled, double-clickable application. This
+is to some degree possible, but there needs to be a bit more
+infrastructure in place before many people would find it easy.</para>
+        <para>Cocoa applications use the NSLog function to write
+informational/warning/error messages to the application's standard
+output stream. When launched by the Finder, a GUI application's
+standard output is diverted to a logging facility that can be
+monitored with the Console application (found in
+/Applications/Utilities/Console.app).  In the hybrid environment, the
+application's standard output stream is usually the initial listener's
+standard output stream. With two different buffered stream mechanisms
+trying to write to the same underlying Unix file descriptor, it's not
+uncommon to see NSLog output mixed with lisp output on the initial
+listener.</para>
+      </sect2>
+
+      <sect2 id="Writing--and-reading--Cocoa-code">
+        <para>Writing (and reading) Cocoa code
+The syntax of the constructs used to define Cocoa classes and methods
+has changed a bit (it was never documented outside of the source code
+and never too well documented at all), largely as the result of
+functionality offered by Randall Beer's bridge; the &ldquo;standard
+name-mapping conventions&rdquo; referenced below are described in his
+CocoaBridgeDoc.txt file, as are the constructs used to invoke (&ldquo;send
+messages to&rdquo;) Cocoa methods.</para>
+        <para>All of the symbols described below are currently internal to
+the CCL package.</para>
+        <colspec>
+          <thead cols="1">
+            <tbody colwidth="100*"></tbody>
+            <row>
+              <abstract>
+                <entry>CCL::@CLASS</entry>
+              
+              </abstract>
+              <abstract>
+                <entry>CCL::@SELECTOR</entry>
+              
+              </abstract>
+              <abstract>
+                <entry>CCL::DEFINE-OBJC-METHOD</entry>
+              
+              </abstract>
+              <abstract>
+                <entry>CCL::DEFINE-OBJC-CLASS-METHOD</entry>
+              
+              </abstract>
+            </row>
+          </thead>
+        </colspec>
+      </sect2>
+
+      <sect2 id="The-Application-Kit-and-Multiple-Threads">
+        <para>The Application Kit and Multiple Threads
+The Cocoa API is broken into several pieces.  The Application Kit,
+affectionately called AppKit, is the one which deals with window
+management, drawing, and handling events.  AppKit really wants all
+these things to be done by a "distinguished thread".  creation, and
+drawing to take place on a distinguished thread.</para>
+        <para>Apple has published some guidelines which discuss these issues in some
+detail; see
+the Apple Multithreading Documentation, and in particular the guidelines
+on
+Using the Application Kit from Multiple Threads.  The upshot is that there
+can sometimes be unexpected behavior when objects are created in
+threads other than the distinguished event thread; eg, the event
+thread sometimes starts performing operations on objects that haven't
+been fully initialized.</para>
+        <para>It's certainly more convenient to do certain types of exploratory
+programming by typing things into a listener or evaluating a &ldquo;defun&rdquo;
+in an Emacs buffer; it may sometimes be necessary to be aware of this
+issue while doing so.</para>
+        <para>Each thread in the Cocoa runtime system is expected to maintain a
+current &ldquo;autorelease pool&rdquo; (an instance of the NSAutoreleasePool
+class); newly created objects are often added to the current
+autorelease pool (via the -autorelease method), and periodically the
+current autorelease pool is sent a &ldquo;-release&rdquo; message, which causes
+it to send &ldquo;-release&rdquo; messages to all of the objects that've been
+added to it.</para>
+        <para>If the current thread doesn't have a current autorelease pool, the
+attempt to autorelease any object will result in a severe-looking
+warning being written via NSLog. The event thread maintains an
+autorelease pool (it releases the current pool after each event is
+processed and creates a new one for the next event), so code that only
+runs in that thread should never provoke any of these severe-looking
+NSLog messages.</para>
+        <para>To try to suppress these messages (and still participate in the Cocoa
+memory management scheme), each listener thread (the initial listener
+and any created via the &ldquo;New Listener&rdquo; command in the IDE) is given
+a default autorelease pool; there are REPL colon-commands for
+manipulating the current listener's &ldquo;toplevel auturelease pool&rdquo;.</para>
+        <para>In the current scheme, every time that Cocoa calls lisp code, a lisp
+error handler is established which maps any lisp conditions to ObjC
+exceptions and arranges that this exception is raised when the
+callback to lisp returns. Whenever lisp code invokes a Cocoa method,
+it does so with an ObjC exception handler in place; this handler maps
+ObjC exceptions to lisp conditions and signals those conditions.</para>
+        <para>Any unhandled lisp error or ObjC exception that occurs during the
+execution of the distinguished event thread's event loop causes a
+message to be NSLog'ed and the event loop to (try to) continue
+execution. Any error that occurs in other threads is handled at the
+point of the outermost Cocoa method invocation. (Note that the error
+is not necessarily &ldquo;handled&rdquo; in the dynamic context in which it
+occurs.)</para>
+        <para>Both of these behaviors could possibly be improved; both of them
+seem to be substantial improvements over previous behaviors (where,
+for instance, a misspelled message name typically terminated the
+application.)</para>
+      </sect2>
+
+      <sect2 id="Acknowledgement--2-">
+        <para>Acknowledgement
+The Cocoa bridge was originally developed, and generously contributed
+by, Randal Beer.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Building-an-Application-Bundle">
+      <para>Building an Application Bundle
+You may have noticed that (require "COCOA") takes a long time to load.
+It is possible to avoid this by saving a Lisp heap image which has
+everything already loaded.  There is an example file which allows you
+to do this, "ccl/examples/cocoa-application.lisp", by producing a
+double-clickable application which runs your program.  First, load
+your own program.  Then, do:</para>
+      <programlisting>
+? (require "COCOA-APPLICATION")
+</programlisting>
+      <para>When it finishes, you should be able to double-click the OpenMCL icon
+in the ccl directory, to quickly start your program.</para>
+      <para>The OS may have already decided that OpenMCL.app isn't a valid
+executable bundle, and therefore won't let you double-click it.
+If this happens to you, to force it to reconsider, just update the
+last-modified time of the bundle.  In Terminal:</para>
+      <programlisting>> touch OpenMCL.app
+</programlisting>
+      <para>There is one important caveat.</para>
+      <para>Because of the way that the ObjC bridge currently works, a saved
+image is dependent upon the <emphasis>exact</emphasis> versions of
+the Cocoa libraries which were present when it was saved.
+Specifically, the interface database is.  So, for example, an
+application produced under OS X 10.3.5 will not work under
+OS X 10.3.6.  This is inconvenient when you wish to distribute an
+application you have built this way.</para>
+      <para>Work in this direction is ongoing.  It is worth looking at the project
+"Bosco", by Mikel Evins, which is a template that can be used to build
+application bundles in a different way.  It is
+available here, as part
+of the "Clotho" project, and there is
+here.</para>
+      <para>When an image which had contained ObjC classes (which are also
+CLOS classes) is re-launched, those classes are "revived": all
+preexisting classes have their addresses updated destructively, so that
+existing subclass/superclass/metaclass relationships are maintained.
+It's not possible (and may never be) to preserve foreign
+instances across SAVE-APPLICATION. (It may be the case that NSArchiver
+and NSCoder and related classes offer some approximation of that.)</para>
+    </sect1>
+
+    <sect1 id="Recommended-Reading">
+      <para>Recommended Reading</para>
+      <term><indexterm>Cocoa Documentation
+          <variablelist>This is the top page for all of Apple's documentation onCocoa.  If you are unfamiliar with Cocoa, it is a goodplace to start.</variablelist>
+        </indexterm><indexterm>Foundation Reference for Objective-C
+          <variablelist>This is one of the two most important Cocoa references; itcovers all of the basics, except for GUI programming.  This isa reference, not a tutorial.</variablelist>
+        </indexterm><indexterm>Application Kit Reference for Objective-C
+          <variablelist>This is the other; it covers GUI programming with Cocoain considerable depth.  This is a reference, not a tutorial.</variablelist>
+        </indexterm><indexterm>Apple Developer Documentation
+          <variablelist>This is the site which the above two documents are found on;go here to find the documentation on any other Apple API.Also go here if you need general guidance about OS X, Carbon,Cocoa, Core Foundation, or Objective C.</variablelist>
+        </indexterm>
+      </term>
+    </sect1>
+
+    <sect1 id="Operating-System-Dictionary">
+      <para>Operating-System Dictionary</para>
+
+      <sect2 id="CCL--GETENV">
+        <para>CCL::GETENV</para>
+        <informalfigure>getenv</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::GETENV &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+getenv name => value
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>name
+            <variablelist>a string which is the name of an existingenvironment variable;case-sensitive</variablelist>
+          </indexterm><indexterm>value
+            <variablelist>if there is an environment variable named<literal>name</literal>, its value, as a string; if thereis not, NIL</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Looks up the value of the environment variable named by
+<literal>name</literal>, in the OS environment.</para>
+      </sect2>
+
+      <sect2 id="CCL--SETENV">
+        <para>CCL::SETENV</para>
+        <informalfigure>setenv</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::SETENV &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+setenv name value => errno
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>name
+            <variablelist>a string which is the name of a new or existingenvironment variable;case-sensitive</variablelist>
+          </indexterm><indexterm>value
+            <variablelist>a string, to be the new value of theenvironment variablenamed by <literal>name</literal></variablelist>
+          </indexterm><indexterm>errno
+            <variablelist>zero if the function call completes successfully;otherwise, a platform-dependent integer which describesthe problem</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Sets the value of the environment variable named by
+<literal>name</literal>, in the OS environment.  If there is
+no such environment
+variable, creates it.</para>
+      </sect2>
+
+      <sect2 id="CCL--CURRENT-DIRECTORY-NAME">
+        <para>CCL::CURRENT-DIRECTORY-NAME</para>
+        <informalfigure>current-directory-name</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::CURRENT-DIRECTORY-NAME &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+current-directory-name
+	  => path
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>path
+            <variablelist>a string, an absolute pathname in Posix format - withdirectory components separated by slashes</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Looks up the current working directory of the OpenMCL process;
+unless it has been changed, this is the directory OpenMCL was
+started in.</para>
+      </sect2>
+
+      <sect2 id="CCL--GETUID">
+        <para>CCL::GETUID</para>
+        <informalfigure>getuid</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::GETUID &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+getuid => uid
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>uid
+            <variablelist>a non-negative integer, identifying a specific useraccount as defined in the OS user database</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the ("real") user ID of the current user.</para>
+      </sect2>
+
+      <sect2 id="CCL--SETUID">
+        <para>CCL::SETUID</para>
+        <informalfigure>setuid</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::SETUID &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+setuid uid => errno
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>uid
+            <variablelist>a non-negative integer, identifying a specific useraccount as defined in the OS user database</variablelist>
+          </indexterm><indexterm>errno
+            <variablelist>zero if the function call completes successfully;otherwise, a platform-dependent integer which describesthe problem</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Attempts to change the current user ID (both "real" and
+"effective"); fails unless
+the OpenMCL process has super-user privileges or the ID
+given is that of the current user.</para>
+      </sect2>
+
+      <sect2 id="CCL--SETGID">
+        <para>CCL::SETGID</para>
+        <informalfigure>setgid</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::SETGID &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+setgid gid => errno
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>gid
+            <variablelist>a non-negative integer, identifying a specificgroup as defined in the OS user database</variablelist>
+          </indexterm><indexterm>errno
+            <variablelist>zero if the function call completes successfully;otherwise, a platform-dependent integer which describesthe problem</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Attempts to change the current group ID (both "real" and
+"effective"); fails unless
+the OpenMCL process has super-user privileges or the ID
+given is that of a group to which the current user belongs.</para>
+      </sect2>
+
+      <sect2 id="CCL--GETPID">
+        <para>CCL::GETPID</para>
+        <informalfigure>getpid</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::GETPID &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+getpid => pid
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>pid
+            <variablelist>a non-negative integer, identifying an OS process</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the ID of the OpenMCL OS process.</para>
+      </sect2>
+
+      <sect2 id="CCL--GET-USER-HOME-DIR">
+        <para>CCL::GET-USER-HOME-DIR</para>
+        <informalfigure>get-user-home-dir</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::GET-USER-HOME-DIR &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+get-user-home-dir
+	  uid => path
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>uid
+            <variablelist>a non-negative integer, identifying a specific useraccount as defined in the OS user database</variablelist>
+          </indexterm><indexterm>path
+            <variablelist>a string, an absolute pathname in Posix format - withdirectory components separated by slashes; or NIL</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Looks up and returns the defined home directory of the user
+identified by <literal>uid</literal>.  This value comes from the
+OS user database, not from the <literal>$HOME</literal>
+environment variable.  Returns NIL if there is no user with
+the ID <literal>uid</literal>.</para>
+      </sect2>
+
+      <sect2 id="CCL--OS-COMMAND">
+        <para>CCL::OS-COMMAND</para>
+        <informalfigure>os-command</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::OS-COMMAND &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+os-command command-line
+	  => exit-code
+</programlisting>
+        <bridgehead renderas="sect3">Values</bridgehead>
+        <term><indexterm>command-line
+            <variablelist>a string, obeying all the whitespace andescapingconventions required by the user's default system shell</variablelist>
+          </indexterm>
+        </term>
+        <term><indexterm>exit-code
+            <variablelist>a non-negative integer, returned as the exitcode of a subprocess; zero indicates success</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Invokes the Posix function <literal>system()</literal>, which
+invokes the user's default system shell (such as
+sh or tcsh) as a new process, and has that shell execute
+<literal>command-line</literal>.</para>
+        <para>If the shell was able to find the command specified in
+<literal>command-line</literal>, then <literal>exit-code</literal>
+is the exit code of that command.  If not, it is the exit
+code of the shell itself.</para>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para>By convention, an exit code of 0 indicates success.  There are
+also other conventions; unfortunately, they are OS-specific, and
+the portable macros to decode their meaning are implemented
+by the system headers as C preprocessor macros.  This means
+that there is no good, automated way to make them available
+to Lisp.</para>
+      </sect2>
+
+      <sect2 id="CCL----CLASS">
+        <para>CCL::@CLASS</para>
+        <informalfigure>@class</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::@CLASS &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+@class class-name
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>class-name
+            <variablelist>a string which denotes an existing class name, or asymbol which can be mapped to such a string via the standardname-mapping conventions for class names</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Used to refer to a known ObjC class by name. (Via the use
+LOAD-TIME-VALUE, the results of a class-name -> class lookup
+are cached.)</para>
+        <para><literal>@class</literal> is obsolete as of late 2004, because
+find-class now works on ObjC classes.  It is described here
+only because some old code still uses it.</para>
+      </sect2>
+
+      <sect2 id="CCL----SELECTOR">
+        <para>CCL::@SELECTOR</para>
+        <informalfigure>@selector</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::@SELECTOR &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+@selector string
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>string
+            <variablelist>a string constant, used to canonically refer to anObjC method selector</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Used to refer to an ObjC method selector (method name). Uses
+LOAD-TIME-VALUE to cache the result of a string -> selector
+lookup.</para>
+      </sect2>
+
+      <sect2 id="CCL--DEFINE-OBJC-METHOD">
+        <para>CCL::DEFINE-OBJC-METHOD</para>
+        <informalfigure>define-objc-method</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::DEFINE-OBJC-METHOD &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+define-objc-method
+	    (selector class-name) &amp;body body
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>selector
+            <variablelist>either a string which represents the name of theselector or a list which describ+es the method's returntype, selector components, and argument types (see below.)If the first form is used, then the first form in the bodymust be a list which describes the selector's argumenttypes and return value type, as per DEFCALLBACK.</variablelist>
+          </indexterm><indexterm>class-name
+            <variablelist>either a string which names an existing ObjC classname or a list symbol which can map to such a string via thestandard name-mapping conventions for class names. (Notethat the "canonical" lisp class name is such asymbol)</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Defines an ObjC-callable method which implements the
+specified message selector for instances of the existing ObjC
+class class-name.</para>
+      </sect2>
+
+      <sect2 id="CCL--DEFINE-OBJC-CLASS-METHOD">
+        <para>CCL::DEFINE-OBJC-CLASS-METHOD</para>
+        <informalfigure>define-objc-class-method</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::DEFINE-OBJC-CLASS-METHOD &mdash;</para>
+        <para>Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+define-objc-class-method
+	    (selector class-name) &amp;body body
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <para>As per DEFINE-OBJC-METHOD</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Like DEFINE-OBJC-METHOD, only used to define methods on the
+<emphasis>class</emphasis> named by class-name and on its
+subclasses.</para>
+        <para>For both DEFINE-OBJC-METHOD and DEFINE-OBJC-CLASS-METHOD, the
+"selector" argument can be a list whose first element is a
+foreign type specifier for the method's return value type and whose
+subsequent elements are either:</para>
+        <listitem mark="bullet">
+          <variablelist>a non-keyword symbol, which can be mapped to a selector stringfor a parameterless method according to the standard name-mappingconventions for method selectors.</variablelist>
+          <variablelist>a list of alternating keywords and variable/type specifiers,where the set of keywords can be mapped to a selector string for aparameteriezed method according to the standard name-mappingconventions for method selectors and each variable/type-specifier iseither a variable name (denoting a value of type :ID) or a list whoseCAR is a variable name and whose CADR is the correspondingargument's foreign type specifier.</variablelist>
+        
+        </listitem>
+      </sect2>
+
+      <sect2 id="CCL--ALTERNATE-LINE-TERMINATOR-">
+        <para>CCL:*ALTERNATE-LINE-TERMINATOR*</para>
+        <informalfigure>*alternate-line-terminator*</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL:*ALTERNATE-LINE-TERMINATOR* &mdash;</para>
+        <para>Variable</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>This variable is currently only used by the standard reader macro
+function for #\; (single-line comments); that function reads successive
+characters until EOF, a #\NewLine is read, or a character EQL to the
+value of *alternate-line-terminator* is read. In OpenMCL for Darwin, the
+value of this variable is initially #\Return ; in OpenMCL for LinuxPPC,
+it's initially NIL.</para>
+        <para>Their default treatment by the #\; reader macro is the primary way
+in which #\Return and #\Linefeed differ syntactally; by extending the
+#\; reader macro to (conditionally) treat #\Return as a
+comment-terminator, that distinction is eliminated. This seems to make
+LOAD and COMPILE-FILE insensitive to line-termination issues in many
+cases. It could fail in the (hopefully rare) case where a LF-terminated
+(Unix) text file contains embedded #\Return characters, and this
+mechanism isn't adequate to handle cases where newlines are embedded
+in string constants or other tokens (and presumably should be translated
+from an external convention to the external one) : it doesn't change
+what READ-CHAR or READ-LINE "see", and that may be necessary to
+handle some more complicated cases.</para>
+      </sect2>
+
+      <sect2 id="iEXTERNAL-FORMAT">
+        <para>:EXTERNAL-FORMAT</para>
+        <informalfigure>:external-format</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>:EXTERNAL-FORMAT &mdash;</para>
+        <para>Keyword Argument</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Per ANSI CL, OpenMCL supports the :EXTERNAL-FORMAT keyword
+argument to the functions OPEN, LOAD, and COMPILE-FILE. This argument is
+intended to provide a standard way of providing implementation-dependent
+information about the format of files opened with an element-type of
+CHARACTER. This argument can meaningfully take on the values :DEFAULT
+(the default), :MACOS, :UNIX, or :INFERRED in OpenMCL.</para>
+        <para>When defaulted to or specified as :DEFAULT, the format of the file
+stream is determined by the value of the variable
+CCL:*DEFAULT-EXTERNAL-FORMAT*. See below.</para>
+        <para>When specified as :UNIX, all characters are read from and written
+to files verbatim.</para>
+        <para>When specified as :MACOS, all #\Return characters read from the
+file are immediately translated to #\Linefeed (#\Newline); all #\Newline
+(#\Linefeed) characters are written externally as #\Return characters.</para>
+        <para>When specified as :INFERRED and the file is open for input, the
+first bufferful of input data is examined; if a #\Return character
+appears in the buffer before the first #\Linefeed, the file stream's
+external-format is set to :MACOS; otherwise, it is set to :UNIX.</para>
+        <para>All other values of :EXTERNAL-FORMAT - and any combinations that
+don't make sense, such as trying to infer the format of a
+newly-created output file stream - are treated as if :UNIX was
+specified. As mentioned above, the :EXTERNAL-FORMAT argument doesn't
+apply to binary file streams.</para>
+        <para>The translation performed when :MACOS is specified or inferred has
+a somewhat greater chance of doing the right thing than the
+*alternate-line-terminator* mechanism does; it probably has a somewhat
+greater chance of doing the wrong thing, as well.</para>
+      </sect2>
+
+      <sect2 id="CCL--DEFAULT-EXTERNAL-FORMAT-">
+        <para>CCL:*DEFAULT-EXTERNAL-FORMAT*</para>
+        <informalfigure>*default-external-format*</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL:*DEFAULT-EXTERNAL-FORMAT* &mdash;</para>
+        <para>Variable</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>The value of this variable is used when :EXTERNAL-FORMAT is
+unspecified or specified as :DEFAULT. It can meaningfully be given any
+of the values :UNIX, :MACOS, or :INFERRED, each of which is interpreted
+as described above.</para>
+        <para>Because there's some risk that unsolicited newline translation
+could have undesirable consequences, the initial value of this variable
+in OpenMCL is :UNIX.</para>
+      </sect2>
+
+      <sect2 id="CCL--NS-LISP-STRING">
+        <para>CCL::NS-LISP-STRING</para>
+        <informalfigure>ns-lisp-string</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CCL::NS-LISP-STRING &mdash;</para>
+        <para>Class</para>
+        <bridgehead renderas="sect3">Superclasses</bridgehead>
+        <para>NS:NS-STRING</para>
+        <bridgehead renderas="sect3">Initargs</bridgehead>
+        <term><indexterm>:string
+            <variablelist>a Lisp string which is to be the content ofthe newly-created ns-lisp-string.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>This class
+implements the interface of an NSString, which means that it can
+be passed to any Cocoa or Core Foundation function which expects
+one.</para>
+        <para>The string itself is stored on the Lisp heap, which
+means that its memory management is automatic.  However, the
+ns-lisp-string object itself is a foreign
+object (that is, it has an objc metaclass), and resides on the
+foreign heap.  Therefore, it is necessary to explicitly free
+it, by sending a dealloc message.</para>
+        <bridgehead renderas="sect3">Examples</bridgehead>
+        <para>You can create an ns-lisp-string with
+<literal>make-instance</literal>, just like
+any normal Lisp class:</para>
+        <programlisting>
+? (defvar *the-string*
+          (make-instance 'ccl::ns-lisp-string
+                         :string "Hello, Cocoa."))
+</programlisting>
+        <para>When you are done with the string, you must explicitly
+deallocate it:</para>
+        <programlisting>
+? (ccl::send *the-string* 'dealloc)
+</programlisting>
+        <para>You may wish to use an <literal>unwind-protect</literal>
+form to ensure that this happens:</para>
+        <programlisting>
+(let (*the-string*)
+  (unwind-protect (progn (setq *the-string*
+                               (make-instance 'ccl::ns-lisp-string
+                                              :string "Hello, Cocoa."))
+                         (format t "~&amp;The string is ~D characters long.~%"
+                                 (ccl::send *the-string* 'length)))
+    (when *the-string*
+      (ccl::send *the-string* 'dealloc))))
+</programlisting>
+        <bridgehead renderas="sect3">Notes</bridgehead>
+        <para>Currently, ns-lisp-string is defined in
+the file ccl/examples/cocoa-backtrace.lisp, which is a
+rather awkward place.  It was probably not originally meant
+as a public utility at all.  It would be good if it were
+moved someplace else.  Use at your own risk.</para>
+      </sect2>
+    </sect1>
+  </chapter>
+
+  <chapter id="Understanding-and-Configuring-the-Garbage-Collector">
+    <para>Understanding and Configuring the Garbage Collector</para>
+
+    <sect1 id="Heap-space-allocation">
+      <para>Heap space allocation
+Release 0.10 or later of OpenMCL uses a different memory management
+scheme than previous versions did. Those earlier versions would allocate a
+block of memory (of specified size) at startup and would allocate lisp
+objects within that block. When that block filled with live (non-GCed)
+objects, the lisp would signal a "heap full" condition. The heap
+size imposed a limit on the size of the largest object that could be
+allocated.</para>
+      <para>The new strategy involves reserving a very large (2GB on DarwinPPC32,
+1GB on LinuxPPC, "very large" on 64-bit implementations) block at
+startup and consuming (and relinquishing) its contents as the size of
+the live lisp heap data grows and shrinks. After the initial heap image
+loads and after each full GC, the lisp kernel will try to ensure that a
+specified amount (the "lisp-heap-gc-threshold") of free memory is
+available. The inital value of this kernel variable is 16MB on 32-bit
+implementations and 32MB on 64-bit implementations ; it can be
+manipulated from Lisp (see below.)</para>
+      <para>The large reserved memory block consumes very little in the way of
+system resources; memory that's actually committed to the lisp heap
+(live data and the "threshold" area where allocation takes place)
+consumes finite resources (physical memory and swap space). The lisp's
+consumption of those resources is proportional to its actual memory usage,
+which is generally a good thing.</para>
+      <para>This scheme is much more flexible than the old one, but it may also
+increase the possibility that those resources can become exhausted.
+Neither the new scheme nor the old handles that situation gracefully;
+under the old scheme, a program that consumes lots of memory may have run
+into an artificial limit on heap size before exhausting virtual memory.</para>
+      <para>The -R or &ndash;heap-reserve command-line option can be use to limit the
+size of the reserved block and therefore bound heap expansion. Running</para>
+      <programlisting>
+> openmcl --heap-reserve 8M
+</programlisting>
+      <para>would provide an execution environment that's very similar to
+that provided by earlier OpenMCL versions.</para>
+    </sect1>
+
+    <sect1 id="The-Ephemeral-GC">
+      <para>The Ephemeral GC
+For many programs, the following observations are true to a very
+large degree:</para>
+      <varlistentry numeration="arabic">
+        <variablelist>Most heap-allocated objects have very short lifetimes ("areephemeral"): they become inaccessible soon after they're created.</variablelist>
+        <variablelist>Most non-ephemeral objects have very long lifetimes: it'srarely productive for the GC to consider reclaiming them, sinceit's rarely able to do so. (An object that's survived a largenumber of GCs is likely to survive the next one. That's not alwaystrue of course, but it's a reasonable heuristic.)</variablelist>
+        <variablelist>It's relatively rare for an old object to be destructivelymodified (via SETF) so that it points to a new one, therefore mostreferences to newly-created objects can be found in the stacks andregisters of active threads. It's not generally necessary to scanthe entire heap to find references to new objects (or to prove thatsuch references don't exists), though it is necessary to keeptrack of the (hopefully exceptional) cases where old objects aremodified to point at new ones.</variablelist>
+      </varlistentry>
+      <para>"Ephemeral" (or "generational") garbage collectors try to exploit
+these observations: by concentrating on frequently reclaiming
+newly-created objects quickly, it's less often necessary to do more
+expensive GCs of the entire heap in order to reclaim unreferenced memory.
+In some environments, the pauses associated with such full GCs can be
+noticable and disruptive, and minimizing the frequency (and sometimes the
+duration) of these pauses is probably the EGC's primary goal (though
+there may be other benefits, such as increased locality of reference and
+better paging behavior.) The EGC generally leads to slightly longer
+execution times (and slightly higher, amortized GC time), but there are
+cases where it can improve overall performance as well; the nature and
+degree of its impact on performance is highly application-dependant.</para>
+      <para>Most EGC strategies (including the one employed by OpenMCL)
+logically or physically divide memory into one or more areas of relatively
+young objects ("generations") and one or more areas of old objects.
+Objects that have survived one or more GCs as members of a young
+generation are promoted (or "tenured") into an older generation, where
+they may or may not survive long enough to be promoted to the next
+generation and eventually may become "old" objects that can only be
+reclaimed if a full GC proves that there are no live references to them.
+This filtering process isn't perfect - a certain amount of premature
+tenuring may take place - but it usually works very well in practive.</para>
+      <para>It's important to note that a GC of the youngest generation is
+typically very fast (perhaps a few milliseconds on a modern CPU, depending
+on various factors), OpenMCL's EGC is not concurrent and doesn't
+offer realtime guarantees.</para>
+      <para>OpenMCL's EGC maintains three ephemeral
+generations; all newly created objects are created as members of the
+youngest generation. Each generation has an associated
+<emphasis>threshold</emphasis>, which indicates the number of bytes in it
+and all younger generations that can be allocated before a GC is
+triggered. These GCs will involve the target generation and all younger
+ones (and may therefore cause some premature tenuring); since the older
+generations have larger thresholds, they're GCed less frequently and
+most short-lived objects that make it into an older generation tend not to
+survive there very long.</para>
+      <para>The EGC can be <emphasis>enabled</emphasis> or <emphasis>disabled</emphasis>
+under program control; under some circumstances, it may be enabled but
+<emphasis>inactive</emphasis> (because a full GC is imminent.) Since it
+may be hard to know or predict the consing behavior of other threads, the
+distinction between the "active" and "inactive" state isn't very
+meaningful, especially when native threads are involved.</para>
+    </sect1>
+
+    <sect1 id="GC-Page-reclamation-policy">
+      <para>GC Page reclamation policy</para>
+      <para>After a full GC finishes, it'll try to ensure that at least
+(LISP-HEAP-GC-THRESHOLD) of virtual memory are available; objects will be
+allocated in this block of memory until it fills up, the GC is triggered,
+and the process repeats itself.</para>
+      <para>Many programs reach near stasis in terms of the amount of logical
+memory that's in use after full GC (or run for long periods of time in
+a nearly static state), so the logical address range used for consing
+after the Nth full GC is likely to be nearly or entirely identical to the
+address range used by the N+1th full GC.</para>
+      <para>By default (and traditionally in OpenMCL), the GC's policy is to
+"release" the pages in this address range: to advise the virtual memory
+system that the pages contain garbage and any physical pages associated
+with them don't need to be swapped out to disk before being reused and
+to (re-)map the logical address range so that the pages will be
+zero-filled by the virtual memory system when they're next accessed.
+This policy is intended to reduce the load on the VM system and keep
+OpenMCL's working set to a minimum.</para>
+      <para>For some programs (especially those that cons at a very high rate),
+the default policy may be less than ideal: releasing pages that're
+going to be needed almost immediately - and zero-fill-faulting them back
+in, lazily - incurs unnecessary overhead. (There's a false economy
+associated with minimizing the size of the working set if it's just
+going to shoot back up again until the next GC.) A policy of "retaining"
+pages between GCs might work better in such an environment.</para>
+      <para>Functions described below give the user some control over this
+behavior. An adaptive, feedback-mediated approach might yield a better
+solution.</para>
+    </sect1>
+
+    <sect1 id="iPure--areas-are-read-only--paged-from-image-file">
+      <para>"Pure" areas are read-only, paged from image file
+SAVE-APPLICATION identifies code vectors and the pnames of interned
+symbols and copies these objects to a "pure" area of the image
+file it creates. (The "pure" area accounts for most of what the
+ROOM function reports as "static" space.)</para>
+      <para>When the resulting image file is loaded, the pure area of the file
+is now memory-mapped with read-only access. Code and pure data are paged
+in from the image file as needed (and don't compete for global virtual
+memory resources with other memory areas.)</para>
+      <para>Code-vectors and interned symbol pnames are immutable : it is an
+error to try to change the contents of such an object. Previously, that
+error would have manifested itself in some random way. In the new scheme,
+it'll manifest itself as an "unhandled exception" error in the
+Lisp kernel. The kernel could probably be made to detect a spurious,
+accidental write to read-only space and signal a lisp error in that case,
+but it doesn't yet do so.</para>
+      <para>The image file should be opened and/or mapped in some mode which
+disallows writing to the memory-mapped regions of the file from other
+processes. I'm not sure of how to do that; writing to the file when
+it's mapped by OpenMCL can have unpredictable and unpleasant results.
+SAVE-APPLICATION will delete its output file's directory entry and
+create a new file; one may need to exercise care when using file system
+utilities (like tar, for instance) that might overwrite an existing image
+file.</para>
+    </sect1>
+
+    <sect1 id="Weak-Hash-Tables">
+      <para>Weak Hash Tables
+In general, a "weak reference" is a reference to an object which
+will not prevent the object from being garbage-collected.  For
+example, suppose that you want to keep a list of all the objects
+of a certain type.  If you don't take special steps, the fact that
+you have a list of them will mean that the objects are always
+"live", because you can always reference them through the list.
+Therefore, they will never be garbage-collected, and their memory
+will never be reclaimed, even if they are referenced nowhere else
+in the program.  You may want this behaviour.  If you don't, you
+need weak references.</para>
+      <para>OpenMCL supports weak references with "weak hash tables".
+Hash tables may be weak with respect to either their keys or
+their values.  To make a hash table with weak keys, invoke
+<literal>make-hash-table</literal> with the option :weak t,
+or, equivalently, :weak :key.  To make one with weak values,
+use :weak :value.  When the key is weak, the equality test
+must be #'eq (because it wouldn't make sense otherwise).</para>
+      <para>When garbage-collection occurs, key-value pairs are removed
+from the hash table if there are no other references to the
+weak element of the pair (key or value).</para>
+      <para>In general, weak-key hash tables are useful when you want to
+use the hash to store some extra information about the objects
+you look up in it, while weak-value hash tables are useful when you
+want to use the hash as an index for looking up objects.</para>
+      <para>If you are experimenting with weak hash tables interactively, remember
+that an object is not dead if it was returned by one of the last
+three interactively-evaluated expressions, because of the variables
+<literal>*</literal>, <literal>**</literal>, and
+<literal>***</literal>.  The easy workaround is to evaluate some
+meaningless expression before invoking <literal>gc</literal>,
+to get the object out of the repl variables.</para>
+    </sect1>
+
+    <sect1 id="Garbage-Collection-Dictionary">
+      <para>Garbage-Collection Dictionary</para>
+
+      <sect2 id="LISP-HEAP-GC-THRESHOLD">
+        <para>LISP-HEAP-GC-THRESHOLD</para>
+        <informalfigure>lisp-heap-gc-threshold</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>LISP-HEAP-GC-THRESHOLD &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+lisp-heap-gc-threshold
+</programlisting>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns the value of the kernel variable that specifies the
+amount of free space to leave in the heap after full GC.</para>
+      </sect2>
+
+      <sect2 id="SET-LISP-HEAP-GC-THRESHOLD">
+        <para>SET-LISP-HEAP-GC-THRESHOLD</para>
+        <informalfigure>set-lisp-heap-gc-threshold</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SET-LISP-HEAP-GC-THRESHOLD &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    lisp-heap-gc-threshold new-threshold
+
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>new-value
+            <variablelist>The requested new lisp-heap-gc-threshold.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Sets the value of the kernel variable that specifies the
+amount of free space to leave in the heap after full GC to
+new-value, which should be a non-negative fixnum. Returns the
+value of that kernel variable (which may be somewhat larger than
+what was specified).</para>
+      </sect2>
+
+      <sect2 id="USE-LISP-HEAP-GC-THRESHOLD">
+        <para>USE-LISP-HEAP-GC-THRESHOLD</para>
+        <informalfigure>use-lisp-heap-gc-threshold</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>USE-LISP-HEAP-GC-THRESHOLD &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+
+	    use-lisp-heap-gc-threshold
+
+</programlisting>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Tries to grow or shrink lisp's heap space, so that the
+free space is (approximately) equal to the current heap threshold.
+Returns NIL</para>
+      </sect2>
+
+      <sect2 id="EGC">
+        <para>EGC</para>
+        <informalfigure>egc</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>EGC &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+egc arg
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>arg
+            <variablelist>a generalized boolean</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Enables the EGC if arg is non-nil, disables the EGC
+otherwise. Returns the previous enabled status. Although this
+function is thread-safe (in the sense that calls to it are
+serialized), it doesn't make a whole lot of sense to be
+turning the EGC on and off from multiple threads ...</para>
+      </sect2>
+
+      <sect2 id="EGC-ENABLED-P">
+        <para>EGC-ENABLED-P</para>
+        <informalfigure>egc-enabled-p</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>EGC-ENABLED-P &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+egc-enabled-p
+</programlisting>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns T if the EGC was enabled at the time of the call,
+NIL otherwise.</para>
+      </sect2>
+
+      <sect2 id="EGC-ACTIVE-P">
+        <para>EGC-ACTIVE-P</para>
+        <informalfigure>egc-active-p</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>EGC-ACTIVE-P &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+egc-active-p
+</programlisting>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns T if the EGC was active at the time of the call, NIL
+otherwise. Since this is generally a volatile piece of
+information, it's not clear whether this function serves a
+useful purpose when native threads are involved.</para>
+      </sect2>
+
+      <sect2 id="EGC-CONFIGURATION">
+        <para>EGC-CONFIGURATION</para>
+        <informalfigure>egc-configuration</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>EGC-CONFIGURATION &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+egc-configuration
+</programlisting>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns, as multiple values, the sizes in kilobytes of the
+thresholds associated with the youngest ephemeral generation, the
+middle ephemeral generation, and the oldest ephemeral generation</para>
+      </sect2>
+
+      <sect2 id="CONFIGURE-EGC">
+        <para>CONFIGURE-EGC</para>
+        <informalfigure>configure-egc</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>CONFIGURE-EGC &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+configure-egc
+	  generation-0-size generation-1-size
+	  generation-2-size
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>generation-0-size
+            <variablelist>the requested threshold size of the youngestgeneration, in kilobytes</variablelist>
+          </indexterm><indexterm>generation-1-size
+            <variablelist>the requested threshold size of the middle generation,in kilobytes</variablelist>
+          </indexterm><indexterm>generation-2-size
+            <variablelist>the requested threshold size of the oldest generation,in kilobytes</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>If the EGC is currently disabled, puts the indicated
+threshold sizes in effect and returns T, otherwise, returns NIL.
+(The provided threshold sizes are rounded up to a multiple of
+64Kbytes in OpenMCL 0.14 and later, and to a multiple of 32KBytes in earlier
+versions.)</para>
+      </sect2>
+
+      <sect2 id="GC-RETAIN-PAGES">
+        <para>GC-RETAIN-PAGES</para>
+        <informalfigure>gc-retain-pages</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>GC-RETAIN-PAGES &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+gc-retain-pages arg
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>arg
+            <variablelist>a generalized boolean</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Tries to influence the GC to retain/recycle the pages
+allocated between GCs if arg is true, and to release them
+otherwise. This is generally a tradeoff between paging and other
+VM considerations.</para>
+      </sect2>
+
+      <sect2 id="GC-RETAINING-PAGES">
+        <para>GC-RETAINING-PAGES</para>
+        <informalfigure>gc-retaining-pages</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>GC-RETAINING-PAGES &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+gc-retaining-pages
+</programlisting>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns T if the GC tries to retain pages between full GCs
+and NIL if it's trying to release them to improve VM paging
+performance.</para>
+      </sect2>
+    </sect1>
+  </chapter>
+
+  <chapter id="Implementation-Details-of-OpenMCL">
+    <para>Implementation Details of OpenMCL
+This chapter describes many aspects of OpenMCL's implementation as of
+(roughly) version 1.1.  Details vary a bit between the three archutectures
+(PPC32, PPC64, and X86-64) currently supported and those details change
+over time, so the definitive reference is the source code (especially
+some files in the ccl/compiler/ directory whose names contain the string
+"arch" and some files in the ccl/lisp-kernel/ directory whose namee
+contain the string "constants".)  Hopefully, this chapter will make
+it easier for someone who's interested to read and understand the
+contents of those files.</para>
+
+    <sect1 id="Threads-and-exceptions">
+      <para>Threads and exceptions
+OpenMCL's threads are "native" (meaning that they're scheduled and
+controlled by the  operating system.)  Most of the implications of
+this are discussed elsewhere; this section tries to describe how
+threads look from the lisp kernel's perspective (and especailly
+from the GC's point of view.)</para>
+      <para>OpenMCL's runtime system tries to use machine-level exception
+mechanisms (conditional traps when available, illegal instructions,
+memory access protection in some cases) to detect and handle ...
+exceptional situations.  These situations include some TYPE-ERRORs
+and PROGRAM-ERRORS (notably wrong-number-of-args errors), and also
+include cases like "not being able to allocate memory without GCing
+or obtaining more memory from the OS."  The general idea is that
+it's usually faster to pay (very occasional) exception-processing
+overhead and figure out what's going on in an exception handler than
+it is to maintain enough state and context to handle an exceptional
+case via a lighter-weight mechanism when that exceptional case
+(by definition) rarely occurs.</para>
+      <para>Some emulated execution environments (the Rosetta PPC emulator on
+x86 versions of OSX) don't provide accurate exception information
+to exception handling functions. OpenMCL can't run in such environments.</para>
+
+      <sect2 id="The-Thread-Context-Record">
+        <para>The Thread Context Record
+When a lisp thread is first created (or when a thread created by
+foreign code first calls back to lisp), a data structure called
+a Thread Context Record (or TCR) is allocated and initialized.  On
+modern versions of Linux and FreeBSD, the allocation actually happens
+via a set of thread-local-storage ABI extensions, so a thread's
+TCR is created when the thread is created and dies when the thread
+dies.  (The World's Most Advanced Operating System - as Apple's
+marketing literature refers to Darwin -  is not very advanced in this
+regard, and I know of no reason to assume that advances will be made
+in this area anytime soon.)</para>
+        <para>A TCR contains a few dozen fields (and is therefore a few hundred
+bytes in size.)  The fields are mostly thread-specific information
+about the thread's stacks' locations and sizes, information about
+the underlying (POSIX) thread, and information about the thread's
+dynamic binding history and pending CATCH/UNWIND-PROTECTs.  Some
+of this information could be kept in individual machine registers
+while the thread is running (and the PPC - which has more registers
+available - keeps a few things in registers that the X86-64 has
+to access via the TCR), but it's important to remember that the
+information is thread-specific and can't (for instance) be kept
+in a fixed global memory location.</para>
+        <para>When lisp code is running, the current thread's TCR is kept in
+a register.  On PPC platforms, a general purpose register is used;
+on x86-64, an (otherwise nearly useless) segment register works
+well (prevents the expenditure of a more generally useful general-
+purpose register for this purpose.)</para>
+        <para>The address of a TCR is aligned in memory in such a way that a
+FIXNUM can be used to represent it.  The lisp function CCL::%CURRENT-TCR
+returns the calling thread's TCR as a fixnum; actual value of the
+TCR's address is 4 or 8 times the value of this fixnum.</para>
+        <para>When the lisp kernel initializes a new TCR, it's added to a global
+list maintained by the kernel; when a thread exits, its TCR is removed
+from this list.</para>
+        <para>When a thread calls foreign code, lisp stack pointers are saved in its
+TCR, lisp registers (at least those whose value should be preserved
+across the call) are saved on the thread's value stack, and (on x86-64)
+RSP is switched to the control stack.  A field in the TCR
+(tcr.valence) is then set to indicate that the thread is running foreigm
+code, foreign argument registers are loaded from a frame on the foreign
+stack, and the foreign function is called. (That's a little oversimplified
+and possibly inaccurate, but the important things to note are that the
+thread "stops following lisp stack and register usage conventions" and
+that it advertises the fact that it's done so.  Similar transitions in
+a thread's state ("valence") occur when it enters of exits an exception
+handler (which is sort of an OS/hardware-mandated foreign function call
+where the OS thoughtfully saves the thread's register state for it
+beforehand.)</para>
+      </sect2>
+
+      <sect2 id="Exception-contexts-comma---and-exception-handling-in-general">
+        <para>Exception contexts, and exception-handling in general
+Unix-like OSes tend to refer to exceptions as "signals"; the same
+general mechanism ("signal handling") is used to process both
+asynchronous OS-level events (such as the result of the keyboard driver
+noticing that ^C or ^Z has been pressed) and synchronous hardware-level
+events (like trying to execute and illegal instruction or access
+protected memory.)  It makes some sense to defer ("block") handling
+of aysnchronous signals so that some critical code sequences complete
+without interruption; since it's generally not possible for a thread
+to proceed after a synchronous exception unless and until its state
+is modified by an exception handler, it makes no sense to talk about
+blocking synchronous signals (though some OSes will let you do so
+and doing so can have mysterious effects.)</para>
+        <para>On OSX/Darwin, the POSIX signal handling facilities coexist with
+lower-level Mach-based exception handling facilities.  Unfortunately,
+the way that this is implemented interacts poorly with debugging
+tools: GDB will generally stop whenever the target program
+encounters a Mach-level exception and offers no way to proceed from
+that point (and let the program's POSIX signal handler try to handle
+the exception); Apple's CrashReporter program has had a similar issue
+and, depending on how it's configured, may bombard the user with
+alert dialogs which falsely claim that an application has crashed
+(when in fact the application in question has routinely handled
+a routine exception.)  On Darwin/OSX, OpenMCL uses Mach thread-level
+exception handling facilities which run before GDB or CrashReporter
+get a chance to confuse themeselves; OpenMCL's Mach exception handling
+tries to force the thread which received a synchronous exception to
+invoke a signal handling function ("as if" signal handling worked
+more usefully under Darwin.)  Mach exception handlers run in a dedicated
+thread (which basically does nothing but wait for exception messages
+from the lisp kernel, obtain and modify information about the state
+of threads in which exceptions have occurred, and reply to the
+exception messages with an indication that the exception has been
+handled.  The reply from a thread-level exception handler keeps the
+exception from being reported to GDB or CrashReporter and avoids
+the problems related to those programs.  Since OpenMCL's Mach exception
+handler doesn't claim to handle debugging-related exceptions (from
+breakpoints or single-step operations), it's possible to use GDB to
+debug OpenMCL.</para>
+        <para>On platforms where signal handling and debugging don't get in each
+other's way, a signal handler is entered with all signals blocked.
+(This behavior is specified in the call to the sigaction() function
+which established the signal handler.)  The signal handler recieves
+three arguments from the OS kernel; the first is an intger which
+identifies the signal, the second is a pointer to an object of
+type "siginfo_t", which may or may not contain a few fields that
+would help to identify the cause of the exception, and the third
+argument is a pointer to a data structure (called a "ucontext"
+or something similar) which contains machine-dependent information
+about the state of the tread at the time that the exception/signal
+occurred.  While asynchronous signals are blocked, the signal handler
+stores the pointer to its third argument (the "signal context") in
+a field in the current thread's TCR, sets some bits in another TCR
+field to indicate that the thread is now waiting to handle an
+exception, unblocks asynchronous signals, and waits for a global
+exception lock which serializes exception processing.</para>
+        <para>On Darwin, the Mach exception thread creates a signal context (and
+maybe a siginfo_t structure), stores the signal context in the
+thread's TCR, sets the TCR field wich describes the thread's state,
+and arranges that the thread resume execution at its signal handling
+function (with a signal handler, possibly NULL siginfo_t, and signal
+context as arguments.  When the thread resumes, it waits for the
+global exception lock.</para>
+        <para>On x86-64 platforms where signal handing can be used to handle
+synchronous exceptions, there's an additional complication: the
+OS kernel ordinarily allocates the signal context and siginfo
+structures on the stack of the thread which received the signal;
+in practice, that means "wherever RSP is pointing."  OpenMCL's
+ require that the
+thread's value stack - where RSP is usually pointing while lisp
+code is running - contain only "nodes" (properly tagged lisp
+objects), and scribbling a signal context all over the value
+stack would violate this requirement.  To maintain consistency,
+the sigaltstack() mechanism is used to cause the signal to be
+delivered on (and the signal context and siginfo to be allocated
+on) a special stack area (the last few pages of the thread's
+cntrol stack, in practice.  When the signal handler runs, it
+(carefully) copies the signal context and siginfo to the thread's
+control stack and makes RSP point into that stack before invoking
+the "real" signal handler.  (The effect of this hack is that the
+"real" signal handler always runs on the thread's control stack.)</para>
+        <para>Once the exception handler has obtained the global exception lock,
+it uses the values of the signal number, siginfo_t, and signal context
+arguments to determine the (logical) cause of the exception.  Some
+exceptions may be caused by factors that should generate lisp errors
+or other serious conditions (stack overflow); if this is the case,
+the kernel code may release the global exception lock and call out
+to lisp code.  (The lisp code in question may need to repeat some
+of the exception decoding process; in particular, it needs to be
+able to interpret register values in the signal context that it
+receives as an argument.)</para>
+        <para>In some cases, the lisp kernel exception handler may not be
+able to recover from the exception (this is currently true of
+some types of memory-access fault and is also true of traps
+or illegal instructions that occur during foreign code execution.
+In such cases, the kernel exception handler reports the
+exception as "unhandled", and the kernel debugger is invoked.</para>
+        <para>If the kernel exception handler identifies the exception' cause
+as being a transient out-of-memory condition (indicating that
+the current thread needs more memory to cons in), it tries to
+make that memory available.  In some cases, doing so involves
+invoking the GC.</para>
+      </sect2>
+
+      <sect2 id="Threads-comma---exceptions-comma---and-the-GC">
+        <para>Threads, exceptions, and the GC
+OpenMCL's GC is not concurrent: when the GC is invoked in response to an
+exception in a particular thread, all other lisp threads must stop until
+the GC's work is done.  The thread that triggered the GC iterates over
+the global TCR list, sending each other thread a distinguished "suspend"
+signal, then iterates over the list again, waiting for a per-thread
+semaphore that indicates that the thread has received the "suspend"
+signal and responded appropriatedly.  Once all other threads have
+acknowledged the request to suspend themselves, the GC thread can
+run the GC proper (after doing any necessary .)  Once
+the GC's completed its work, the thread that invoked the GC iterates
+over the global TCR list, raising a per-thread "resume" semaphore
+for each other thread.</para>
+        <para>The signal handler for the asynchronous "suspend" signal is entered
+with all asynchronous signals blocked.  It saves its signal-context
+argument in a TCR slot, raises the tcr's "suspend" semaphore, then
+waits on the TCR's "resume" semaphore.</para>
+        <para>The GC thread has access to the signal contexts of all TCRs (including
+its own) at the time when the thread received an exception or
+acknowledged a request to suspend itself.  This information (and
+information about stack areas in the TCR itself) allows the GC to
+identify the "stack locations and register contents" that are elements
+of the GC's root set.</para>
+      </sect2>
+
+      <sect2 id="PC-lusering">
+        <para>PC-luseringIt's not quite accurate to say that OpenMCL's compiler and runtime
+follow precise stack and register usage conventions at all times; there
+are a few exceptions:</para>
+        <listitem mark="bullet">
+          <variablelist>On both PPC and x86-64 platforms, consing isn't fully atomic.It takes at least a few instructions to allocate an object in memory(and slap a header on it if necesssary); if a thread is interrupted inthe middle of that instruction sequence, the new object may or may nothave been created or fully initialized at the point in time that theinterrupt occurred.  (There are actually a few different states ofpartial initialization)</variablelist>
+          <variablelist>On the PPC, the common act of building a lisp control stack frameinvolves allocating a four-word frame and storing three register valuesinto that frame.  (The fourth word - the back pointer to the previousframe - is automatically set when the frame is allocated.)  The previouscontents of those three words are unknown (there might have been aforeign stack frame at the same address a few instructions earlier),so interrupting a thread that's in the process of initializing aPPC control stack frame isn't GC-safe.</variablelist>
+          <variablelist>There are similar problems with the initialization of temp stackframes on the PPC.  (Allocation and initialization doesn't happenatomically, and the newly allocated stack memory may have undefinedcontents.)</variablelist>
+          <variablelist>'s write barrier has to be implemented atomically (i.e.,both an intergenerational store and the update of a correspondingreference bit has to happen without interruption, or neither of theseevents can happen.)</variablelist>
+          <variablelist>There are a few more similar cases.</variablelist>
+        
+        </listitem>
+        <para>Fortunately, the number of these non-atomic instruction sequences is
+small, and fortunately it's fairly easy for the interrupting thread
+to recognize when the interrupted thread is in the middle of such
+a sequence.  When this is detected, the interrupting thread modfies
+the state of the interrupted thread (modifying its PC and other
+registers) so that it is no longer in the middle of such a sequenece
+(it's either backed out of it or the remaining instructions are
+emulated.)</para>
+        <para>This works because (a) many of the troublesome instruction sequences
+are PPC-specific and it's relatively easy to partially disassemble the
+instructions surrounding the interrupted thread's PC on the PPC and
+(b) those instruction sequences are heavily stylized and intended to
+be easily recognized.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Register-usage-and-tagging">
+      <para>Register usage and tagging</para>
+
+      <sect2 id="Register-usage-and-tagging-overview">
+        <para>Register usage and tagging overview
+Regardless of other details of its implementation, a garbage
+collector's job is to partition the set of all heap-allocated
+lisp objects (CONSes, STRINGs, INSTANCEs, etc.) into two subsets.
+The first subset contains all objects that are transitively referenced
+from a small set of "root" objects (the contents of the stacks
+and registers of all active threads at the time the GC occurs
+and the values of some global variables.)  The second subset contains
+everything else: those lisp objects that are not transitively
+reachable from the roots are garbage, and the memory occupied
+by garbage objects can be reclaimed (since the GC has just proven
+that it's impossible to reference them.)</para>
+        <para>The set of live, reachable lisp objects basically form the nodes
+of a (usually large) graph, with edges from each node A to any other
+objects (nodes) that object A references.</para>
+        <para>Some nodes in this graph can never have outgoing edges: an array with a
+specialized numeric or character type usually represents its elements in
+some (possibly more compact) specialized way.  Some nodes may refer
+to lisp objects that are never allocated in memory (FIXNUMs, CHARACTERs,
+SINGLE-FLOATs on 64-bit platforms ..)  This latter class of objects
+are sometimes called "immediates", but that's a little confusing
+because the term "immediate" is sometimes used to refer to things
+that can never be part of the big connectivity graph (e.g., the "raw"
+bits that make up a floating-point value, foreign address, or
+numeric value that needs to be used - at least fleetingly - in
+compiled code.)</para>
+        <para>For the GC to be able to build the connectivity graph reliably, it's
+necessary for it to be able to reliably tell (a) whether or not a
+"potential root" - the contents of a machine register or stack location
+- is in fact a node and (b) for any node, whether it may have components
+that refer to other nodes.</para>
+        <para>There's no reliable way to answer the first question on stock hardware.
+(If everything was a node, as might be the case on specially microcoded
+"lisp machine" hardware, it wouldn't even need to be asked.)  Since
+there's no way to just look at a machine word (the contents of a machine
+register or stack location) and tell whether or not it's a node or just
+some random non-node value, we have to either adopt and enforce strict
+conventions on register and stack usage or tolerate ambiguity.</para>
+        <para>"Tolerating ambiguity" is an approach taken by some ("conservative") GC
+schemes; by contrast, OpenMCL's GC is "precise", which in this case
+means that it believes that the contents of certain machine registers
+and stack locations are always nodes and that other registers and stack
+locations are never nodes and that these conventions are never violated
+by the compiler or runtime system.  The fact that threads are
+preemptively scheduled means that a GC could occur (because of activity
+in some other thread) on any instruction boundary, which in turn means
+that the compiler and runtime system must follow precise  at all times.</para>
+        <para>Once we've decided that a given machine word is a node, a  describes how the node's value and type are encoded in that
+machine word.</para>
+        <para>Most of this - so far - has discussed thigs from the GC's very low-level
+perspective.  From a much higher point of view, lisp functions accept
+nodes as arguments, return nodes as values, and (usually) perform
+some operations on those arguments in order to produce those results.
+(In many cases, the operations in question involve raw non-node values.)
+Higher-level parts of the lisp type system (functions like TYPE-OF
+and CLASS-OF, etc.) depend on the .</para>
+      </sect2>
+
+      <sect2 id="pc-locatives-on-the-PPC">
+        <para>pc-locatives on the PPC
+On the PPC, there's a third case (besides "node" and "immediate" values).
+As discussed below, a node that denotes a memory-allocated lisp object
+is a biased (tagged) pointer -to- that object; it's not generally possible
+to point -into- some composite (multi-element) object (such a pointer
+would not be a node, and the GC would have no way to update the pointer
+if it were to move the underlying object.)</para>
+        <para>Such a pointer ("into" the interior of a heap-allocated object) is
+often called a <emphasis>locative</emphasis>; the cases where locatives are allowed
+in OpenMCL mostly involve the behavior of function call and return
+instructions.  (To be technicaly accurate, the other case also arises
+on x86-64, but that case isn't as user-visible.)</para>
+        <para>On the PowerPC (both PPC32 and PPC64), all machine instructions are
+32 bits wide and all instruction words are allocated on 32-bit boundaries.
+In PPC OpenMCL, a CODE-VECTOR is a specialized type of vector-like object;
+its elements are 32-bit PPC machine instructions.  A CODE-VECTOR is
+an attribute of FUNCTION object; a function call involves accessing the
+function's code-vector and jumping to the address of its first instruction.</para>
+        <para>As each instruction in the code vector sequentially executes, the
+hardware program counter (PC) register advances to the address of the
+next instruction (a locative into the code vector); since PPC
+instructions are always 32 bits wide and aligned on 32-bit boundaries,
+the low two bits of the PC are always 0.  If the function executes a
+call (simple call instrucions have the mnemonic "bl" on the PPC, which
+stands for "branch and link"), the address of the next instruction (also
+a word-aligned locative into a code-vector) is copied into the special-
+purpose PPC "link register" (lr); a function returns to its caller
+via a "branch to link register" (blr) instruction.  Some cases of
+function call and return might also use the PPC's "count register"
+(ctr), and if either the lr or ctr needs to be stored in memory it
+needs to first be copied to a general-purpose registers.</para>
+        <para>OpenMCL's GC understands that certain registers contain these special
+"pc-locatives" (locatives that point into CODE-VECTOR objects); it
+contains specal support for finding the containing CODE-VECTOR object
+and for adjusting all of these "pc-locatives" if the containing object
+is moved in memory.  The first part of that - finding the containing
+object - is possible and practical on the PPC because of architectural
+artifcacts (fixed-width instructions and arcana of instruction encoding.)
+It's not possible on x86-64, but fortunately not necessary either (though
+the second part - adjusting the PC/RIP when the containing object moves)
+is both necessary and simple.</para>
+      </sect2>
+
+      <sect2 id="Register-and-stack-usage-conventions">
+        <para>Register and stack usage conventions</para>
+
+        <sect3 id="Stack-conventions">
+          <para>Stack conventions
+On both PPC and X86 platforms, each lisp thread uses 3 stacks; the ways
+in which these stacks are used differs between the PPC and X86.</para>
+          <para>Each thread has:</para>
+          <listitem mark="bullet">
+            <variablelist>A "control stack".On both platforms, this is "the stack" used by foreign code.On the PPC, it consists of a linked list of frameswhere the first word in each frame points to the first word in theprevious frame (and the outermost frame points to 0.)  Some frameson a PPC control stack are lisp frames; lisp frames are always 4 wordsin size and contain (in addition to the back pointer to the previousframe) the calling function (a node), the return address (a "locative"into the calling function's code-vector), and the value to which thevalue-stack pointer (see below) should be restored on function exit.On the PPC, the GC has to look at control-stack frames, identifywhich of those frames are lisp frames, and treat the contents ofthe saved function slot as a node (and handle the return addresslocative specially.)On x86-64, the control stack is used for dynamic-extent allocationof immediate objects.  Since the control stack never contains nodeson x86-64, the GC ignores it on that platform.Alignment of the control stack follows the ABI conventions of theplatform (at least at any point in time where foreign code could run.)On PPC, the r1 register always points to the top of the current thread'scontrol stack; on x86-64, the RSP register points to the top of thecurrent thread's control stack when the thread is running foreigncode and the address of the top of the control stack is kept in thethread's TCR see  when not running foreigncode.The control stack "grows down."</variablelist>
+            <variablelist>A "value stack".On both platforms, all values on the value stack are nodes (including"tagged return addresses" on x86-64.)  The value stack is always alignedto the native word size; objects are always pushed on the value stackusing atomic instructions ("stwu"/"stdu" on PPC, "push" on x86-64), sothe contents of the value stack between its bottom and top are alwaysunambiguously nodes; the compiler usually tries to pop or discardnodes from the value stack as soon as possible after their last use(as soon as they may have become garbage.)On x86-64, the RSP register addresses the top of the value stackwhen running lisp code; that address is saved in the TCR whenrunning foreign code.On the PPC, a dedicated regiter (VSP, currently r15) is used toaddress the top of the value stack when running lisp code, and theVSP value is saved in the TCR when running foreign code.The value stack grows down.</variablelist>
+            <variablelist>A "temp stack".The temp stack consists of a linked list of frames, each of which pointsto the previous temp stack frame.  The number of native machine wordsin each temp stack frame is always even, so the temp stack is alignedon a two-word (64- or 128-bit) boundary.The temp stack is used for dynamic-extent objects on both platforms;on the PPC, it's used for essentially all such objects (regardlessof whether or not the objects contain nodes); on the x86-64, immediatedynamic-extent objects (strings, foreign pointers, etc.) are allocatedon the control stack and only node-containing dynamic-extent objectsare allocated on the temp stack.Data structures used to implement CATCH and UNWIND-PROTECT are stored onthe temp stack on both ppc and x86-64.Temp stack frames are always doublenode aligned and objects withina temp stack frame are aligned on doublenode boundaries.  The firstword in each frame contains a back pointer to the previous frame; onthe PPC, the second word is used to indicate to the GC whethe theremaining objects are nodes (if the second word is 0) or immediate(otherwise.)  On x86-64, where temp stack frames always contain nodes,the second word is always 0.The temp stack grows down.  It usually takes several instuctions toallocate and safely initialize a temp stack frame that's intended tocontain nodes, and the GC has to recognize the case where a threadis in the process of allocating and initializing a temp stack frameand take care not to interpret any uninitialized words in the frameas nodes.  See .The PPC keeps the current top of the temp stack in a dedicated register(TSP, currently r12) when running lisp code and saves this register'svalue in the TCR when running foreign code.  The x86-64 keeps theaddress of the top of each thread's temp stack in the thread's TCR.</variablelist>
+          
+          </listitem>
+        </sect3>
+
+        <sect3 id="Register-conventions">
+          <para>Register conventions
+If there are a "reasonable" (for some value of "reasonable") number or
+general-purpose registers and the instruction set is "reasonably"
+orthogonal (most instructions that operate on GPRs can operate on any
+GPR), then it's possible to statically partition the GPRs into at least
+two sets: "immediate registers" never contain nodes, and "node registers"
+always contain nodes.  (On the PPC, a few registers are members of a
+third set of "PC locatives", and on both platforms some registers may
+have dedicated roles as stack or heap pointers; the latter class is
+treated as immediates by the GC proper but may be used to help determine
+the bounds of stack and heap memory areas.)</para>
+          <para>The ultimate definition of register partitioning is hardwired
+into the GC in functions like "mark_xp()" and "forward_xp()", which
+process the values of some of the registers in an exception frame
+as nodes and may give some sort of special treatment to other register
+values they encounter there.)</para>
+          <para>On x86-64, the static register partitioning scheme involves:</para>
+          <listitem mark="bullet">
+            <variablelist>(only) two "immediate" registers.The RAX and RDX registers are used as the implicit operands andresults of some extended-precision multiply and divide instructionswhich generally involve non-node values; since their use in theseinstructions means that they can't be guaranteed to contain nodevalues at all times, it's natural to put these registers in the"immediate" set.  RAX is generally given the symbolic name "imm0",and RDX is given the symbolic name "imm1"; you may see these namesin disassembled code, usually in operations involving type checking,array indexing, and foreign memory and function access.</variablelist>
+            <variablelist>(only) two "dedicated" registers.RSP and RBP have dedicated functionality dictated by the hardwareand calling conventions.  (There are a few places where RBP istemporarily used as an extra immediate register.)</variablelist>
+            <variablelist>12 "node" registers.All other registers (RBX, RCX, RSI, RDI, and R8-R15) are asserted tocontain node values at (almost) all times; legacy "string" operationsthat implicitly use RSI and/or RDI are not used.  Shift and rotateintructions which shift/rotate by a variable number of bits arerequired by the architecture to use the low byte of RCX (the traditionalCL register) as the implicit shift count; when it's necessary to keepa non-node shift count in the low byte of RCX, the upper 7 bytes ofthe register are zeroed (so that misinterpetation of the immediatevalue in RCX as a node will not have negative GC affects.  (The GCmight briefly treate it as a node, but since it's not pointing anywherenear the lisp heap it'll soon lose interest in it.)Legacy instructions that use RCX (or some portions of it) as a loopcounter can not be used (since such instructions might introducenon-node values into RCX.)</variablelist>
+          
+          </listitem>
+          <para>On the PPC, the static register partitioning scheme involves:</para>
+          <listitem mark="bullet">
+            <variablelist>6 "immediate" registersRegisters r3-r8 are given the symbolic names imm0-imm5.  As a RISCarchitecture with simpler addressing modes, the PPC probably usesimmediate registers a bit more often than the CISC x86-64 does, butthey're generally used for the same sort of things (type checking,array indexing, FFI, etc.)</variablelist>
+            <variablelist>9 dedicated registers
+              <listitem mark="bullet">
+                <variablelist>r0 (symbolic name rzero) always contains the value 0 when runninglisp code.  Its value is sometimes read as 0 when it's used as thebase register in a memory address; keeping the value 0 there issometimes convenient and avoids asymmetry.</variablelist>
+                <variablelist>r1 (symbolic name sp) is the control stack pointer, by PPC convention.</variablelist>
+                <variablelist>r2 is used to hold the current thread's TCR on ppc64 systems; it'snot used on ppc32.</variablelist>
+                <variablelist>r9 and r10 (symbolic names allocptr and allocbase) are used to do per-thread memory allocation</variablelist>
+                <variablelist>r11 (symbolic name nargs) contains the number of function arguments on entry and the number of return values in multiple-value returning constructs.  It's not used more generally as either a node or immediate register because of the way that certain trap instruction encodings are interpreted.</variablelist>
+                <variablelist>r12 (symbolic name tsp) holds the top of the current thread's temp stack.</variablelist>
+                <variablelist>r13 is used to hold the TCR on PPC32 sytems; it's not used on PPC64.</variablelist>
+                <variablelist>r14 (symbolic name loc-pc) is used to copy "pc-locative" values between main memory and special-purpose PPC registers (LR and CTR) used in function-call and return instructions.</variablelist>
+                <variablelist>r15 (symbolic name vsp) addresses the top of the current thread's value stack.</variablelist>
+                <variablelist>lr and ctr are PPC branch-unit registers used in function call and return instructions; they're always treated as "pc-locatives", which precludes the use of the ctr in some PPC looping constructs.</variablelist>
+              
+              </listitem>
+</variablelist>
+            <variablelist>17 "node" registersr15-r31 are always treated as node registers</variablelist>
+          
+          </listitem>
+        </sect3>
+      </sect2>
+
+      <sect2 id="Tagging-scheme">
+        <para>Tagging schemeOpenMCL always allocates lisp objects on double-node (64-bit for 32-bit
+platforms, 128-bit for 64-bit platforms) boundaries; this mean that the
+low 3 bits (32-bit lisp) or 4 bits (64-bit lisp) are always 0 and are
+therefore redundant (we only really need to know the upper 29 or 60 bits
+in order to identify the aligned object address.)  The extra bits in a
+lisp node can be used to encode at least some information about the
+node's type, and the other 29/60 bits represent either an immediate
+value or a doublenode-aligned memory address.  The low 3 or 4 bits of a
+node are called the node's "tag bits", and the conventions used to
+encode type information in those tag bits are called a "tagging scheme."</para>
+        <para>It might be possible to use the same tagging scheme on all platforms (at
+least on all platforms with the same word size and/or the same number of
+available tag bits), but there are often some strong reasons for not
+doing so.  These arguments tend to be very machine-specific: sometimes,
+there are fairly obvious machine-dependent tricks that can be exploited
+to make common operations on some types of tagged objects faster; other
+times, there are architectural restrictions that make it impractical to
+use certain tags for certain types.  (On PPC64, the "ld" (load
+doubleword) and "std" (store doubleword) instructions - which load and
+store a GPR operand at the effective address formed by adding the value
+of another GPR operand and a 16-bit constant operand - require that the
+low two bits of that constant operand be 0.  Since such instructions
+would typically be used to access the fields of things like CONS cells
+and structures, it's desirable that that the tags chosen for CONS cells
+and structures allow the use of these intructions as opposed to more
+expensive alternatives.)</para>
+        <para>One architecture-dependent tagging trick that works well on all
+architectures is to use a tag of 0 for FIXNUMs: a fixnum basically
+encodes its value shifted left a few bits and keeps those low bits
+clear. FIXNUM addition, subtraction, and binary logical operations can
+operate directly on the node operands, addition and subtraction can
+exploit hardware-based overflow detection, and (in the absence of
+overflow) the hardware result of those operations is a node (fixnum).
+Some other slightly-less-common operations may require a few extra
+instructions, but arithmetic operations on FIXNUMs should be as
+cheap as possible and using a tag of zero for FIXNUMs helps to
+ensure that it will be.</para>
+        <para>If we have N available tag bits (N = 3 for 32-bit OpenMCL and N = 4
+for 64-bit OpenMCL), this way of representing fixnums with the low
+M bits forced to 0 works as long as M <= N.  The smaller we make
+M, the larger the values of MOST-POSITIVE-FIXNUM and MOST-NEGATIVE
+become; the larger we make N, the more distinct non-FIXNUM tags
+become available.  A reasonable compromise is to choose M = N-1;
+this basically yields two distinct FIXNUM tags (one for even
+fixnums, one for odd fixnums), gives 30-bit fixnums on 32-bit
+platforms and 61-bit fixnums on 64-bit platforms, and leaves us
+with 6 or 14 tags to encoded other types.</para>
+        <para>Once we get past the assignment of FIXNUM tags, things quickly devolve
+into machine-dependencies.  We can fairly easily see that we can't
+directly all other primitive lisp object types with only 6 or 14
+available tag values; the details of how types are encoded vary between
+the ppc32, ppc64, and x86-64 implementations, but there are some general
+common principles:</para>
+        <listitem mark="bullet">
+          <variablelist>CONS cells always contain exactly 2 elements and are usually fairly common.It therefore makes sense to give CONS cells their own tag.  Unlike thefixnum case - where a tag value of 0 had positive implications - theredoesn't seem to be any advantage to using any particular value.  (A longtime ago - in the case of 68K MCL - the CONS tag and the order of CARand CDR in memory were chosen to allow smaller, cheaper addressing modesto be used to "cdr down a list."  That's not a factor on ppc or x86-64,but all versions of OpenMCL still store the CDR of a CONS cell first inmemory.  It doesn't matter, but doing it the way that the host systemdid made boostrapping to a new target system a little easier.)</variablelist>
+          <variablelist>Any way you look at it, NIL is a bit ... unusual.NIL is both a SYMBOL and a LIST (as well as being a canonical truthvalue and probably a few other things.)  Its role as a LIST is probablymuch more important to most programs than its role as a SYMBOL is:LISTP has to be true of NIL and primitives like CAR and CDR do LISTPimplicitly when safe and want that operation to be fast.There are several possible approaches to this; OpenMCL uses two of them.On PPC32 and X86-64, NIL is basically a weird CONS cell that straddlestwo doublenodes; the tag of NIL is unique and congruent modulo 4 (modulo8 on 64-bit) with the tag used for CONS cells.  LISTP is thereforetrue of any node whose low 2 (or 3) bits contain the appropriate tagvalue (it's not otherwise necessary to special-case NIL.)  SYMBOLaccessors (SYMBOL-NAME, SYMBOL-VALUE, SYMBOL-PLIST ..) -do- haveto special-case NIL (and access the components of an internal proxysymbol.)On PPC64 (where architectural restrictions dictate the set of tagsthat can be used to access fixed components of an object), thatapproach wasn't practical.  NIL is just a distinguished SYMBOL,and it just happens to be the case that its pname slot and valueslots are at the same offsets from a tagged pointer as a CONS cellsCDR and CAR would be.  NIL's pname is set to NIL (SYMBOL-NAMEchecks for this and returns the string "NIL"), and LISTP (andtherefore safe CAR and CDR) have to check for (OR NULL CONSP).At least in the case of CAR and CDR, the fact that the PPC hasmultiple condition-code fields keeps that extra test from beingprohibitively expensive.</variablelist>
+          <variablelist>Some objects are immediate.(but not FIXNUMs).This is true of CHARACTERs and, on 64-bit platforms, SINGLE-FLOATs.It's also true of some nodes used in the runtime system (specialvalues used to indicate unbound variables and slots, for instance.)On 64-bit platforms, SINGLE-FLOATs have their own unique tag (makingthem a little easier to recognize; on all platforms, CHARACTERs sharea tag with other immediate objects (unbound markers) but are easyto recognize (by looking at several of their low bits.)  The GCtreats any node with an immediate tag (and any node with a fixnumtag) as a leaf.</variablelist>
+          <variablelist>There are some advantages to treating everything else - memory-allocated objects that aren't CONS cells - uniformly.There are some disadvantages to that uniform treatment as well, and thetreatment of "memory-allocated non-CONS objects" isn't entirely uniformaccross all OpenMCL implementations.  Let's first pretend that thetreatment is uniform, then discuss the ways in which it isn't.The "uniform approach" is to treat all memory-allocated non-CONS objectsas if they were vectors; this use of the term is a little looser thanwhat's implied by the CL VECTOR type.  OpenMCL actually uses the term"uvector" to mean "a memory-allocated lisp object other than a CONS cell,whose first word is a header which describes the object's type andthe number of elements that it contains."  In this view, a SYMBOL isa UVECTOR, as is a STRING, a STANDARD-INSTANCE, a CL array or vector,a FUNCTION, and even a DOUBLE-FLOAT.In the PPC implementations (where things are a little more ... uniform),a single tag value is used to denote any uvector; in order to determinesomething more specific about the type of the object in question, it'snecessary to fetch the low byte of the header word from memory.  On thex86-64 platform, certain types of uvectors - SYMBOLs and FUNCTIONs -are given their own unique tags.  The good news about the x86-64 approachis that SYMBOLs and FUNCTIONs can be recognized without referencingmemory; the slightly bad news is that primitive operations that workon UVECTOR-tagged objects - like the function CCL:UVREF - don't workon SYMBOLs or FUNCTIONs on x86-64 (but -do- work on those types of objectsin the PPC ports.)The header word which precedes a UVECTOR's data in memory contains 8bits of type information in the low byte and either 24 or 56 bits of"element-count" information in the rest of the word.  (This is wherethe sometimes-limiting value of 2^24 for ARRAY-TOTAL-SIZE-LIMIT onPPC32 platforms comes from.)  The low byte of the header - sometimescalled the uvector's subtag - is itself tagged (which means thatthe header is tagged.)  The (3 or 4) tag bits in the subtag are usedto determine whether the uvector's elements are nodes or immediates.(A UVECTOR whose elements are nodes is called a GVECTOR; a UVECTORwhose elements are immediates is called an IVECTOR.  This terminologycame from Spice Lisp, which was a predecessor of CMUCL.)Even though a uvector header is tagged, a header is not a node.  There'sno (supported) way to get your hands on one in lisp and doing so couldbe dangerous.  (If the value of a header wound up in a lisp noderegister and that register wound up getting pushed on a thread's valuestack, the GC might misinterpret that situation to mean that therewas a stack-allocated UVECTOR on the value stack.)</variablelist>
+        
+        </listitem>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Heap-Allocation">
+      <para>Heap Allocation
+When the OpenMCL kernel first starts up, a large contiguous chunk of the
+process's address space is mapped as "anonymous, no access" memory. ("Large"
+means different things in different contexts; on LinuxPPC32, it means "about
+1 gigabyte", on DarwinPPC32, it means "about 2 gigabytes", and on current
+64-bit platforms it ranges from 128 to 512 gigabytes, depending on OS. These
+values are both defaults and upper limits; the &ndash;heap-reserve argument can
+be used to try to reserve less than the default.)</para>
+      <para>Reserving address space that can't (yet) be read or written to doesn't
+cost much; in particular, it doesn't require that correspinding swap
+space or physical memory be available.  Marking the address range as being
+"mapped" helps to ensure that other things (random calls to malloc(),
+dynamically loaded shared libraries) won't be allocated in this region
+that lisp has reserved for its own heap growth.</para>
+      <para>A small portion (around 1/32 on 32-bit platforms and 1/64 on 64-bit
+platforms) of that large chunk of address space is reserved for GC
+data structures.  Memory pages reserved for these data structures are
+mapped read-write as pages made writable in the main portion of the
+heap.</para>
+      <para>The initial heap image is mapped into this reserved address space and
+an additional (LISP-HEAP-GC-THRESHOLD) bytes are mapped read-write.
+GC data structures grow to match the amount of GC-able memory in the
+initial image + the gc threshold, and control is transferred to lisp
+code.  Inevitably, that code spoils everything and starts consing;
+there are basically three layers of memory allocation that can go on.</para>
+
+      <sect2 id="Per-thread-object-allocation">
+        <para>Per-thread object allocationEach lisp thread has a private "reserved memory segment"; when a thread
+starts up, its reserved memory segment is empty.  PPC ports maintain the
+highest unallocated addres and he lowest allocated address in the
+current segment in registers when running lisp code; on x86-664, these
+values are maintained in the current threads's TCR.  (An "empty" heap
+segment is one whose high pointer and low pointer are equal.)  When
+a thread is not in the midde of allocating something, the low 3 or
+4 bits of the high and low pointers are clear (the pointers are
+doublenode-aligned.)</para>
+        <para>A thread tries to allocate an object whose physical size in bytes is X
+and whose tag is Y by:</para>
+        <varlistentry numeration="arabic">
+          <variablelist>decrementing the "high" pointer by (- X Y)</variablelist>
+          <variablelist>trapping if the high pointer is less than the low pointer</variablelist>
+          <variablelist>using the (tagged) high pointer to initialize the object, if necessary</variablelist>
+          <variablelist>clearing the low bits of the high pointer</variablelist>
+        </varlistentry>
+        <para>On PPC32, where the size of a CONS cell is 8 bytes and the tag of a CONS
+cell is 1, machine code which sets the arg_z register to the result of
+doing (CONS arg_y arg_z) looks like:</para>
+        <programlisting>
+  (SUBI ALLOCPTR ALLOCPTR 7)    ; decrement the high pointer by (- 8 1)
+  (TWLLT ALLOCPTR ALLOCBASE)    ; trap if the high pointer is below the base
+  (STW ARG_Z -1 ALLOCPTR)       ; set the CDR of the tagged high pointer
+  (STW ARG_Y 3 ALLOCPTR)        ; set the CAR
+  (MR ARG_Z ALLOCPTR)           ; arg_z is the new CONS cell
+  (RLWINM ALLOCPTR ALLOCPTR 0 0 28)     ; clear tag bits
+</programlisting>
+        <para>On x86-64, the idea's similar but the implementation is different.  The
+high and low pointers to the current thread's reserved segment are kept
+in the TCR, which is addressed by the gs segment register. An x86-64
+CONS cell is 16 bytes wide and has a tag of 3; we canonically use the
+temp0 register to initialize the object</para>
+        <programlisting>
+  (subq ($ 13) ( (% gs) 216))  ; decrement allocptr
+  (movq ( (% gs) 216) (% temp0)); load allocptr into temp0
+  (cmpq ( (% gs) 224) (% temp0)) ; compare to allocabase
+  (jg L1)                       ; skip trap
+  (uuo-alloc)                   ; uh, don't skip trap
+L1
+  (andb ($ 240) ( (% gs) 216)) ; untag allocptr in the tcr
+  (movq (% arg_y) ( 5 (% temp0))) ; set the car
+  (movq (% arg_z) ( -3 (% temp0))); set the cdr
+  (movq (% temp0) (% arg_z))    ; return the cons
+</programlisting>
+        <para>If we don't take the trap (if allocating 8-16 bytes doesn't exhaust
+the thread's reserved memory segment), that's a fairly short and
+simple instruction sequence.  If we do take the trap, we'll have to
+do some additional work in order to get a new segment for the current
+thread.</para>
+      </sect2>
+
+      <sect2 id="Allocation-of-reserved-heap-segments">
+        <para>Allocation of reserved heap segmentsAfter lisp image is first mapped into memory - and after each full GC - the
+lisp kernel ensures that (LISP-HEAP-GC-TRESHOLD) additional bytes beyond
+the current end of the heap are mapped read-write.</para>
+        <para>If a thread traps while trying to allocate memory, the thread goes
+through the usual exception-handling protocol (to ensure that any oher
+thread that GCs "sees" the state of the trapping thread and to serialize
+exception handling.)  When the exception handler runs, it determines
+the nature and size of the failed allocation and tries to complete the
+allocation on the thread's behalf (and leave it with a reasonably large
+thread-specific memory segment so that the next small allocation is
+unlikely to trap.</para>
+        <para>Depending on the size of the requested segment allocation, the number of
+segment allocations that have occurred since the last GC, and the EGC
+and GC thresholds, the segment allocation trap handler may invoke a full
+or ephemeral GC before returning a new segment.  It's worth noting that
+the [E]GC is triggered based on the number of and size of these segments
+that've been allocated since the last GC; it doesn't have much to do
+with how "full" each of those per-thread segments are.  It's possible
+for a large number of threads to do fairly incidental memory allocation
+and trigger the GC as a result; avoiding this involves tuning the
+per-thread allocation quantum and the GC/EGC thresholds appropriately.</para>
+      </sect2>
+
+      <sect2 id="Heap-growth">
+        <para>Heap growthAll OSes on which OpenMCL currently runs use an "overcommit" memory
+allocation strategy by default (though some of them provide ways of
+overriding that default.)  What this means in general is that the OS
+doesn't necessarily ensure that backing store is available when asked
+to map pages as read-write; it'll often return a success indicator from
+the mapping attempt (mapping the pages as "zero-fill, copy-on-write"),
+and only try to allocate the backing store (swap space and/or physical
+memory) when non-zero contents are written to the pages.</para>
+        <para>It -sounds- like it'd be better to have the mmap() call fail
+immediately, but it's actually a complicated issue.  (It's possible that
+other applications will stop using some backing store before lisp code
+actually touches the pages that need it, for instance.)  It's also
+not guaranteed that lisp code would be able to "cleanly" signal an
+out-of-memory condition if lisp is ... out of memory</para>
+        <para>I don't know that I've ever seen an abrupt out-of-memory failure that
+wasn't preceeded by several minutes of excessive paging activity.  The
+most expedient course in cases like this is to either (a) use less memory
+or (b) get more memory; it's generally hard to use memory that you don't
+have.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="GC-details">
+      <para>GC details
+The GC uses a Mark/Compact algorithm; its execution time is
+essentially a factor of the amount of live data in the heap. (The somewhat
+better-known Mark/Sweep algorithms don't compact the live data but instead
+traverse the garbage to rebuild free-lists; their execution time is
+therefore a factor of the total heap size.)</para>
+      <para>As mentioned in , two auxiliary data structures
+(proportional to the size of the lisp heap) are maintained. These are</para>
+      <varlistentry numeration="arabic">
+        <variablelist>the markbits bitvector, which contains a bit for everydoublenode in the dynamic heap (plus a few extra words for alignmentand so that sub-bitvectors can start on word boundaries.)</variablelist>
+        <variablelist>the relocation table, which contains a native word for every 32 or 64doublenodes in the dynamic heap, plus an extra word used to keep trackof the end of the heap.</variablelist>
+      </varlistentry>
+      <para>The total GC space overhead is therefore on the order of 3% (2/64 or
+1/32).</para>
+      <para>The general algorithm proceeds as follows:</para>
+
+      <sect2 id="Mark-phase">
+        <para>Mark phase
+Each doublenode in the dynamic heap has a corresponding bit in the
+markbits vector. (For any doublenode in the heap, the index of its mark
+bit is determined by subtracing the address of the start of the heap
+from the address of the object and dividing the result by 8 or 16.) The GC
+knows the markbit index of the free pointer, so determining that the
+markbit index of a doubleword address is between the start of the heap
+and the free pointer can be done with a single unsigned
+comparison.</para>
+        <para>The markbits of all doublenodes in the dynamic heap are zeroed
+before the mark phase begins. An object is <emphasis>marked</emphasis>
+if the markbits of all of its constituent doublewords are set and
+unmarked otherwise; setting an object's markbits involves setting the
+corrsponding markbits of all constituent doublenodes in the
+object.</para>
+        <para>The mark phase traverses each root. If the tag of the value of
+the root indicates that it's a non-immediate node whose address lies
+in the lisp heap, then:</para>
+        <varlistentry numeration="arabic">
+          <variablelist>If the object is already marked, do nothing.</variablelist>
+          <variablelist>Set the object's markbit(s).</variablelist>
+          <variablelist>If the object is an ivector, do nothing further.</variablelist>
+          <variablelist>If the object is a cons cell, recursively mark its car andcdr.</variablelist>
+          <variablelist>Otherwise, the object is a gvector. Recursively mark itselements.</variablelist>
+        </varlistentry>
+        <para>Marking an object thus involves ensuring that its mark bits are set and
+then recursively marking any pointers contained within the object if the
+object was originally unmarked. If this recursive step was implemented
+in the obvious manner, marking an object would take stack space
+proportional to the length of the pointer chain from some root to that
+object. Rather than storing that pointer chain implicitly on the stack
+(in a series of recursive calls to the mark subroutine), the OpenMCL
+marker uses mixture of recursion and a technique called <emphasis>link
+inversion</emphasis> to store the pointer chain in the objects themselves.
+(Recursion tends to be simpler and faster; if a recursive step notes
+that stack space is becoming limited, the link-inversion technique is
+used.)</para>
+        <para>Certain types of objects are treated a little specially:</para>
+        <varlistentry numeration="arabic">
+          <variablelist>To support a feature called <emphasis>GCTWA
+              <tip>
+<para>I believe that theacronym comes from MACLISP, where it stood for "Garbage Collection ofTruly Worthless Atoms".</para>
+              </tip>
+, </emphasis>the vector which contains the internalsymbols of the current package is marked on entry to the mark phasebut the symbols themselves are not marked at this time. Near the endof the mark phase, symbols referenced from this vector which are nototherwise marked are marked if and only if they're somehowdistinguishable from newly created symbols (by virtue of their havingfunction bindings, value bindings, plists, or other attributes.)</variablelist>
+          <variablelist>Pools have their first element set to NIL before any otherelements are marked.</variablelist>
+          <variablelist>All hash tables have certain fields (used to cache previousresults) invalidated.</variablelist>
+          <variablelist>Weak Hash Tables and other weak objects are put on a linkedlist as they're encountered; their contents are only retained ifthere are other (non-weak) references to them.</variablelist>
+        </varlistentry>
+        <para>At the end of the mark phase, the markbits of all objects which
+are transitively reachable from the roots are set and all other markbits
+are clear.</para>
+      </sect2>
+
+      <sect2 id="Relocation-phase">
+        <para>Relocation phase
+The <emphasis>forwarding address</emphasis> of a doublenode in the
+dynamic heap is (<its current address> - (size_of_doublenode * <the number of
+unmarked markbits that precede it>)) or alternately (<the base of
+the heap> + (size_of_doublenode * <the number of marked markbits that preced
+it>)). Rather than count the number of preceding markbits each time,
+the relocation table is used to precompute an approximation of the
+forwarding addresses for all doublewords. Given this approximate address
+and a pointer into the markbits vector, it's relatively easy to compute
+the exact forwarding address.</para>
+        <para>The relocation table contains the forwarding addresses of each
+<emphasis>pagelet</emphasis>, where a pagelet is 256 bytes (or 32
+doublenodes). The forwarding address of the first pagelet is the base of
+the heap. The forwarding address of the second pagelet is the sum of the
+forwarding address of the first and 8 bytes for each mark bit set in the
+first 32-bit word in the markbits table. The last entry in the
+relocation table contains the forwarding address that the freepointer
+would have, e.g., the new value of the freepointer after
+compaction.</para>
+        <para>In many programs, old objects rarely become garbage and new
+objects often do. When building the relocation table, the relocation
+phase notes the address of the first unmarked object in the dynamic
+heap. Only the area of the heap between the first unmarked object and
+the freepointer needs to be compacted; only pointers to this area will
+need to be forwarded (the forwarding address of all other pointers to
+the dynamic heap is the address of that pointer.) Often, the first
+unmarked object is much nearer the free pointer than it is to the base
+of the heap.</para>
+      </sect2>
+
+      <sect2 id="Forwarding-phase">
+        <para>Forwarding phase
+The forwarding phase traverses all roots and the
+"old" part of the dynamic heap (the part between the base
+of the heap and the first unmarked object.) All references to objects
+whose address is between the first unmarked object and the free pointer
+are updated to point to the address the object will have after
+compaction by using the relocation table and the markbits vector and
+interpolating.</para>
+        <para>The relocation table entry for the pagelet nearest the object is
+found. If the pagelet's address is less than the object's address, the
+number of set markbits that precede the object on the pagelet is used to
+determine the object's address; otherwise, the number of set markbits
+the follow the object on the pagelet is used.</para>
+        <para>Since forwarding views the heap as a set of doublewords, locatives
+are (mostly) treated like any other pointers. (The basic difference is
+that locatives may appear to be tagged as fixnums, in which case they're
+treated as word-aligned pointers into the object.)</para>
+        <para>If the forward phase changes the address of any hash table key in
+a hash table that hashes by address (e.g., an EQ hash table), it sets a
+bit in the hash table's header. The hash table code will rehash the hash
+table's contents if it tries to do a lookup on a key in such a
+table.</para>
+        <para>Profiling reveals that about half of the total time spent in the
+GC is spent in the subroutine which determines a pointer's forwarding
+address. Exploiting GCC-specific idioms, hand-coding the routine, and
+inlining calls to it could all be expected to improve GC
+performance.</para>
+      </sect2>
+
+      <sect2 id="Compact-phase">
+        <para>Compact phase
+The compact phase compacts the area between the first unmarked
+object and the freepointer so that it contains only marked objects.
+While doing so, it forwards any pointers it finds in the objects it
+copies.</para>
+        <para>When the compact phase is finished, so is the GC (more or less):
+the free pointer and some other data structures are updated and control
+returns to the exception handler that invoked the GC. If sufficient
+memory has been freed to satisfy any allocation request that may have
+triggered the GC, the exception handler returns; otherwise, a
+"seriously low on memory" condition is signalled, possibly
+after releasing a small emergency pool of memory.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="The-ephemeral-GC">
+      <para>The ephemeral GC
+In the OpenMCL memory management scheme, the relative age of two
+objects in the dynamic heap can be determined by their addresses: if
+addresses X and Y are both addresses in the dynamic heap, X is younger
+than Y (X was created more recently than Y) if it is nearer to the free
+pointer (and farther from the base of the heap) than Y.</para>
+      <para>Ephemeral (or generational) garbage collectors attempt to exploit
+the following assumptions:</para>
+      <listitem mark="bullet">
+        <variablelist>most newly created objects become garbage soon after they'recreated.</variablelist>
+        <variablelist>most objects that have already survived several GCs are unlikelyto ever become garbage.</variablelist>
+        <variablelist>old objects can only point to newer objects as the result of adestructive modification (e.g., via SETF.)</variablelist>
+      
+      </listitem>
+      <para>By concentrating its efforts on (frequently and quickly) reclaiming
+newly created garbage, an ephemeral collector hopes to postpone the more
+costly full GC as long as possible. It's important to note that most
+programs create some long-lived garbage, so an EGC can't typically
+eliminate the need for full GC.</para>
+      <para>An EGC views each object in the heap as belonging to exactly one
+<emphasis>generation</emphasis>; generations are sets of objects that are
+related to each other by age: some generation is the youngest, some the
+oldest, and there's an age relationship between any intervening
+generations. Objects are typically assigned to the youngest generation
+when first allocated; any object that has survived some number of GCs in
+its current generation is promoted (or <emphasis>tenured</emphasis>) into
+an older generation.</para>
+      <para>When a generation is GCed, the roots consist of the stacks,
+registers, and global variables as always and also of any pointers to
+objects in that generation from other generations. To avoid the need to
+scan those (often large) other generations looking for such
+intergenerational references, the runtime system must note all such
+intergenerational references at the point where they're created (via
+Setf).<tip><para>This is sometimes called "The Write Barrier": all
+assignments which might result in intergenerational references must be
+noted, as if the other generations were write-protected.</para></tip> The set of pointers that may contain intergenerational
+references is sometimes called <emphasis>the remembered
+set</emphasis>.</para>
+      <para>In OpenMCL's EGC, the heap is organized exactly the same as otherwise;
+"generations" are merely structures which contain pointers to
+regions of the heap (which is already ordered by age.) When a generation
+needs to be GCed, any younger generation is incorporated into it; all
+objects which survive a GC of a given generation are promoted into the
+next older generation. The only intergenerational references that can
+exist are therefore those where an old object is modified to contain a
+pointer to a new object.</para>
+      <para>The EGC uses exactly the same code as the full GC. When a given GC
+is "ephemeral",</para>
+      <listitem mark="bullet">
+        <variablelist>the "base of the heap" used to determine anobject's markbit address is the base of the generation beingcollected;</variablelist>
+        <variablelist>the markbits vector is actually a pointer into the middle of theglobal markbits table; preceding entries in this table are used tonote doubleword addresses in older generations that (may) containintergenerational references;</variablelist>
+        <variablelist>some steps (notably GCTWA and the handling of weak objects) arenot performed;</variablelist>
+        <variablelist>the intergenerational references table is used to findadditional roots for the mark and forward phases. If a bit is set inthe intergenerational references table, that means that thecorresponding doubleword (in some "old" generation, insome "earlier" part of the heap) may have had a pointerto an object in a younger generation stored into it.</variablelist>
+      
+      </listitem>
+      <para>The intergenerational references table is maintained indirectly:
+whenever a setf operation that may introduce an intergenerational
+reference occurs, a pointer to the doubleword being stored into is pushed
+onto the <emphasis>memo buffer</emphasis>, which is a stack whos top is
+addressed by the memo register. Whenever the memo buffer
+overflows<tip><para>A guard page at the end of the memo buffer simplifies overflow
+detection.</para></tip> when the EGC is active, the handler scans the buffer and
+sets bits in the intergenerational references table for each doubleword
+address it finds in the buffer that belongs to some generation other than
+the youngest; the same scan is performed on entry to any ephemeral GC.
+After (possibly) performing this scan, the handler resets the memo
+register to point to the bottom of the memo stack; this means that when
+the EGC is inactive, the memo buffer is constantly being filled and
+emptied for no apparent reason.</para>
+      <para>With one exception (the implicit setfs that occur on entry to and
+exit from the binding of a special variable), all setfs that might
+introduce an intergenerational reference must be memoized.<tip><para>Note that the implicit setfs that occur when initializing an
+object - as in the case of a call to cons or vector - can't introduce
+intergenerational references, since the newly created object is always
+younger than the objects used to initialize it.</para></tip> It's always safe to push any cons cell or gvector locative
+onto the memo stack; it's never safe to push anything else.</para>
+      <para>Typically, the intergenerational references bitvector is sparse: a
+relatively small number of old locations are stored into, although some of
+them may have been stored into many times. The routine that scans the
+memoization buffer does a lot of work and usually does it fairly often; it
+uses a simple, brute-force method but might run faster if it was smarter
+about recognizing addresses that it'd already seen.</para>
+      <para>When the EGC mark and forward phases scan the intergenerational
+reference bits, they can clear any bits that denote doublewords that
+definitely do not contain intergenerational references.</para>
+    </sect1>
+
+    <sect1 id="Fasl-files">
+      <para>Fasl files
+The information in this section was current in November 2004.
+Saving and loading of Fasl files is implemented in
+xdump/faslenv.lisp, level-0/nfasload.lisp, and lib/nfcomp.lisp.
+The information here is only an overview, which might help when
+reading the source.</para>
+      <para>The OpenMCL Fasl format is forked from the old MCL Fasl format; there
+are a few differences, but they are minor.  The name "nfasload"
+comes from the fact that this is the so-called "new" Fasl system,
+which was true in 1986 or so.  The format has held up well, although
+it would certainly need extensions to deal with 64-bit data, and
+some other modernization might be possible.</para>
+      <para>A Fasl file begins with a "file header", which contains version
+information and a count of the following "blocks".  There's typically
+only one "block" per Fasl file.  The blocks are part of a mechanism
+for
+combining multiple logical files into a single physical file, in order
+to simplify the distribution of precompiled programs.  (Nobody seems
+to be doing anything interesting with this feature, at the moment,
+probably because it isn't documented.)</para>
+      <para>Each block begins with a header for itself, which just describes the
+size of the data that follows.</para>
+      <para>The data in each block is treated as a simple stream of bytes, which
+define a bytecode program.  The actual bytecodes, "fasl operators",
+are defined in xdump/faslenv.lisp.  The descriptions in the source
+file are terse, but, according to Gary, "probably accurate".</para>
+      <para>Some of the operators are used to create a per-block "object table",
+which
+is a vector used to keep track of previously-loaded objects and
+simplify references to them.  When the table is created, an index
+associated with it is set to zero; this is analogous to an array
+fill-pointer, and allows the table to be treated like a stack.</para>
+      <para>The low seven bits of each bytecode are used to specify the
+fasl operator;
+currently, about fifty operators are defined.  The high byte, when
+set, indicates that the result of the operation should be pushed
+onto the object table.</para>
+      <para>Most bytecodes are followed by operands; the operand data is
+byte-aligned.
+How many operands there are, and their type, depend on the bytecode.
+Operands can be indices into the object table, immediate values, or
+some combination of these.</para>
+      <para>An exception is the bytecode #xFF, which has the symbolic name
+ccl::$faslend; it is used to mark the end of the block.</para>
+    </sect1>
+
+    <sect1 id="Heap-images">
+      <para>Heap images
+Needs complete rewrite.</para>
+    </sect1>
+
+    <sect1 id="Operating-system-dependencies">
+      <para>Operating system dependencies</para>
+    </sect1>
+
+    <sect1 id="The-Objective-C-Bridge--1-">
+      <para>The Objective-C Bridge
+Unlike the rest of this chapter, this section was written in late
+2004.</para>
+
+      <sect2 id="How-OpenMCL-Recognizes-Objective-C-Objects">
+        <para>How OpenMCL Recognizes Objective-C Objects
+In most cases, pointers to instances of Objective-C classes are
+recognized as such; the recognition is (and probably always will be)
+slightly heuristic. Basically, any pointer that passes basic sanity
+checks and whose first word is a pointer to a known ObjC class is
+considered to be an instance of that class; the Objective-C runtime
+system would reach the same conclusion.</para>
+        <para>It's certainly possible that a random pointer to an arbitrary
+memory address could look enough like an ObjC instance to fool the lisp
+runtime system, and it's possible that pointers could have their
+contents change so that something that had either been a true ObjC
+instance (or had looked a lot like one) is changed (possibly by virtue
+of having been deallocated.)</para>
+        <para>In the first case, we can improve the heuristics substantially: we
+can make stronger assertions that a particular pointer is really "of
+type :ID" when it's a parameter to a function declared to take
+such a pointer as an argument or a similarly declared function result; we
+can be more confident of something we obtained via SLOT-VALUE of a slot
+defined to be of type :ID than if we just dug a pointer out of memory
+somewhere.</para>
+        <para>The second case is a little more subtle: ObjC memory management is
+based on a reference-counting scheme, and it's possible for an
+object to ... cease to be an object while lisp is still referencing it.
+If we don't want to deal with this possibility (and we don't),
+we'll basically have to ensure that the object is not deallocated
+while lisp is still thinking of it as a first-class object. There's
+some support for this in the case of objects created with MAKE-INSTANCE,
+but we may need to give similar treatment to foreign objects that are
+introduced to the lisp runtime in other ways (as function arguments,
+return values, SLOT-VALUE results, etc. as well as those instances
+that're created under lisp control.)</para>
+        <para>This doesn't all work yet (in fact, not much of it works yet);
+in practice, this has not yet been as much of a problem as anticipated,
+but that may be because existing Cocoa code deals primarily with
+relatively long-lived objects such as windows, views, menus, etc.</para>
+      </sect2>
+
+      <sect2 id="Recommended-Reading--1-">
+        <para>Recommended Reading</para>
+        <term><indexterm>The Apple Objective-C Runtime Reference
+            <variablelist>This describes the internal data structures and programminginterface of Objective C as it is implemented on OS X.</variablelist>
+          </indexterm>
+        </term>
+      </sect2>
+    </sect1>
+  </chapter>
+
+  <chapter id="Modifying-OpenMCL">
+    <para>Modifying OpenMCL</para>
+
+    <sect1 id="Contributing-Code-Back-to-the-OpenMCL-Project">
+      <para>Contributing Code Back to the OpenMCL Project
+This section is a placeholder, added as of August 2004.  The
+full text is being written, and will be added as soon as it is
+available.</para>
+    </sect1>
+
+    <sect1 id="Using-OpenMCL-in--development--and-in--user--mode">
+      <para>Using OpenMCL in "development" and in  "user" mode
+As it's distributed, OpenMCL starts up with *PACKAGE* set to the CL-USER
+package and with most predefined functions and methods protected against
+accidental redefinition.  The package setting is of course a requirement
+of ANSI CL, while the protection protection is intended to catch certain
+types of programming errors (accidentally redefining a CL or CCL function)
+before those errors have a chance to do much damage.</para>
+      <para>These settings may make using OpenMCL to develop OpenMCL a bit more
+awkward, since much of that process assumes that the CCL package is
+current (and a primary purpose of that process is to redefine some
+"predefined, builtin functions".) The standard, "routine"
+ways of building OpenMCL from sources (see )
+- COMPILE-CCL, XCOMPILE-CCL, and XLOAD-LEVEL-0 - bind *PACKAGE* to the
+"CCL" package and enable the redefinition of predefined functions;
+the symbols COMPILE-CCL, XCOMPILE-CCL, and XLOAD-LEVEL-0 are additionally
+now exported from the "CCL" package.</para>
+      <para>Some other (more ad-hoc) ways of doing development on OpenMCL -
+compiling and/or loading individual files, incrementally redefining
+individual functions - may be awkward unless one reverts to the mode of
+operation which was traditionally offered in OpenMCL. (Some OpenMCL source
+files - especially those that comprise the bootstrapping image sources and
+the first few files in the "cold load" sequence - are compiled and
+loaded in the "CCL" package but don't contain (IN-PACKAGE
+"CCL") forms, since IN-PACKAGE doesn't work until later in the
+cold load sequence.)</para>
+      <para>The somewhat bizarre behavior of both SET-USER-ENVIRONMENT and
+SET-DEVELOPMENT-ENVIRONMENT with respect to the special variables they
+affect is intended to allow those constructs to take effect when the
+read-eval-print loop next returns to a top-level '? ' prompt;
+the constructs can meaningfully be used inside LOAD, for instance
+(recall that LOAD binds *PACKAGE*), though using both constructs within
+the same LOAD call would likely be pretty confusing.</para>
+      <para>"user" and "development" are otherwise very
+generic terms; here they're intended to enforce the distinction
+between "using" OpenMCL and "developing" it.</para>
+      <para>The initial environment from which OpenMCL images are saved is one
+where (SET-USER-ENVIRONMENT T) has just been called; in previous
+versions, it was effectively as if (SET-DEVELOPMENT-ENVIRONMENT T) had
+just been called.</para>
+      <para>Hopefully, most users of OpenMCL can safely ignore these issues
+most of the time. Note that doing (SET-USER-ENVIRONMENT T) after loading
+one's own code (or 3rd-party code) into OpenMCL would protect that
+code (as well as OpenMCL's) from accidental redefinition; that may
+be useful in some cases.</para>
+    </sect1>
+
+    <sect1 id="Debugging-facilities-in-the-lisp-kernel">
+      <para>Debugging facilities in the lisp kernel
+In a perfect world, something like this couldn't happen:</para>
+      <programlisting>
+Welcome to OpenMCL Version x.y!
+? (defun foo (x)
+    (declare (cons x))
+    (cdr x))
+FOO
+
+? (foo -1) ;Oops. Too late ...
+Unhandled exception 11 at 0x300e90c8, context->regs at #x7ffff6b8
+Continue/Debugger/eXit <enter>?
+</programlisting>
+      <para>As you may have noticed, it's not a perfect world; it's rare
+that the cause (attempting to reference the CDR of -1, and therefore
+accessing unmapped memory near location 0) of this effect (an
+"Unhandled exception ..." message) is so obvious.</para>
+      <para>The addresses printed in the message above aren't very useful
+unless you're debugging the kernel with GDB (and they're often
+very useful if you are.)</para>
+      <para>Aside from causing an exception that the lisp kernel doesn't
+know how to handle, one can also enter the kernel debugger (more)
+deliberately:</para>
+      <programlisting>
+? (defun classify (n)
+     (cond ((> n 0) "Greater")
+           ((< n 0) "Less")
+           (t
+            ;;; Sheesh ! What else could it be ?
+            (ccl::bug "I give up. How could this happen ?"))))
+CLASSIFY
+
+? (classify 0)
+Bug in OpenMCL system code:
+I give up. How could this happen ?
+? for help
+[12345] OpenMCL kernel debugger:
+</programlisting>
+      <para>CCL::BUG isn't quite the right tool for this example (a call to
+BREAK or PRINT might do a better job of clearing up the mystery), but
+it's sometimes helpful when those other tools can't be used.
+The
+lisp error system notices, for instance, if attempts to signal errors
+themselves cause errors to be signaled; this sort of thing can happen if
+CLOS or the I/O system are broken or missing. After some small number of
+recursive errors, the error system gives up and calls CCL::BUG.</para>
+      <para>If one enters a '?' at the kernel debugger prompt, one will see output
+like:</para>
+      <programlisting>(S)  Find and describe symbol matching specified name
+(B)  Show backtrace
+(X)  Exit from this debugger, asserting that any exception was handled
+(K)  Kill OpenMCL process
+(?)  Show this help
+</programlisting>
+      <para>CCL::BUG just does an FF-CALL into the lisp kernel.  If the kernel debugger
+was invoked because of an unhandled exception (such as an illegal memory
+reference) the OS kernel saves the machine state
+("context") in a data structure for us, and in that case some additional
+options can be used to display the contents of the registers at the point
+of the exception. Another function - CCL::DBG - causes a special exception
+to be generated and enters the lisp kernel debugger with a non-null
+"context":</para>
+      <programlisting>? (defun classify2 (n)
+  (cond ((> n 0) "Greater")
+        ((< n 0) "Less")
+        (t (dbg n))))
+CLASSIFY2
+
+? (classify2 0)
+Lisp Breakpoint
+ While executing: #<Function CLASSIFY2 #x08476cfe>
+? for help
+[12345] OpenMCL kernel debugger: ?
+(G)  Set specified GPR to new value
+(A)  Advance the program counter by one instruction (use with caution!)
+(D)  Describe the current exception in greater detail
+(R)  Show raw GPR/SPR register values
+(L)  Show Lisp values of tagged registers
+(F)  Show FPU registers
+(S)  Find and describe symbol matching specified name
+(B)  Show backtrace
+(X)  Exit from this debugger, asserting that any exception was handled
+(P)  Propagate the exception to another handler (debugger or OS)
+(K)  Kill OpenMCL process
+(?)  Show this help
+</programlisting>
+      <para>CCL::DBG takes an argument, whose value is copied into the register
+that OpenMCL uses to return a function's primary value (arg_z, which
+is r23 on the PowerPC). If we were to choose the (L) option at this point,
+we'd see a dislay like:</para>
+      <programlisting>rnil = 0x01836015
+nargs = 0
+r16 (fn) = #<Function CLASSIFY2 #x30379386>
+r23 (arg_z) = 0
+r22 (arg_y) = 0
+r21 (arg_x) = 0
+r20 (temp0) = #<26-element vector subtag = 2F @#x303793ee>
+r19 (temp1/next_method_context) = 6393788
+r18 (temp2/nfn) = #<Function CLASSIFY2 #x30379386>
+r17 (temp3/fname) = CLASSIFY2
+r31 (save0) = 0
+r30 (save1) = *TERMINAL-IO*
+r29 (save2) = 0
+r28 (save3) = (#<RESTART @#x01867f2e> #<RESTART @#x01867f56>)
+r27 (save4) = ()
+r26 (save5) = ()
+r25 (save6) = ()
+r24 (save7) = ()
+</programlisting>
+      <para>From this we can conclude that the problematic argument to CLASSIFY2
+was 0 (see r23/arg_z), and that I need to work on a better example.</para>
+      <para>The R option shows the values of the ALU (and PPC branch unit)
+registers in hex; the F option shows the values of the FPU registers.</para>
+      <para>The (B) option shows a raw stack backtrace; it'll try to
+identify foreign functions as well as lisp functions. (Foreign function
+names are guesses based on the nearest preceding exported symbol.)</para>
+      <para>If you ever unexpectedly find yourself in the "lisp kernel
+debugger", the output of the (L) and (B) options are often the most
+helpful things to include in a bug report.</para>
+    </sect1>
+
+    <sect1 id="Using-AltiVec-in-OpenMCL-LAP-functions">
+      <para>Using AltiVec in OpenMCL LAP functions</para>
+
+      <sect2 id="Overview--16-">
+        <para>Overview
+It's now possible to use AltiVec instructions in PPC LAP
+(assembler) functions.</para>
+        <para>The lisp kernel detects the presence or absence of AltiVec and
+preserves AltiVec state on lisp thread switch and in response to
+exceptions, but the implementation doesn't otherwise use vector
+operations.</para>
+        <para>This document doesn't document PPC LAP programming in general.
+Ideally, there would be some document that did.</para>
+        <para>This document does explain AltiVec register-usage conventions in
+OpenMCL and explains the use of some lap macros that help to enforce those
+conventions.</para>
+        <para>All of the global symbols described below are exported from the CCL
+package. Note that lap macro names, ppc instruction names, and (in most
+cases) register names are treated as strings, so this only applies to
+functions and global variable names.</para>
+        <para>Much of the OpenMCL support for AltiVec LAP programming is based on
+work contributed to MCL by Shannon Spires.</para>
+      </sect2>
+
+      <sect2 id="Register-usage-conventions">
+        <para>Register usage conventions
+OpenMCL LAP functions that use AltiVec instructions must
+interoperate with each other and with C functions; that suggests that they
+follow C AltiVec register usage conventions. (vr0-vr1 scratch, vr2-vr13
+parameters/return value, vr14-vr19 temporaries, vr20-vr31 callee-save
+non-volatile registers.)</para>
+        <para>The EABI (Embedded Application Binary Interface) used in LinuxPPC
+doesn't ascribe particular significance to the vrsave special-purpose
+register; on other platforms (notably MacOS), it's used as a bitmap
+which indicates to system-level code which vector registers contain
+meaningful values.</para>
+        <para>The WITH-ALTIVEC-REGISTERS lapmacro generates code which which
+saves, updates, and restores VRSAVE on platforms where this is required
+(as indicated by the value of the special variable which controls this)
+and ignores VRSAVE on platforms that don't require it to be
+maintained.</para>
+        <para>On all PPC platforms, it's necessary to save any non-volatile
+vector registers (vr20 .. vr31) before assigning to them and to restore
+such registers before returning to the caller.</para>
+        <para>On platforms that require that VRSAVE be maintained, it's not
+necessary to mention the "use" of vector registers that're
+used as incoming parameters. It's not incorrect to mention their use
+in a WITH-ALTIVEC-REGISTERS form, but it may be unneccessary in many
+interesting cases. One can likewise assume that the caller of any function
+that returns a vector value (in vr2 has already set the apropriate bit in
+VRSAVE to indicate that this register is live. One could therefore write a
+leaf function that added the bytes in vr3 and vr2 and returned the result
+in vr2 as:</para>
+        <programlisting>
+(defppclapfunction vaddubs ((y vr3) (z vr2))
+  (vaddubs z y z)
+  (blr))
+</programlisting>
+        <para>When vector registers that aren't incoming parameters are used
+in a LAP function, WITH-ALTIVEC-REGISTERS takes care of maintaining VRSAVE
+and of saving/restoring any non-volatile vector registers:</para>
+        <programlisting>
+(defppclapfunction load-array ((n arg_z))
+  (check-nargs 1)
+  (with-altivec-registers (vr1 vr2 vr3 vr27) ; Clobbers imm0
+    (li imm0 arch::misc-data-offset)
+    (lvx vr1 arg_z imm0) ; load MSQ
+    (lvsl vr27 arg_z imm0) ; set the permute vector
+    (addi imm0 imm0 16) ; address of LSQ
+    (lvx vr2 arg_z imm0) ; load LSQ
+    (vperm vr3 vr1 vr2 vr27) ; aligned result appears in VR3
+    (dbg t)) ; Look at result in some debugger
+  (blr))
+</programlisting>
+        <para>AltiVec registers are not preserved by CATCH and UNWIND-PROTECT.
+Since AltiVec is only accessible from LAP in OpenMCL and since LAP
+functions rarely use high- level control structures, this should rarely be
+a problem in practice.</para>
+        <para>LAP functions which use non-volatile vector registers and which call
+(Lisp ?) code which may use CATCH or UNWIND-PROTECT should save those
+vector registers before such a call and restore them on return. This is
+one of the intended uses of the WITH-VECTOR-BUFFER lap macro.</para>
+      </sect2>
+    </sect1>
+
+    <sect1 id="Development-Mode-Dictionary">
+      <para>Development-Mode Dictionary</para>
+
+      <sect2 id="iWARN-IF-REDEFINE-KERNEL-">
+        <para>*WARN-IF-REDEFINE-KERNEL*</para>
+        <informalfigure>*warn-if-redefine-kernel</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>*WARN-IF-REDEFINE-KERNEL* &mdash;</para>
+        <para>Variable</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>When true, attempts to redefine (via DEFUN or DEFMETHOD)
+functions and methods that are marked as being
+"predefined" signal continuable errors.</para>
+        <para>Note that these are CERRORs, not warnings, and that
+no lisp functions or methods have been defined in the kernel
+in MCL or OpenMCL since 1987 or so.</para>
+      </sect2>
+
+      <sect2 id="SET-DEVELOPMENT-ENVIRONMENT">
+        <para>SET-DEVELOPMENT-ENVIRONMENT</para>
+        <informalfigure>set-development-environment</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SET-DEVELOPMENT-ENVIRONMENT &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+set-development-environment
+	  &amp;optional
+	  unmark-builtin-functions
+</programlisting>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Arranges that the outermost special bindings of *PACKAGE*
+and *WARN-IF-REDEFINE-KERNEL* restore values of the "CCL"
+package and NIL to these variables, respectively. If the optional
+argument is true, marks all globally defined functions and methods
+as being "not predefined" (this is a fairly expensive
+operation.)</para>
+      </sect2>
+
+      <sect2 id="SET-USER-ENVIRONMENT">
+        <para>SET-USER-ENVIRONMENT</para>
+        <informalfigure>set-user-environment</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>SET-USER-ENVIRONMENT &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+set-user-environment
+	  &amp;optional mark-builtin-functions
+</programlisting>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Arranges that the outermost special bindings of *PACKAGE*
+and *WARN-IF-REDEFINE-KERNEL* restore values of the
+"CL-USER" package and T to these variables, respectively.
+If the optional argument is true, marks all globally defined
+functions and methods as being "predefined" (this is a
+fairly expensive operation.)</para>
+      </sect2>
+
+      <sect2 id="iALTIVEC-AVAILABLE-">
+        <para>*ALTIVEC-AVAILABLE*</para>
+        <informalfigure>*altivec-available*</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>*ALTIVEC-AVAILABLE* &mdash;</para>
+        <para>Variable</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>This variable is intitialized each time an OpenMCL session
+starts based on information provided by the lisp kernel. Its value
+is true if AltiVec is present and false otherwise. This variable
+shouldn't be set by user code.</para>
+      </sect2>
+
+      <sect2 id="ALTIVEC-AVAILABLE-P">
+        <para>ALTIVEC-AVAILABLE-P</para>
+        <informalfigure>altivec-available-p</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>ALTIVEC-AVAILABLE-P &mdash;</para>
+        <para>Function</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+altivec-available-p
+</programlisting>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Returns non-NIL if AltiVec is available.</para>
+      </sect2>
+
+      <sect2 id="iALTIVEC-LAPMACROS-MAINTAIN-VRSAVE-P-">
+        <para>*ALTIVEC-LAPMACROS-MAINTAIN-VRSAVE-P*</para>
+        <informalfigure>*altivec-lapmacros-maintain-vrsave-p*</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>*ALTIVEC-LAPMACROS-MAINTAIN-VRSAVE-P* &mdash;</para>
+        <para>Variable</para>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Intended to control the expansion of certain lap macros.
+Initialized to NIL on LinuxPPC; initialized to T on platforms
+(such as MacOS X/Darwin) that require that the VRSAVE SPR contain
+a bitmask of active vector registers at all times.</para>
+      </sect2>
+
+      <sect2 id="WITH-ALTIVEC-REGISTERS">
+        <para>WITH-ALTIVEC-REGISTERS</para>
+        <informalfigure>with-altivec-registers</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>WITH-ALTIVEC-REGISTERS &mdash;</para>
+        <para>LAP Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+with-altivec-registers
+	  reglist &amp;body body
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>reglist
+            <variablelist>A list of vector register names (vr0 .. vr31).</variablelist>
+          </indexterm><indexterm>body
+            <variablelist>A sequence of PPC LAP instructions.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Specifies the set of AltiVec registers used in body. If
+*altivec-lapmacros-maintain-vrsave-p* is true when the macro is
+expanded, generates code to save the VRSAVE SPR and updates VRSAVE
+to incude a bitmask generated from the specified register list.
+Generates code which saves any non-volatile vector registers which
+appear in the register list, executes body, and restores the saved
+non-volatile vector registers (and, if
+*altivec-lapmacros-maintain-vrsave-p* is true, restores VRSAVE as
+well. Uses the IMM0 register (r3) as a temporary.</para>
+      </sect2>
+
+      <sect2 id="WITH-VECTOR-BUFFER">
+        <para>WITH-VECTOR-BUFFER</para>
+        <informalfigure>with-vector-buffer</informalfigure>
+        <bridgehead renderas="sect3">Name</bridgehead>
+        <para>WITH-VECTOR-BUFFER &mdash;</para>
+        <para>LAP Macro</para>
+        <bridgehead renderas="sect3">Synopsis</bridgehead>
+        <programlisting>
+with-vector-buffer base n &amp;body body
+</programlisting>
+        <bridgehead renderas="sect3">Arguments and Values</bridgehead>
+        <term><indexterm>base
+            <variablelist>Any available general-purpose register.</variablelist>
+          </indexterm><indexterm>n
+            <variablelist>An integer between 1 and 254, inclusive. (Shouldtypically be much, much closer to 1.) Specifies the size ofthe buffer, in 16-byte units.</variablelist>
+          </indexterm><indexterm>body
+            <variablelist>A sequence of PPC LAP instructions.</variablelist>
+          </indexterm>
+        </term>
+        <bridgehead renderas="sect3">Description</bridgehead>
+        <para>Generates code which allocates a 16-byte aligned buffer
+large enough to contain N vector registers; the GPR base points to
+the lowest address of this buffer. After processing body, the
+buffer will be deallocated. The body should preserve the value of
+base as long as it needs to reference the buffer. It's
+intended that base be used as a base register in stvx and lvx
+instructions within the body.</para>
+      </sect2>
+    </sect1>
+  </chapter> <para>Symbol Index
+<tgroup>
+  <secondaryie>
+    <indexdiv>#_, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>%ff-call, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>%reference-external-entry-point, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>*alternate-line-terminator*, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>*altivec-available*, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>*altivec-lapmacros-maintain-vrsave-p*, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>*current-process*, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>*default-external-format*, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>*ticks-per-second*, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>*warn-if-redefine-kernel, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>:external-format, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>:y, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>@class, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>@selector, see </indexdiv></secondaryie></tgroup>
+<tgroup>A
+  <secondaryie>
+    <indexdiv>accept-connection, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>all-processes, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>altivec-available-p, see </indexdiv></secondaryie></tgroup>
+<tgroup>C
+  <secondaryie>
+    <indexdiv>close, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>close-shared-library, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>configure-egc, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>current-directory-name, see </indexdiv></secondaryie></tgroup>
+<tgroup>D
+  <secondaryie>
+    <indexdiv>def-foreign-type, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>defcallback, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>define-objc-class-method, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>define-objc-method, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>dotted-to-ipaddr, see </indexdiv></secondaryie></tgroup>
+<tgroup>E
+  <secondaryie>
+    <indexdiv>egc, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>egc-active-p, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>egc-configuration, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>egc-enabled-p, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>external, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>external-call, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>external-process-error-stream, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>external-process-id, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>external-process-input-stream, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>external-process-output-stream, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>external-process-status, see </indexdiv></secondaryie></tgroup>
+<tgroup>F
+  <secondaryie>
+    <indexdiv>ff-call, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>foreign-symbol-address, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>foreign-symbol-entry, see </indexdiv></secondaryie></tgroup>
+<tgroup>G
+  <secondaryie>
+    <indexdiv>gc-retain-pages, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>gc-retaining-pages, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>get-user-home-dir, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>getenv, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>getpid, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>getuid, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>grab-lock, see </indexdiv></secondaryie></tgroup>
+<tgroup>I
+  <secondaryie>
+    <indexdiv>ipaddr-to-dotted, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>ipaddr-to-hostname, see </indexdiv></secondaryie></tgroup>
+<tgroup>L
+  <secondaryie>
+    <indexdiv>lisp-heap-gc-threshold, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>local-host, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>local-port, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>lookup-hostname, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>lookup-port, see </indexdiv></secondaryie></tgroup>
+<tgroup>M
+  <secondaryie>
+    <indexdiv>make-lock, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>make-process, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>make-read-write-lock, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>make-record, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>make-semaphore, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>make-socket, see </indexdiv></secondaryie></tgroup>
+<tgroup>N
+  <secondaryie>
+    <indexdiv>ns-lisp-string, see </indexdiv></secondaryie></tgroup>
+<tgroup>O
+  <secondaryie>
+    <indexdiv>open-shared-library, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>os-command, see </indexdiv></secondaryie></tgroup>
+<tgroup>P
+  <secondaryie>
+    <indexdiv>pref, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-abort, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-allow-schedule, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-enable, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-input-wait, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-interrupt, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-kill, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-output-wait, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-preset, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-reset, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-resume, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-run-function, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-suspend, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-suspend-count, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-wait, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-wait-with-timeout, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>process-whostate, see </indexdiv></secondaryie></tgroup>
+<tgroup>R
+  <secondaryie>
+    <indexdiv>receive-from, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>release-lock, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>remote-host, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>remote-port, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>request-terminal-input-via-break, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>rlet, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>rletz, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>run-program, see </indexdiv></secondaryie></tgroup>
+<tgroup>S
+  <secondaryie>
+    <indexdiv>send-to, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>set-development-environment, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>set-lisp-heap-gc-threshold, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>set-user-environment, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>setenv, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>setgid, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>setuid, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>SHARP-AMPERSAND, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>shutdown, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>signal-external-process, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>signal-semaphore, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>socket-address-family, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>socket-connect, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>socket-error, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>socket-error-code, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>socket-error-identifier, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>socket-error-situation, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>socket-format, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>socket-os-fd, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>socket-type, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>stream-device, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>stream-read-ivector, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>stream-read-list, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>stream-read-vector, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>stream-write-ivector, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>stream-write-list, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>stream-write-vector, see </indexdiv></secondaryie></tgroup>
+<tgroup>T
+  <secondaryie>
+    <indexdiv>terminate-when-unreachable, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>timed-wait-on-semaphore, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>try-lock, see </indexdiv></secondaryie></tgroup>
+<tgroup>U
+  <secondaryie>
+    <indexdiv>unuse-interface-dir, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>use-interface-dir, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>use-lisp-heap-gc-threshold, see </indexdiv></secondaryie></tgroup>
+<tgroup>W
+  <secondaryie>
+    <indexdiv>wait-on-semaphore, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>with-altivec-registers, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>with-lock-grabbed, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>with-open-socket, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>with-read-lock, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>with-terminal-input, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>with-vector-buffer, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>with-write-lock, see </indexdiv></secondaryie>
+  <secondaryie>
+    <indexdiv>without-interrupts, see </indexdiv></secondaryie></tgroup></para>
+</book>
+
