[Openmcl-cvs-notifications] r8570 - in /trunk/source/doc/src: Makefile.fedora Makefile.macports openmcl-documentation.xml

rme at clozure.com rme at clozure.com
Fri Feb 22 21:34:53 EST 2008


Author: rme
Date: Fri Feb 22 21:34:53 2008
New Revision: 8570

Log:
Superseded by split version.

Removed:
    trunk/source/doc/src/openmcl-documentation.xml
Modified:
    trunk/source/doc/src/Makefile.fedora
    trunk/source/doc/src/Makefile.macports

Modified: trunk/source/doc/src/Makefile.fedora
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- trunk/source/doc/src/Makefile.fedora (original)
+++ trunk/source/doc/src/Makefile.fedora Fri Feb 22 21:34:53 2008
@@ -70,7 +70,7 @@
 =

 include makehtml
 =

-install: $(HTMLFILES)
+install: $(HTMLFILES) distclean
 	cp $(HTMLFILES) ../HTML
 =

 $(TEMP):
@@ -80,7 +80,7 @@
 	rm -rf build-*
 =

 distclean: clean
-	-find . -type f -name "*~" | xargs rm
+	rm -f *~
 =

 # All this rigamarole is to make the pathnames stored in the tarfile
 # have a uniform prefix regardless of where the build directory actually

Modified: trunk/source/doc/src/Makefile.macports
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- trunk/source/doc/src/Makefile.macports (original)
+++ trunk/source/doc/src/Makefile.macports Fri Feb 22 21:34:53 2008
@@ -21,7 +21,7 @@
 # are, you should make sure that the correct catalog file is being used
 # (see below), and, if so, that its contents are correct.
 #EXTRAPARAMS=3D --load-trace
-EXTRAPARAMS=3D
+EXTRAPARAMS=3D --xinclude --nonet
 =

 # The catalog file tells the translator where to find XSL stylesheets on t=
he
 # local system.  The first choice here is what should be used for builds
@@ -54,9 +54,11 @@
 =

 # Compute some targets.
 =

-XMLFILES =3D $(shell find . -name "*.xml")
+#XMLFILES =3D $(shell find . -name "*.xml")
+XMLFILES =3D [0-9][0-9]-*.xml ccl-documentation.xml
 XSLFILES =3D $(shell find xsl -name "*.xsl")
-HTMLFILES =3D $(patsubst %.xml,%.html, $(XMLFILES))
+#HTMLFILES =3D $(patsubst %.xml,%.html, $(XMLFILES))
+HTMLFILES =3D ccl-documentation.html
 =

 # Save the xsltproc version string for use in debugging.
 =


Removed: trunk/source/doc/src/openmcl-documentation.xml
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D
--- trunk/source/doc/src/openmcl-documentation.xml (original)
+++ trunk/source/doc/src/openmcl-documentation.xml (removed)
@@ -1,15693 +1,0 @@
-<?xml version=3D"1.0" encoding=3D"US-ASCII"?>
-<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN" "http://www.oas=
is-open.org/docbook/xml/4.2/docbookx.dtd" [
-<!ENTITY rest "<varname>&amp;rest</varname>">
-<!ENTITY key "<varname>&amp;key</varname>">
-<!ENTITY optional "<varname>&amp;optional</varname>">
-<!ENTITY body "<varname>&amp;body</varname>">
-<!ENTITY aux "<varname>&amp;aux</varname>">
-<!ENTITY allow-other-keys "<varname>&amp;allow-other-keys</varname>">
-]>
-<book lang=3D"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:</p=
ara>
-      <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</em=
phasis>
-      </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=3D"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 pathn=
ame of the file
-#P"/Users/alms/my_lisp_stuff/ccl/level-1/level-1.lisp"
-</programlisting>
-      </sect2>
-      <sect2 id=3D"Invocation">
-	<title>Invocation</title>
-	<para>Assuming that the shell script is properly installed, it can be use=
d to invoke OpenMCL from a shell prompt:
-	<programlisting>
-shell&gt;<replaceable>ccl</replaceable> <emphasis>args</emphasis>
-	</programlisting>
-	<literal>ccl</literal> will run a 32-bit session;
-	<literal>ccl64</literal> will run a 64-bit session.
-	</para>
-      </sect2>
-      <sect2 id=3D"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 wi=
th the
-<literal>--no-init</literal> option.</para>
-      </sect2>
-
-      <sect2 id=3D"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=3D"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 fro=
m 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 symbo=
ls</para></listitem>
-        <listitem><para>autocomplete symbols and package names</para></lis=
titem>
-        <listitem><para>cross-reference function calls</para></listitem>
-        <listitem><para>examine stack traces and debug errors</para></list=
item>
-      =

-      </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=3D"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=3D"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=3D"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=3D"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=3D"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=3D"bold">Note for Macintosh Users:</emphasi=
s> =

-	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=3D"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=3D"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=3D"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=3D"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=3D"filename_conventions">
-       <title>Platform-specific filename conventions</title>
-       <table id =3D"Platform-specific-filename-conventions">
-	 <title>Platform-specific filename conventions</title>
-	 <tgroup cols=3D"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=3D"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></list=
item>
-        <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><liter=
al>-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><liter=
al>-snapshot-</literal><replaceable>yymmdd</replaceable><literal>.tar.gz</l=
iteral>,
-      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=3D"http://subversion=
.tigris.org">Subversion web page</ulink> contains links to subversion clien=
t 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=3D"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=3D"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 re=
side
-      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=3D"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></li=
stitem>
-          <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=3D"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=3D"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=3D"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=3D"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=3D"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=3D"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
-$ ./KERNEL BOOT_IMAGE
-	</programlisting>
-        <para>Where <replaceable>KERNEL</replaceable> and
-        <replaceable>BOOT_IMAGE</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>") ; Overwit=
ing 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=3D"Questions-and-Answers">
-
-    <title>Questions and Answers</title>
-
-    <sect1 id=3D"How-can-I-do-nonblocking--aka--unbuffered--and--raw---IO-=
">
-      <title>How can I do nonblocking (aka "unbuffered" and "raw") IO?</ti=
tle>
-      <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:</par=
a>
-      <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=3D"I-m-using-the-graphics-demos--Why-doesn-t-the-menubar-cha=
nge-">
-      <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=3D"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=3D"Programming-with-Threads">
-    <title>Programming with Threads</title>
-
-    <sect1 id=3D"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 (&lt; 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=3D"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=3D"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=3D"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 certain=
ly
-      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=3D"Background-Terminal-Input">
-      <title>Background Terminal Input</title>
-
-      <sect2 id=3D"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=3D"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")))
-#&lt;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: #&lt;Anonymous Function #x3063B276&gt;
-> Type :GO to continue, :POP to abort.
-> If continued: Return from BREAK.
-Type :? for other options.
-1 &gt; :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=3D"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?")))
-#&lt;PROCESS sleep-60(1) [Enabled] #x3063BF26&gt;
-
-? (process-run-function "sleep-5" #'(lambda () (sleep 5) (break "quicker")=
))
-#&lt;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=3D"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=3D"The-Threads-which-OpenMCL-Uses-for-Its-Own-Purposes">
-      <title>The Threads which OpenMCL Uses for Its Own Purposes</title>
-      <para>
-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=3D"Threads-Dictionary">
-      <title>Threads Dictionary</title>
-      <refentry id=3D"f_all-processes">
-	<indexterm zone=3D"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> =3D> 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=3D"inline">
-	    <member><xref linkend=3D"v_current-process"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_make-process">
-	<indexterm zone=3D"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
-	    =3D> 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=3D"f_process-preset"/>) and
-	  <emphasis>enabled</emphasis>
-	  (allowed to execute, as by <xref linkend=3D"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=3D"inline">
-	    <member><xref linkend=3D"f_process-preset"/></member>
-	    <member><xref linkend=3D"f_process-enable"/></member>
-	    <member><xref linkend=3D"f_process-run-function"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-suspend">
-	<indexterm zone=3D"f_process-suspend">
-	  <primary>process-suspend</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-SUSPEND</refname>
-	  <refpurpose>Suspends a specified process.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-	=

-	<refsynopsisdiv>
-	  <synopsis><function>process-suspend</function> process
-	  =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-	  =

-	  <variablelist>
-	    <varlistentry>
-	      <term>process</term>
-	      <listitem>
-		<para>a lisp process (thread).</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>T if <varname>process</varname> had been runnable
-		and is now suspended; NIL otherwise.  That is, T if
-		<varname>process</varname>'s
-		<xref linkend=3D"f_process-suspend-count"/>
-		transitioned from 0 to 1.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Suspends <varname>process</varname>, 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 <function>process-suspend</function> must be reversed by
-	  a matching call to <xref linkend=3D"f_process-resume"/>
-	  before <varname>process</varname> is able to run.  What
-	  <function>process-suspend</function> actually does is increment
-	  the <xref linkend=3D"f_process-suspend-count"/> of
-	  <varname>process</varname>.
-	  </para>
-
-	  <para>A process can suspend itself; it it&#39;s successful in doing
-	  so, then it can obviously only be resumed by some other
-	  process.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_process-resume"/></member>
-	    <member><xref linkend=3D"f_process-suspend-count"/></member>
-	  </simplelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-	  <para><function>process-suspend</function> was previously called
-	  <function>process-disable</function>.
-	  <xref linkend=3D"f_process-enable"/>
-	  now names a function for which there is no
-	  obvious inverse, so <function>process-disable</function>
-	  is no longer
-	  defined.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-resume">
-	<indexterm zone=3D"f_process-resume">
-	  <primary>process-resume</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-RESUME</refname>
-	  <refpurpose>Resumes a specified process which had previously
-	  been suspended by process-suspend.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-resume</function> process
-	  =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-	  =

-	  <variablelist>
-	    <varlistentry>
-	      <term>process</term>
-	      <listitem>
-		<para>a lisp process (thread).</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>T if <varname>process</varname> had been suspended
-		and is now runnable; NIL otherwise.  That is, T if
-		<varname>process</varname>'s
-		<xref linkend=3D"f_process-suspend-count"/>
-		transitioned from  to 0.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Undoes the effect of a previous call to
-	  <xref linkend=3D"f_process-suspend"/>; if
-	  all such calls are undone, makes the process runnable. Has no
-	  effect if the process is not suspended.  What
-	  <function>process-resume</function> actually does is decrement
-	  the <xref linkend=3D"f_process-suspend-count"/> of
-	  <varname>process</varname>, to a minimum of 0.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_process-suspend"/></member>
-	    <member><xref linkend=3D"f_process-suspend-count"/></member>
-	  </simplelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <para>
-	    This was previously called PROCESS-ENABLE;
-	    <xref linkend=3D"f_process-enable"/> now does something slightly
-	    different.
-	  </para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-suspend-count">
-	<indexterm zone=3D"f_process-suspend-count">
-	  <primary>process-suspend-count</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-SUSPEND-COUNT</refname>
-	  <refpurpose>Returns the number of currently-pending suspensions
-	  applicable to a given process.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>process-suspend-count</function>
-	    process =3D> result
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>process</term>
-	      <listitem>
-		<para>a lisp process (thread).</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>The number of "outstanding"
-		<xref linkend=3D"f_process-suspend"/> calls on
-		<varname>process</varname>, or NIL if
-		<varname>process</varname> has expired.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>An "outstanding" <xref linkend=3D"f_process-suspend"/> call
-	  is one which has not yet been reversed by a call to
-	  <xref linkend=3D"f_process-resume"/>.  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
-	  <function>process-suspend-count</function> of 0, has been
-	  preset as by <xref linkend=3D"f_process-preset"/>, and has been
-	  enabled as by <xref linkend=3D"f_process-enable"/>.  Newly-created
-	  processes have a <function>process-suspend-count</function> of
-	  0.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_process-suspend"/></member>
-	    <member><xref linkend=3D"f_process-resume"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-preset">
-	<indexterm zone=3D"f_process-preset">
-	  <primary>process-preset</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-PRESET</refname>
-	  <refpurpose>Sets the initial function and arguments of a specified
-	  process.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-preset</function>
-	  process function &rest; args
-	  =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>process</term>
-	      <listitem>
-		<para>a lisp process (thread).</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>function</term>
-	      <listitem>
-		<para>a function, designated by itself or by a symbol
-		which names it.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>args</term>
-	      <listitem>
-		<para>a list of values, appropriate as arguments to
-		<varname>function</varname>.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>undefined.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Typically used to initialize a newly-created or newly-reset
-	  process, setting things up so that when <varname>process</varname>
-	  becomes enabled, it will begin execution by
-	  applying <varname>function</varname> to <varname>args</varname>.
-	  <function>process-preset</function> does not enable
-	  <varname>process</varname>,
-	  although a process must be <function>process-preset</function>
-	  before it can be enabled.  Processes are normally enabled by
-	  <xref linkend=3D"f_process-enable"/>.
-	  </para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-process"/></member>
-	    <member><xref linkend=3D"f_process-enable"/></member>
-	    <member><xref linkend=3D"f_process-run-function"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-enable">
-	<indexterm zone=3D"f_process-enable">
-	  <primary>process-enable</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-ENABLE</refname>
-	  <refpurpose>Begins executing the initial function of a specified
-	  process.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-enable</function>
-	  process &optional; timeout
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>process</term>
-	      <listitem>
-		<para>a lisp process (thread).</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>timeout</term>
-	      <listitem>
-		<para>a time interval in seconds.  May be any
-		non-negative real number the <function>floor</function> of
-		which fits in 32 bits.  The default is 1.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>undefined.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Tries to begin the execution of <varname>process</varname>.
-	  An error is signaled if <varname>process</varname> has never
-	  been <xref linkend=3D"f_process-preset"/>.  Otherwise,
-	  <varname>process</varname> invokes its initial function.
-	  </para>
-	  =

-	  <para><function>process-enable</function> attempts to
-	  synchronize with <varname>process</varname>, 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
-	  <varname>timeout</varname>, a continuable error is signaled,
-	  which offers the opportunity to continue waiting.
-	  </para>
-
-	  <para>A process cannot meaningfully attempt to enable itself.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-process"/></member>
-	    <member><xref linkend=3D"f_process-preset"/></member>
-	    <member><xref linkend=3D"f_process-run-function"/></member>
-	  </simplelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <para>It would be nice to have more discussion of what it means
-	  to synchronize with the process.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-run-function">
-	<indexterm zone=3D"f_process-run-function">
-	  <primary>process-run-function</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-RUN-FUNCTION</refname>
-	  <refpurpose>Creates a process, presets it, and enables it.
-	  </refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-run-function</function>
-	  process-specifier function &rest; args =3D> process</synopsis>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>process-specifier</term>
-	      <listitem>
-		<para>
-		  <varname>name</varname> | =

-		  (&key; <varname>name</varname>
-		  <varname>persistent</varname>
-		  <varname>priority</varname>
-		  <varname>class</varname>
-		  <varname>stack-size</varname>
-		  <varname>vstack-size</varname>
-		  <varname>tstack-size</varname>)
-		</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>name</term>
-	      <listitem>
-		<para>a string, used to identify the process.
-		Passed to <function>make-process</function>.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>function</term>
-	      <listitem>
-		<para>a function, designated by itself or by a symbol
-		which names it.  Passed to
-		<function>preset-process</function>.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>persistent</term>
-	      =

-	      <listitem>
-		<para>a boolean, passed to <function>make-process</function>.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	    =

-	    <varlistentry>
-	      <term>priority</term>
-	      =

-	      <listitem>
-		<para>ignored.</para>
-	      </listitem>
-	    </varlistentry>
-	    =

-	    <varlistentry>
-	      <term>class</term>
-	      =

-	      <listitem>
-		<para>a subclass of CCL:PROCESS.  Passed to
-		<function>make-process</function>.</para>
-	      </listitem>
-	    </varlistentry>
-	    =

-	    <varlistentry>
-	      <term>stack-size</term>
-	      =

-	      <listitem>
-		<para>a size, in bytes.  Passed to
-		<function>make-process</function>.</para>
-	      </listitem>
-	    </varlistentry>
-	    =

-	    <varlistentry>
-	      <term>vstack-size</term>
-	      =

-	      <listitem>
-		<para>a size, in bytes.  Passed to
-		<function>make-process</function>.</para>
-	      </listitem>
-	    </varlistentry>
-	    =

-	    <varlistentry>
-	      <term>tstack-size</term>
-	      =

-	      <listitem>
-		<para>a size, in bytes.  Passed to
-		<function>make-process</function>.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>process</term>
-	      <listitem>
-		<para>the newly-created process.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Creates a lisp process (thread) via
-	  <xref linkend=3D"f_make-process"/>,
-	  presets it via <xref linkend=3D"f_process-preset"/>, and
-	  enables it via <xref linkend=3D"f_process-enable"/>.  This means
-	  that <varname>process</varname> will immediately begin to
-	  execute.
-	  <function>process-run-function</function> is
-	  the simplest way to create and run a process.
-	  </para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-process"/></member>
-	    <member><xref linkend=3D"f_process-preset"/></member>
-	    <member><xref linkend=3D"f_process-enable"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-interrupt">
-	<indexterm zone=3D"f_process-interrupt">
-	  <primary>process-interrupt</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-INTERRUPT</refname>
-	  <refpurpose>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.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-interrupt</function>
-	  process function &rest; args =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>process</term>
-	      <listitem>
-		<para>a lisp process (thread).</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>function</term>
-	      <listitem>
-		<para>a function.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>args</term>
-	      <listitem>
-		<para>a list of values, appropriate as arguments to
-		<varname>function</varname>.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>the result of applying <varname>function</varname>
-		to <varname>args</varname> if <varname>proceess</varname>
-		is the <function>current-process</function>, otherwise
-		NIL.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Arranges for <varname>process</varname>
-	  to apply <varname>function</varname> to <varname>args</varname> at
-	  some point in the near future (interrupting whatever
-	  <varname>process</varname>
-	  was doing.) If <varname>function</varname> returns normally,
-	  <varname>process</varname> resumes
-	  execution at the point at which it was interrupted.</para>
-
-	  <para><varname>process</varname> must be in an enabled state in
-	  order to respond
-	  to a <function>process-interrupt</function> request.  It's
-	  perfectly legal for a process to call
-	  <function>process-interrupt</function> on itself.</para>
-
-	  <para><function>process-interrupt</function>
-	  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>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>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"m_without-interrupts"/></member>
-	  </simplelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <para>It would probably be better for <varname>result</varname>
-	  to always be NIL, since the present behaviour is inconsistent.
-	  </para>
-
-	  <para>
-	    <function>Process-interrupt</function> works by sending signals
-	    between threads, via the C function
-	    <function>#_pthread_signal</function>.  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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"v_current-process">
-	<indexterm zone=3D"v_current-process">
-	  <primary>*current-process*</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>*CURRENT-PROCESS*</refname>
-	  <refpurpose>Bound in each process, to that process
-	  itself.</refpurpose>
-	  <refclass>Variable</refclass>
-	</refnamediv>
-
-	<refsect1>
-	  <title>Value Type</title>
-
-	  <para>A lisp process (thread).</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>Initial Value</title>
-	  =

-	  <para>Bound separately in each process, to that process itself.
-	  </para>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Used when lisp code needs to find out what process it is
-	  executing in.  Shouldn't be set by user code.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_all-processes"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-reset">
-	<indexterm zone=3D"f_process-reset">
-	  <primary>process-reset</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-RESET</refname>
-	  <refpurpose>Causes a specified process to cleanly exit from
-	  any ongoing computation.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-reset</function>
-	  process &optional; kill-option =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>process</term>
-	      <listitem>
-		<para>a lisp process (thread).</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>kill-option</term>
-	      <listitem>
-		<para>a generalized boolean.  The default is T.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>undefined.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Causes <varname>process</varname> to cleanly exit
-	  from any ongoing computation.  If <varname>kill-option</varname>
-	  is true, <varname>process</varname> then exits.  Otherwise, it
-	  enters a state where it can be
-	  <xref linkend=3D"f_process-preset"/>. 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
-	  <varname>process</varname>
-	  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.
-	  <xref linkend=3D"f_process-enable"/>
-	  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 <function>unwind-protect</function> cleanup
-	  forms, and of the OS scheduler.</para>
-
-	  <para>Resetting a process other than
-	  <xref linkend=3D"v_current-process"/> involves the
-	  use of <xref linkend=3D"f_process-interrupt"/>.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_process-kill"/></member>
-	    <member><xref linkend=3D"f_process-abort"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-kill">
-	<indexterm zone=3D"f_process-kill">
-	  <primary>process-kill</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-KILL</refname>
-	  <refpurpose>Causes a specified process to cleanly exit from any
-	  ongoing computation, and then exit.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-kill</function> process
-	  =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>process</term>
-	      <listitem>
-		<para>a lisp process (thread).</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>undefined.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Entirely equivalent to calling
-	  (PROCESS-RESET PROCESS T).  Causes <varname>process</varname>
-	  to cleanly exit from any ongoing computation, and then exit.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	  =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_process-reset"/></member>
-	    <member><xref linkend=3D"f_process-abort"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-abort">
-	<indexterm zone=3D"f_process-abort">
-	  <primary>process-abort</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-ABORT</refname>
-	  <refpurpose>Causes a specified process to process an abort
-	  condition, as if it had invoked
-	  <function>abort</function>.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-abort</function> process
-	  &optional; condition
-	  =3D> NIL</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>process</term>
-	      <listitem>
-		<para>a lisp process (thread).</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>condition</term>
-	      <listitem>
-		<para>a lisp condition.  The default is NIL.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Entirely equivalent to calling
-	  (<xref linkend=3D"f_process-interrupt"/> <varname>process</varname>
-	  (<function>lambda</function> ()
-	  (<function>abort</function> <varname>condition</varname>))).
-	  Causes <varname>process</varname> to transfer control to the
-	  applicable handler or restart for <function>abort</function>.</para>
-
-	  <para>If <varname>condition</varname> is non-NIL,
-	  <function>process-abort</function> does not consider any
-	  handlers which are explicitly bound to conditions other than
-	  <varname>condition</varname>.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	  =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_process-reset"/></member>
-	    <member><xref linkend=3D"f_process-kill"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"v_ticks-per-second">
-	<indexterm zone=3D"v_ticks-per-second">
-	  <primary>*ticks-per-second*</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>*TICKS-PER-SECOND*</refname>
-	  <refpurpose>Bound to the clock resolution of the OS
-	  scheduler.</refpurpose>
-	  <refclass>Variable</refclass>
-	</refnamediv>
-
-	  <refsect1>
-	    <title>Value Type</title>
-
-	    <para>A positive integer.</para>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Initial Value</title>
-	    =

-	    <para>The clock resoluton of the OS scheduler.  Currently,
-	    both LinuxPPC and DarwinPPC yeild an initial value of 100.
-	    </para>
-	  </refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_process-wait-with-timeout"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-whostate">
-	<indexterm zone=3D"f_process-whostate">
-	  <primary>process-whostate</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-WHOSTATE</refname>
-	  <refpurpose>Returns a string which describes the status of
-	  a specified process.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-whostate</function> process
-	  =3D> whostate</synopsis>
-	  <variablelist>
-	    <varlistentry>
-	      <term>process</term>
-	      <listitem>
-		<para>a lisp process (thread).</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>whostate</term>
-	      <listitem>
-		<para>a string which describes the "state" of
-		<varname>process</varname>.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>This information is primarily for the benefit of
-	  debugging tools.  <varname>whostate</varname> is a terse report
-	  on what <varname>process</varname> is doing, or not doing,
-	  and why.</para>
-
-	  <para>If the process is currently waiting in a call to
-	  <xref linkend=3D"f_process-wait"/> or
-	  <xref linkend=3D"f_process-wait-with-timeout"/>, its
-	  <function>process-whostate</function> will be the value
-	  which was passed to that function as <varname>whostate</varname>.
-	  </para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_process-wait"/></member>
-	    <member><xref linkend=3D"f_process-wait-with-timeout"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <para>This should arguably be SETFable, but doesn't seem to
-	  ever have been.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-allow-schedule">
-	<indexterm zone=3D"f_process-allow-schedule">
-	  <primary>process-allow-schedule</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-ALLOW-SCHEDULE</refname>
-	  <refpurpose>Used for cooperative multitasking; probably never
-	  necessary.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-allow-schedule</function></synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <para>This is a holdover from the days of cooperative
-	  multitasking.  All modern general-purpose operating systems use
-	  preemptive multitasking.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-wait">
-	<indexterm zone=3D"f_process-wait">
-	  <primary>process-wait</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-WAIT</refname>
-	  <refpurpose>Causes the current lisp process (thread) to wait for
-	  a given
-	  predicate to return true.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-wait</function>
-	  whostate function &rest; args =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>whostate</term>
-
-	      <listitem>
-		<para>a string, which will be the value of
-		<xref linkend=3D"f_process-whostate"/>
-		while the process is waiting.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>function</term>
-	      <listitem>
-		<para>a function, designated by itself or by a symbol
-		which names it.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>args</term>
-	      <listitem>
-		<para>a list of values, appropriate as arguments to
-		<varname>function</varname>.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>NIL.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Causes the current lisp process (thread) to repeatedly
-	  apply <varname>function</varname> to
-	  <varname>args</varname> until the call returns a true result, then
-	  returns NIL. After
-	  each failed call, yields the CPU as if by
-	  <xref linkend=3D"f_process-allow-schedule"/>.</para>
-	  =

-	  <para>
-	  As with <xref linkend=3D"f_process-allow-schedule"/>, 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>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_process-whostate"/></member>
-	    <member><xref linkend=3D"f_process-wait-with-timeout"/></member>
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-wait-with-timeout">
-	<indexterm zone=3D"f_process-wait-with-timeout">
-	  <primary>process-wait-with-timeout</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-WAIT-WITH-TIMEOUT</refname>
-	  <refpurpose>Causes the current thread to wait for a given
-	  predicate to return true, or for a timeout to expire.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-wait-with-timeout</function>
-	  whostate ticks function args =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>whostate</term>
-	      <listitem>
-		<para>a string, which will be the value of
-		<xref linkend=3D"f_process-whostate"/>
-		while the process is waiting.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>ticks</term>
-	      <listitem>
-		<para>either a positive integer expressing a duration
-		in "ticks" (see <xref linkend=3D"v_ticks-per-second"/>),
-		or NIL.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>function</term>
-	      <listitem>
-		<para>a function, designated by itself or by a symbol
-		which names it.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>args</term>
-	      <listitem>
-		<para>a list of values, appropriate as arguments to
-		<varname>function</varname>.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>T if <function>process-wait-with-timeout</function>
-		returned because its <varname>function</varname> returned
-		true, or NIL if it returned because the duration
-		<varname>ticks</varname> has been exceeded.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>If <varname>ticks</varname> is NIL, behaves exactly like
-	  <xref linkend=3D"f_process-wait"/>, except for returning T.
-	  Otherwise, <varname>function</varname> will be tested repeatedly,
-	  in the same
-	  kind of test/yield loop as in <xref linkend=3D"f_process-wait"/>>
-	  until either <varname>function</varname> returns true,
-	  or the duration <varname>ticks</varname> has been exceeded.
-	  </para>
-
-	  <para> Having already read the descriptions of
-	  <xref linkend=3D"f_process-allow-schedule"/> and
-	  <xref linkend=3D"f_process-wait"/>, the
-	  astute reader has no doubt anticipated the observation that
-	  better alternatives should be used whenever possible.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"v_ticks-per-second"/></member>
-	    <member><xref linkend=3D"f_process-whostate"/></member>
-	    <member><xref linkend=3D"f_process-wait"/></member>
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_without-interrupts">
-	<indexterm zone=3D"m_without-interrupts">
-	  <primary>without-interrupts</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>WITHOUT-INTERRUPTS</refname>
-	  <refpurpose>Evaluates its body in an environment in which
-	  process-interrupt requests are deferred.</refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>without-interrupts</function>
-	  &body; body =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>body</term>
-	      <listitem>
-		<para>an implicit progn.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>the primary value returned by
-		<varname>body</varname>.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Executes <varname>body</varname>
-	  in an environment in which <xref linkend=3D"f_process-interrupt"/>
-	  requests are
-	  deferred. As noted in the description of
-	  <xref linkend=3D"f_process-interrupt"/>, this has nothing to do
-	  with the
-	  scheduling of other threads; it may be necessary to inhibit
-	  <xref linkend=3D"f_process-interrupt"/> handling when
-	  (for instance) modifying some data
-	  structure (for which the current thread holds an appropriate lock)
-	  in some manner that&#39;s not reentrant.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_process-interrupt"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_make-lock">
-	<indexterm zone=3D"f_make-lock">
-	  <primary>make-lock</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>MAKE-LOCK</refname>
-	  <refpurpose>Creates and returns a lock object, which can
-	  be used for synchronization between threads.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>make-lock</function> &optional;
-	  name =3D> lock</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>name</term>
-	      <listitem>
-		<para>any lisp object; saved as part of
-		<varname>lock</varname>.  Typically a string or symbol
-		which may appear in the <xref linkend=3D"f_process-whostate"/>s
-		of threads which are waiting for <varname>lock</varname>.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>lock</term>
-	      <listitem>
-		<para>a newly-allocated object of type CCL:LOCK.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Creates and returns a lock object, which can
-	  be used to synchronize access to some shared resource.
-	  <varname>lock</varname> is
-	  initially in a &#34;free&#34; state; a lock can also be
-	  &#34;owned&#34; by a
-	  thread.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"m_with-lock-grabbed"/></member>
-	    <member><xref linkend=3D"f_grab-lock"/></member>
-	    <member><xref linkend=3D"f_release-lock"/></member>
-	    <member><xref linkend=3D"f_try-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_with-lock-grabbed">
-	<indexterm zone=3D"m_with-lock-grabbed">
-	  <primary>with-lock-grabbed</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>WITH-LOCK-GRABBED</refname>
-	  <refpurpose>Waits until a given lock can be obtained, then
-	  evaluates its body with the lock held.</refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>with-lock-grabbed</function>
-	  (lock) &body; body</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>lock</term>
-	      <listitem>
-		<para>an object of type CCL:LOCK.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>body</term>
-	      <listitem>
-		<para>an implicit progn.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>the primary value returned by
-		<varname>body</varname>.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Waits until <varname>lock</varname> is either free or
-	  owned by the calling
-	  thread, then excutes <varname>body</varname> with the
-	  lock owned by the calling thread. If <varname>lock</varname>
-	  was free when <function>with-lock-grabbed</function> was called,
-	  it is restored to a free state after <varname>body</varname>
-	  is executed.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_grab-lock"/></member>
-	    <member><xref linkend=3D"f_release-lock"/></member>
-	    <member><xref linkend=3D"f_try-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_grab-lock">
-	<indexterm zone=3D"f_grab-lock">
-	  <primary>grab-lock</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>GRAB-LOCK</refname>
-	  <refpurpose>Waits until a given lock can be obtained, then
-	  obtains it.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>grab-lock</function> lock</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>lock</term>
-	      <listitem>
-		<para>an object of type CCL:LOCK.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Blocks until <varname>lock</varname> is owned by the
-	  calling thread.</para>
-
-	  <para>The macro <xref linkend=3D"m_with-lock-grabbed"/>
-	  <emphasis>could</emphasis> be defined in
-	  terms of <function>grab-lock</function> and
-	  <xref linkend=3D"f_release-lock"/>, but it is actually
-	  implemented at a slightly lower level.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"m_with-lock-grabbed"/></member>
-	    <member><xref linkend=3D"f_release-lock"/></member>
-	    <member><xref linkend=3D"f_try-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_release-lock">
-	<indexterm zone=3D"f_release-lock">
-	  <primary>release-lock</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>RELEASE-LOCK</refname>
-	  <refpurpose>Relinquishes ownership of a given lock.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>release-lock</function> lock</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>lock</term>
-	      <listitem>
-		<para>an object of type CCL:LOCK.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Signals an error of type CCL:LOCK-NOT-OWNER if
-	  <varname>lock</varname>
-	  is not already owned by the calling thread; otherwise, undoes the
-	  effect of one previous =

-	  <xref linkend=3D"f_grab-lock"/>.  If this means that
-	  <function>release-lock</function> has now been called on
-	  <varname>lock</varname> the same number of times as
-	  <xref linkend=3D"f_grab-lock"/> has, <varname>lock</varname>
-	  becomes free.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"m_with-lock-grabbed"/></member>
-	    <member><xref linkend=3D"f_grab-lock"/></member>
-	    <member><xref linkend=3D"f_try-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_try-lock">
-	<indexterm zone=3D"f_try-lock">
-	  <primary>try-lock</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>TRY-LOCK</refname>
-	  <refpurpose>Obtains the given lock, but only if it is not
-	  necessary to wait for it.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>try-lock</function> lock =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>lock</term>
-	      <listitem>
-		<para>an object of type CCL:LOCK.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>T if <varname>lock</varname> has been obtained,
-		or NIL if it has not.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Tests whether <varname>lock</varname>
-	  can be obtained without blocking - that is, either
-	  <varname>lock</varname> is already free, or it is already owned
-	  by <xref linkend=3D"v_current-process"/>.  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>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"m_with-lock-grabbed"/></member>
-	    <member><xref linkend=3D"f_grab-lock"/></member>
-	    <member><xref linkend=3D"f_release-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_make-read-write-lock">
-	<indexterm zone=3D"f_make-read-write-lock">
-	  <primary>make-read-write-lock</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>MAKE-READ-WRITE-LOCK</refname>
-	  <refpurpose>Creates and returns a read-write lock, which can
-	  be used for synchronization between threads.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>make-read-write-lock</function>
-	  =3D> read-write-lock</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>read-write-lock</term>
-	      <listitem>
-		<para>a newly-allocated object of type
-		CCL:READ-WRITE-LOCK.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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, <varname>read-write-lock</varname> has
-	  no readers and no writers.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"m_with-read-lock"/></member>
-	    <member><xref linkend=3D"m_with-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <para>There probably should be some way to
-	  atomically &#34;promote&#34; a reader, making it a writer without
-	  releasing the lock, which could otherwise cause delay.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_with-read-lock">
-	<indexterm zone=3D"m_with-read-lock">
-	  <primary>with-read-lock</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>WITH-READ-LOCK</refname>
-	  <refpurpose>Waits until a given lock is available for
-	  read-only access, then evaluates its body with the lock
-	  held.</refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>with-read-lock</function>
-	  (read-write-lock) &body; body =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>read-write-lock</term>
-	      <listitem>
-		<para>an object of type
-		CCL:READ-WRITE-LOCK.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>body</term>
-	      <listitem>
-		<para>an implicit progn.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>the primary value returned by
-		<varname>body</varname>.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Waits until <varname>read-write-lock</varname> has no
-	  writer,
-	  ensures that <xref linkend=3D"v_current-process"/> is a
-	  reader of it, then executes <varname>body</varname>.
-	  </para>
-
-	  <para>After executing <varname>body</varname>, if
-	  <xref linkend=3D"v_current-process"/> was not a reader of
-	  <varname>read-write-lock</varname> before
-	  <function>with-read-lock</function> was called, the lock is
-	  released.  If it was already a reader, it remains one.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"m_with-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_with-write-lock">
-	<indexterm zone=3D"m_with-write-lock">
-	  <primary>with-write-lock</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>WITH-WRITE-LOCK</refname>
-	  <refpurpose>Waits until the given lock is available for write
-	  access, then executes its body with the lock held.</refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>with-write-lock</function>
-	  (read-write-lock) &body; body</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>read-write-lock</term>
-	      <listitem>
-		<para>an object of type
-		CCL:READ-WRITE-LOCK.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>body</term>
-	      <listitem>
-		<para>an implicit progn.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>the primary value returned by
-		<varname>body</varname>.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Waits until <varname>read-write-lock</varname> has no
-	  readers and no writer other than <xref linkend=3D"v_current-process"/>,
-	  then ensures that <xref linkend=3D"v_current-process"/> is the
-	  writer of it.  With the lock held, executes <varname>body</varname>.
-	  </para>
-
-	  <para>After executing <varname>body</varname>, if
-	  <xref linkend=3D"v_current-process"/> was not the writer of
-	  <varname>read-write-lock</varname> before
-	  <function>with-write-lock</function> was called, the lock is
-	  released.  If it was already the writer, it remains the
-	  writer.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"m_with-read-lock"/></member>
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_make-semaphore">
-	<indexterm zone=3D"f_make-semaphore">
-	  <primary>make-semaphore</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>MAKE-SEMAPHORE</refname>
-	  <refpurpose>Creates and returns a semaphore, which can be used
-	  for synchronization between threads.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>make-semaphore</function>
-	  =3D> semaphore</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-	  =

-	  <variablelist>
-	    <varlistentry>
-	      <term>semaphore</term>
-	      <listitem>
-		<para>a newly-allocated object of type CCL:SEMAPHORE.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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.
-	  <varname>semaphore</varname> has an initial count of 0.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_signal-semaphore"/></member>
-	    <member><xref linkend=3D"f_wait-on-semaphore"/></member>
-	    <member><xref linkend=3D"f_timed-wait-on-semaphore"/></member>
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_signal-semaphore">
-	<indexterm zone=3D"f_signal-semaphore">
-	  <primary>signal-semaphore</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>SIGNAL-SEMAPHORE</refname>
-	  <refpurpose>Atomically increments the count of a given
-	  semaphore.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>signal-semaphore</function>
-	  semaphore =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-	  =

-	  <variablelist>
-	    <varlistentry>
-	      <term>semaphore</term>
-	      <listitem>
-		<para>an object of type CCL:SEMAPHORE.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>an integer representing an error identifier
-		which was returned by the underlying OS call.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Atomically increments <varname>semaphore</varname>'s
-	  "count" by 1; this
-	  may enable a waiting thread to resume execution.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_wait-on-semaphore"/></member>
-	    <member><xref linkend=3D"f_timed-wait-on-semaphore"/></member>
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <para><varname>result</varname> should probably be interpreted
-	  and acted on by <function>signal-semaphore</function>, because
-	  it is not likely to be meaningful to a lisp program, and the
-	  most common cause of failure is a type error.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_wait-on-semaphore">
-	<indexterm zone=3D"f_wait-on-semaphore">
-	  <primary>wait-on-semaphore</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>WAIT-ON-SEMAPHORE</refname>
-	  <refpurpose>Waits until the given semaphore has a positive
-	  count which can be atomically decremented.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>wait-on-semaphore</function>
-	  semaphore =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-	  =

-	  <variablelist>
-	    <varlistentry>
-	      <term>semaphore</term>
-	      <listitem>
-		<para>an object of type CCL:SEMAPHORE.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>an integer representing an error identifier
-		which was returned by the underlying OS call.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Waits until <varname>semaphore</varname>
-	  has a positive count that can be
-	  atomically decremented; this will succeed exactly once for each
-	  corresponding call to SIGNAL-SEMAPHORE.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_signal-semaphore"/></member>
-	    <member><xref linkend=3D"f_timed-wait-on-semaphore"/></member>
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <para><varname>result</varname> should probably be interpreted
-	  and acted on by <function>wait-on-semaphore</function>, because
-	  it is not likely to be meaningful to a lisp program, and the
-	  most common cause of failure is a type error.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_timed-wait-on-semaphore">
-	<indexterm zone=3D"f_timed-wait-on-semaphore">
-	  <primary>timed-wait-on-semaphore</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>TIMED-WAIT-ON-SEMAPHORE</refname>
-	  <refpurpose>Waits until the given semaphore has a postive
-	  count which can be atomically decremented, or until a timeout
-	  expires.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>timed-wait-on-semaphore</function>
-	  semaphore timeout =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-	  =

-	  <variablelist>
-	    <varlistentry>
-	      <term>semaphore</term>
-	      <listitem>
-		<para>An object of type CCL:SEMAPHORE.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>timeout</term>
-	      <listitem>
-		<para>a time interval in seconds.  May be any
-		non-negative real number the <function>floor</function> of
-		which fits in 32 bits.  The default is 1.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>T if <function>timed-wait-on-semaphore</function>
-		returned because it was able to decrement the count of
-		<varname>semaphore</varname>; NIL if it returned because
-		the duration <varname>timeout</varname> has been
-		exceeded.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Waits until <varname>semaphore</varname>
-	  has a positive count that can be
-	  atomically decremented, or until the duration
-	  <varname>timeout</varname> has
-	  elapsed.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_wait-on-semaphore"/></member>
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-input-wait">
-	<indexterm zone=3D"f_process-input-wait">
-	  <primary>process-input-wait</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-INPUT-WAIT</refname>
-	  <refpurpose>Waits until input is available on a given
-	  file-descriptor.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-input-wait</function>
-	  fd &optional; timeout</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-	  =

-	  <variablelist>
-	    <varlistentry>
-	      <term>fd</term>
-	      <listitem>
-		<para>a file descriptor, which is a non-negative integer
-		used by the OS to refer to an open file, socket, or similar
-		I/O connection.  See <xref linkend=3D"f_stream-device"/>.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>timeout</term>
-	      <listitem>
-		<para>either NIL, or a time interval in seconds.  May be any
-		non-negative real number the <function>floor</function> of
-		which fits in 32 bits.  The default is NIL.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Wait until input is available on <varname>fd</varname>.
-	  This uses the <function>select()</function> system call, and is
-	  generally a fairly
-	  efficient way of blocking while waiting for input. More
-	  accurately, <function>process-input-wait</function>
-	  waits until it&#39;s possible to read
-	  from fd without blocking, or until <varname>timeout</varname>, if
-	  it is not NIL, has been exceeded.</para>
-
-	  <para>
-	  Note that it&#39;s possible to read without blocking if
-	  the file is at its end - although, of course, the read will
-	  return zero bytes.</para>
-	</refsect1>
-	=

-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <para>
-	  <function>process-input-wait</function> has a timeout parameter,
-	  and
-	  <xref linkend=3D"f_process-output-wait"/> does not.  This
-	  inconsistency should probably be corrected.
-	  </para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_process-output-wait">
-	<indexterm zone=3D"f_process-output-wait">
-	  <primary>process-output-wait</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PROCESS-OUTPUT-WAIT</refname>
-	  <refpurpose>Waits until output is possible on a given file
-	  descriptor.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>process-output-wait</function> fd</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-	  =

-	  <variablelist>
-	    <varlistentry>
-	      <term>fd</term>
-	      <listitem>
-		<para>a file descriptor, which is a non-negative integer
-		used by the OS to refer to an open file, socket, or similar
-		I/O connection.  See <xref linkend=3D"f_stream-device"/>.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Wait until output is possible on <varname>fd</varname>.
-	  This uses the <function>select()</function> system call, and is
-	  generally a fairly
-	  efficient way of blocking while waiting to output.</para>
-
-	  <para>If <function>process-output-wait</function> 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>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	  </simplelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <para>
-	  <xref linkend=3D"f_process-input-wait"/> has a timeout parameter,
-	  and
-	  <function>process-output-wait</function> does not.  This
-	  inconsistency should probably be corrected.
-	  </para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_with-terminal-input">
-	<indexterm zone=3D"m_with-terminal-input">
-	  <primary>with-terminal-input</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>WITH-TERMINAL-INPUT</refname>
-	  <refpurpose>Executes its body in an environment with exclusive
-	  read access to the terminal.</refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>with-terminal-input</function>
-	  &body; body =3D> result</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-	  =

-	  <variablelist>
-	    <varlistentry>
-	      <term>body</term>
-	      <listitem>
-		<para>an implicit progn.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>result</term>
-	      <listitem>
-		<para>the primary value returned by
-		<varname>body</varname>.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Requests exclusive read access to the standard terminal
-	  stream, <varname>*terminal-io*</varname>.  Executes
-	  <varname>body</varname> in an environment with that access.
-	  </para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref
-	              linkend=3D"v_request-terminal-input-via-break"/></member>
-	    <member><xref linkend=3D"cmd_y"/></member>
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"v_request-terminal-input-via-break">
-	<indexterm zone=3D"v_request-terminal-input-via-break">
-	  <primary>request-terminal-input-via-break</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>*REQUEST-TERMINAL-INPUT-VIA-BREAK*</refname>
-	  <refpurpose>Controls how attempts to obtain ownership of
-	  terminal input are made.</refpurpose>
-	  <refclass>Variable</refclass>
-	</refnamediv>
-
-	<refsect1>
-	  <title>Value Type</title>
-
-	  <para>A boolean.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>Initial Value</title>
-	  =

-	  <para>NIL.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	    <member><xref linkend=3D"cmd_y"/></member>
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"cmd_y">
-	<indexterm zone=3D"cmd_y">
-	  <primary>:y</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>:Y</refname>
-	  <refpurpose>Yields control of terminal input to a specified
-	  lisp process (thread).</refpurpose>
-	  <refclass>Toplevel Command</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>(<function>:y</function> p)</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>p</term>
-	      <listitem>
-		<para>a lisp process (thread), designated either by
-		an integer which matches its
-		<function>process-serial-number</function>,
-		or by a string which is <function>equal</function> to
-		its <function>process-name</function>.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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 <varname>p</varname>, which must have used
-	  <xref linkend=3D"m_with-terminal-input"/> to request access to the
-	  terminal input stream.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-	 =

-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"m_with-terminal-input"/></member>
-	    <member><xref
-	              linkend=3D"v_request-terminal-input-via-break"/></member>
-	    <member><xref linkend=3D"f_make-lock"/></member>
-	    <member><xref linkend=3D"f_make-read-write-lock"/></member>
-	    <member><xref linkend=3D"f_make-semaphore"/></member>
-	    <member><xref linkend=3D"f_process-input-wait"/></member>
-	    <member><xref linkend=3D"f_process-output-wait"/></member>
-	  </simplelist>
-	</refsect1>
-      </refentry>
-
-    </sect1>
-  </chapter>
-
-  <chapter id=3D"Programming-with-Sockets">
-    <title>Programming with Sockets</title>
-
-    <sect1 id=3D"Sockets-Overview">
-      <title>Overview</title>
-
-      <para>OpenMCL 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 <xref linkend=3D"f_make-socket"/>.  The type of socket
-      depends on the arguments to it, as follows:</para>
-
-      <variablelist>
-	<varlistentry>
-	  <term>tcp-stream</term>
-
-	  <listitem>
-	    <para>A buffered bi-directional stream over a TCP/IP connection.
-	    tcp-stream is a subclass of stream, and you can read and write to it
-	    using all the usual stream functions. Created by (make-socket
-	    :addess-family :internet :type :stream :connect :active ...) or by
-	    (accept-connection ...).</para>
-	  </listitem>
-	</varlistentry>
-
-	<varlistentry>
-	  <term>file-socket-stream</term>
-
-	  <listitem>
-	    <para>A buffered bi-directional stream over a &#34;UNIX domain&#34;
-	    connection. file-socket-stream is a subclass of stream, and you can
-	    read and write to it using all the usual stream functions. Created
-	    by (make-socket :address-family :file :type :stream :connect :active
-	    ...) or by (accept-connection ...),</para>
-	  </listitem>
-	</varlistentry>
-
-	<varlistentry>
-	  <term>listener-socket</term>
-
-	  <listitem>
-	    <para>A passive socket used to listen for incoming TCP/IP
-	    connections on a particular port. A listener-socket is not a stream.
-	    It doesn&#39;t support I/O. It can only be used to create new
-	    tcp-streams by accept-connection. Created by (make-socket :type
-	    :stream :connect :passive ...)</para>
-	  </listitem>
-	</varlistentry>
-
-	<varlistentry>
-	  <term>file-listener-socket</term>
-
-	  <listitem>
-	    <para>A passive socket used to listen for incoming UNIX domain
-	    connections named by a file in the local filesystem. A
-	    listener-socket is not a stream. It doesn&#39;t support I/O. It can
-	    only be used to create new file-socket-streams by accept-connection.
-	    Created by (make-socket :address-family :file :type :stream :connect
-	    :passive ...)</para>
-	  </listitem>
-	</varlistentry>
-
-	<varlistentry>
-	  <term>udp-socket</term>
-
-	  <listitem>
-	    <para>A socket representing a packet-based UDP/IP connection. A
-	    udp-socket supports I/O but it is not a stream. Instead, you must
-	    use the special functions send-to and receive-from to read and write
-	    to it. Created by (make-socket :type :datagram ...)</para>
-	  </listitem>
-	</varlistentry>
-      </variablelist>
-    </sect1>
-
-    <sect1 id=3D"Sockets-Dictionary">
-      <title>Sockets Dictionary</title>
-      <refentry id=3D"f_make-socket">
-	<indexterm zone=3D"f_make-socket">
-	  <primary>make-socket</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>MAKE-SOCKET</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>make-socket</function>
-	  &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</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>address-family</term>
-
-	      <listitem>
-		<para>The address/protocol family of this socket. Currently
-		only :internet (the default), meaning IP, and :file,
-		referring to UNIX domain addresses, are supported.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>type</term>
-
-	      <listitem>
-		<para>One of :stream (the default) to request a
-		connection-oriented socket, or :datagram to request a
-		connectionless socket. The default is :stream.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>connect</term>
-
-	      <listitem>
-		<para>This argument is only relevant to sockets of type
-		:stream. One of :active (the default) to request a :passive
-		to request a file or TCP listener socket.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>eol</term>
-
-	      <listitem>
-		<para>This argument is currently ignored (it is accepted for
-		compatibility with Franz Allegro).</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>format</term>
-
-	      <listitem>
-		<para>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. they
-		support both character and byte I/O). For :datagram sockets,
-		the format determines the type of buffer created by
-		receive-from.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>remote-host</term>
-
-	      <listitem>
-		<para>Required for TCP streams, it specifies the host to
-		connect to (in any format acceptable to lookup-hostname).
-		Ignored for listener sockets. For UDP sockets, it can be
-		used to specify a default host for subsequent calls to
-		send-to or receive-from.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>remote-port</term>
-
-	      <listitem>
-		<para>Required for TCP streams, it specifies the port to
-		connect to (in any format acceptable to lookup-port).
-		Ignored for listener sockets. For UDP sockets, it can be
-		used to specify a default port for subsequent calls to for
-		subsequent calls to send-to or receive-from.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>remote-filename</term>
-
-	      <listitem>
-		<para>Required for file-socket streams, it specifies the
-		name of a file in the local filesystem (e.g., NOT mounted
-		via NFS, AFP, SMB, ...) which names and controls access to a
-		UNIX-domain socket.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>local-host</term>
-
-	      <listitem>
-		<para>Allows you to specify a local host address for a
-		listener or UDP socket, for the rare case where you want to
-		restrict connections to those coming to a specific local
-		address for security reasons.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>local-port</term>
-
-	      <listitem>
-		<para>Specify a local port for a socket. Most useful for
-		listener sockets, where it is the port on which the socket
-		will listen for connections.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>local-filename</term>
-
-	      <listitem>
-		<para>Required for file-listener-sockets. Specifies the name
-		of a file in the local filesystem which is used to name a
-		UNIX-domain socket. The actual filesystem file should not
-		previously exist when the file-listener-socket is created;
-		its parent directory should exist and be writable by the
-		caller. The file used to name the socket will be deleted
-		when the file-listener-socket is closed.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>keepalive</term>
-
-	      <listitem>
-		<para>If true, enables the periodic transmission of
-		&#34;keepalive&#34; messages.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>reuse-address</term>
-
-	      <listitem>
-		<para>If true, allows the reuse of local ports in listener
-		sockets, overriding some TCP/IP protocol specifications. You
-		will need this if you are debugging a server..</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>nodelay</term>
-
-	      <listitem>
-		<para>If true, disables Nagle&#39;s algorithm, which tries
-		to minimize TCP packet fragmentation by introducing
-		transmission delays in the absence of replies. Try setting
-		this if you are using a protocol which involves sending a
-		steady stream of data with no replies and are seeing
-		significant degradations in throughput.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>broadcast</term>
-
-	      <listitem>
-		<para>If true, requests permission to broadcast datagrams on
-		a UDP socket.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>linger</term>
-
-	      <listitem>
-		<para>If specified and non-nil, should be the number of
-		seconds the OS is allowed to wait for data to be pushed
-		through when a close is done. Only relevant for TCP sockets.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>backlog</term>
-
-	      <listitem>
-		<para>For a listener socket, specifies the number of
-		connections which can be pending but not accepted. The
-		default is 5, which is also the maximum on some operating
-		systems.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Creates and returns a new socket</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_accept-connection">
-	<indexterm zone=3D"f_accept-connection">
-	  <primary>accept-connection</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>ACCEPT-CONNECTION</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>accept-connection</function>
-	  (socket listener-socket) &key; wait</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The listener-socket to listen on.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>wait</term>
-
-	      <listitem>
-		<para>If true (the default), and there are no connections
-		waiting to be accepted, waits until one arrives. If false,
-		returns NIL immediately.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_dotted-to-ipaddr">
-	<indexterm zone=3D"f_dotted-to-ipaddr">
-	  <primary>dotted-to-ipaddr</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>DOTTED-TO-IPADDR</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>dotted-to-ipaddr</function>
-	  dotted &key; errorp</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>dotted</term>
-
-	      <listitem>
-		<para>A string representing an IP address in the
-		&#34;nn.nn.nn.nn&#34; format</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>errorp</term>
-
-	      <listitem>
-		<para>If true (the default) an error is signaled if dotted
-		is invalid. If false, NIL is returned.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Converts a dotted-string representation of a host address to
-	  a 32-bit unsigned IP address.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_ipaddr-to-dotted">
-	<indexterm zone=3D"f_ipaddr-to-dotted">
-	  <primary>ipaddr-to-dotted</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>IPADDR-TO-DOTTED</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>ipaddr-to-dotted</function>
-	  ipaddr &key; values</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>ipaddr</term>
-
-	      <listitem>
-		<para>A 32-bit integer representing an internet host address</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>values</term>
-
-	      <listitem>
-		<para>If false (the default), returns a string in the form
-		&#34;nn.nn.nn.nn&#34;. If true, returns four values
-		representing the four octets of the address as unsigned
-		8-bit integers.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Converts a 32-bit unsigned IP address into octets.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_ipaddr-to-hostname">
-	<indexterm zone=3D"f_ipaddr-to-hostname">
-	  <primary>ipaddr-to-hostname</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>IPADDR-TO-HOSTNAME</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>ipaddr-to-hostname</function>
-	  ipaddr &key; ignore-cache</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>ipaddr</term>
-
-	      <listitem>
-		<para>a 32-bit integer representing an internet host address</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>ignore-cache</term>
-
-	      <listitem>
-		<para>This argument is ignored (it is accepted for
-		compatibility with Franz Allegro)</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Converts a 32-bit unsigned IP address into a host name
-	  string</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_lookup-hostname">
-	<indexterm zone=3D"f_lookup-hostname">
-	  <primary>lookup-hostname</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>LOOKUP-HOSTNAME</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>lookup-hostname</function>
-	  host</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>host</term>
-
-	      <listitem>
-		<para>Specifies the host. It can be either a host name
-		string such as &#34;clozure.com&#34;, or a dotted address
-		string such as &#34;192.168.0.1&#34;, or a 32-bit unsigned
-		IP address such as 3232235521.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Converts a host spec in any of the acceptable formats into a
-	  32-bit unsigned IP address</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_lookup-port">
-	<indexterm zone=3D"f_lookup-port">
-	  <primary>lookup-port</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>LOOKUP-PORT</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>lookup-port</function>
-	  port protocol</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>port</term>
-
-	      <listitem>
-		<para>Specifies the port. It can be either a string, such as
-		&#34;http&#34; or a symbol, such as :http, or an unsigned
-		port number. Note that a string is case-sensitive. A symbol
-		is lowercased before lookup.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>protocol</term>
-
-	      <listitem>
-		<para>Must be one of &#34;tcp&#34; or &#34;udp&#34;.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Finds the port number for the specified port and protocol</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_receive-from">
-	<indexterm zone=3D"f_receive-from">
-	  <primary>receive-from</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>RECEIVE-FROM</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>receive-from</function>
-	  (socket udp-socket) size &key; buffer
-	  extract offset</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket to read from</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>size</term>
-
-	      <listitem>
-		<para>Maximum number of bytes to read. If the packet is
-		larger than this, any extra bytes are discarded.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>buffer</term>
-
-	      <listitem>
-		<para>If specified, must be either a string or a byte vector
-		which will be used to read in the data. If not specified, a
-		new buffer will be created (of type determined by
-		socket-format).</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>extract</term>
-
-	      <listitem>
-		<para>If true, the subsequence of the buffer corresponding
-		only to the data read in is extracted and returned as the
-		first value. If false (the default) the original buffer is
-		returned even if it is only partially filled.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>offset</term>
-
-	      <listitem>
-		<para>Specifies the start offset into the buffer at which
-		data is to be stored. The default is 0.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Reads a UDP packet from a socket. If no packets are
-	  available, waits for a packet to arrive. Returns four values:</para>
-
-	  <orderedlist continuation=3D"restarts" inheritnum=3D"ignore">
-	    <listitem>
-	      <para>The buffer with the data</para>
-	    </listitem>
-
-	    <listitem>
-	      <para>The number of bytes read</para>
-	    </listitem>
-
-	    <listitem>
-	      <para>The 32-bit unsigned IP address of the sender of the data</par=
a>
-	    </listitem>
-
-	    <listitem>
-	      <para>The port number of the sender of the data</para>
-	    </listitem>
-	  </orderedlist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_send-to">
-	<indexterm zone=3D"f_send-to">
-	  <primary>send-to</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>SEND-TO</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>send-to</function>
-	  (socket udp-socket) buffer size &key; remote-host
-	  remote-port offset</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket to write to</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>buffer</term>
-
-	      <listitem>
-		<para>A vector containing the data to send. It must be
-		either a string or a byte vector (either one is acceptable
-		regardless of the stream format).</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>size</term>
-
-	      <listitem>
-		<para>Number of bytes to send</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>remote-host</term>
-
-	      <listitem>
-		<para>The host to send the packet to, in any format
-		acceptable to lookup-hostname. The default is the remote
-		host specified in the call to make-socket.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>remote-port</term>
-
-	      <listitem>
-		<para>The port to send the packet to, in any format
-		acceptable to lookup-port. The default is the remote port
-		specified in the call to make-socket.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>offset</term>
-
-	      <listitem>
-		<para>The offset in the buffer where the packet data starts</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Send a UDP packet over a socket.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_shutdown">
-	<indexterm zone=3D"f_shutdown">
-	  <primary>shutdown</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>SHUTDOWN</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>shutdown</function>
-	  socket &key; direction</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket to shut down (typically a tcp-stream)</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>direction</term>
-
-	      <listitem>
-		<para>One of :input to disallow further input, or :output to
-		disallow further output.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_socket-os-fd">
-	<indexterm zone=3D"f_socket-os-fd">
-	  <primary>socket-os-fd</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>SOCKET-OS-FD</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>socket-os-fd</function>
-	  socket</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns the native OS&#39;s representation of the socket, or
-	  NIL if the socket is closed. On Unix, this is the Unix &#39;file
-	  descriptor&#39;, a small non-negative integer. Note that it is
-	  rather dangerous to mess around with tcp-stream fd&#39;s, as there
-	  is all sorts of buffering and asynchronous I/O going on above the
-	  OS level. listener-socket and udp-socket fd&#39;s are safer to
-	  mess with directly as there is less magic going on.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_remote-host">
-	<indexterm zone=3D"f_remote-host">
-	  <primary>remote-host</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>REMOTE-HOST</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>remote-host</function>
-	  socket</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns the 32-bit unsigned IP address of the remote host,
-	  or NIL if the socket is not connected.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_remote-port">
-	<indexterm zone=3D"f_remote-port">
-	  <primary>remote-port</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>REMOTE-PORT</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>remote-port</function>
-	  socket</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns the remote port number, or NIL if the socket is not
-	  connected.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_local-host">
-	<indexterm zone=3D"f_local-host">
-	  <primary>local-host</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>LOCAL-HOST</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>local-host</function>
-	  socket</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns 32-bit unsigned IP address of the local host.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_local-port">
-	<indexterm zone=3D"f_local-port">
-	  <primary>local-port</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>LOCAL-PORT</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>local-port</function>
-	  socket</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns the local port number</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_socket-address-family">
-	<indexterm zone=3D"f_socket-address-family">
-	  <primary>socket-address-family</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>SOCKET-ADDRESS-FAMILY</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>socket-address-family</function>
-	  socket</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns :internet or :file, as appropriate.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_socket-connect">
-	<indexterm zone=3D"f_socket-connect">
-	  <primary>socket-connect</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>SOCKET-CONNECT</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>socket-connect</function>
-	  socket</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns :active for tcp-stream, :passive for
-	  listener-socket, and NIL for udp-socket</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_socket-format">
-	<indexterm zone=3D"f_socket-format">
-	  <primary>socket-format</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>SOCKET-FORMAT</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>socket-format</function>
-	  socket</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns the socket format as specified by the :format
-	  argument to make-socket.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_socket-type">
-	<indexterm zone=3D"f_socket-type">
-	  <primary>socket-type</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>SOCKET-TYPE</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>socket-type</function>
-	  socket</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>returns :stream for tcp-stream and listener-socket, and
-	  :datagram for udp-socket.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"c_socket-error">
-	<indexterm zone=3D"c_socket-error">
-	  <primary>socket-error</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>SOCKET-ERROR</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Class</refclass>
-	</refnamediv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>The class of OS errors signaled by socket functions</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>Superclasses</title>
-
-	  <para>simple-error</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_socket-error-code">
-	<indexterm zone=3D"f_socket-error-code">
-	  <primary>socket-error-code</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>SOCKET-ERROR-CODE</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>socket-error-code</function>
-	  socket-error</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket-error</term>
-
-	      <listitem>
-		<para>the condition</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>The OS error code of the error</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_socket-error-identifier">
-	<indexterm zone=3D"f_socket-error-identifier">
-	  <primary>socket-error-identifier</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>SOCKET-ERROR-IDENTIFIER</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>socket-error-identifier</function>
-	  socket-error</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket-error</term>
-
-	      <listitem>
-		<para>the condition</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_socket-error-situation">
-	<indexterm zone=3D"f_socket-error-situation">
-	  <primary>socket-error-situation</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>SOCKET-ERROR-SITUATION</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>socket-error-situation</function>
-	  socket-error</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket-error</term>
-
-	      <listitem>
-		<para>the condition</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"o_close">
-	<indexterm zone=3D"o_close">
-	  <primary>close</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>CLOSE</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Method</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>close</function>
-	  (socket socket) &key; abort</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>socket</term>
-
-	      <listitem>
-		<para>The socket to close</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>abort</term>
-
-	      <listitem>
-		<para>If false (the default), closes the socket in an
-		orderly fashion, finishing up any buffered pending I/O,
-		before closing the connection. If true, aborts/ignores
-		pending I/O. (For listener and udp sockets, this argument is
-		effectively ignored since there is never any buffered I/O to
-		clean up).</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>The close generic function can be applied to sockets. It
-	  releases the operating system resources associated with the
-	  socket.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_with-open-socket">
-	<indexterm zone=3D"m_with-open-socket">
-	  <primary>with-open-socket</primary>
-	</indexterm>
-	<refnamediv>
-	  <refname>WITH-OPEN-SOCKET</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>with-open-socket</function>
-	  (var . make-socket-args) &body; body</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>var</term>
-
-	      <listitem>
-		<para>variable to bind</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>make-socket-args</term>
-
-	      <listitem>
-		<para>arguments suitable for passing to make-socket</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>body</term>
-
-	      <listitem>
-		<para>body to execute</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>executes body with var bound to the result of applying
-	  make-socket to make-socket-args. The socket gets closed on exit.</para>
-	</refsect1>
-      </refentry>
-    </sect1>
-  </chapter>
-
-  <chapter id=3D"Running-Other-Programs-as-Subprocesses">
-    <title>Running Other Programs as Subprocesses</title>
-
-    <sect1 id=3D"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=3D"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=3D"Limitations-and-known-bugs">
-      <title>Limitations and known bugs</title>
-      <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=3D"External-Program-Dictionary">
-      <title>External-Program Dictionary</title>
-	<refentry id=3D"f_run-program">
-	  <indexterm zone=3D"f_run-program">
-	    <primary>run-program</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>RUN-PROGRAM</refname>
-	    <refpurpose>Invokes an external program as an OS subprocess
-	    of lisp.</refpurpose>
-	    <refclass>Function</refclass>
-	  </refnamediv>
-
-	  <refsynopsisdiv>
-	    <synopsis><function>run-program</function>
-	    program args &key; (wait t) pty input
-	    if-input-does-not-exist output (if-output-exists :error) (error
-	    :output) (if-error-exists :error) status-hook</synopsis>
-	  </refsynopsisdiv>
-
-	  <refsect1>
-	    <title>Arguments and Values</title>
-
-	    <variablelist>
-	      <varlistentry>
-		<term>program</term>
-
-		<listitem>
-		  <para>A string or pathname which denotes an executable file.
-		  The PATH environment variable is used to find programs whose
-		  name doesn't contain a directory component.</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>args</term>
-
-		<listitem>
-		  <para>A list of simple-strings</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>wait</term>
-
-		<listitem>
-		  <para>Indicates whether or not run-program should wait for
-		  the EXTERNAL-PROCESS to complete or should return
-		  immediately.</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>pty</term>
-
-		<listitem>
-		  <para>This option is accepted but currently ignored;
-		  it's intended to make it easier to run external programs
-		  that need to interact with a terminal device.</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>input</term>
-
-		<listitem>
-		  <para>Selects the input source used by the EXTERNAL-PROCESS.
-		  May be any of the following:</para>
-
-		  <itemizedlist>
-		    <listitem>
-		      <para>NIL Specifies that a null input stream (e.g.,
-		      /dev/null) should be used.</para>
-		    </listitem>
-
-		    <listitem>
-		      <para>T Specifies that the EXTERNAL-PROCESS should use
-		      the input source with which OpenMCL was invoked.</para>
-		    </listitem>
-
-		    <listitem>
-		      <para>A string or pathname. Specifies that the
-		      EXTERNAL-PROCESS should receive its input from the named
-		      existing file.</para>
-		    </listitem>
-
-		    <listitem>
-		      <para>:STREAM Creates a Lisp stream opened for character
-		      output. Any data written to this stream (accessible as
-		      the EXTERNAL-PROCESS-INPUT-STREAM of the
-		      EXTERNAL-PROCESS object) appears as input to the
-		      external process.</para>
-		    </listitem>
-
-		    <listitem>
-		      <para>A stream. Specifies that the lisp stream should
-		      provide input to the EXTERNAL-PROCESS.</para>
-		    </listitem>
-		  </itemizedlist>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>if-input-does-not-exist</term>
-
-		<listitem>
-		  <para>If the input argument specifies the name of an
-		  existing file, this argument is used as the
-		  if-does-not-exist argument to OPEN when that file is opened.</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>output</term>
-
-		<listitem>
-		  <para>Specifies where standard output from the external
-		  process should be sent. Analogous to input above.</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>if-output-exists</term>
-
-		<listitem>
-		  <para>If output is specified as a string or pathname, this
-		  argument is used as the if-exists argument to OPEN when that
-		  file is opened.</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>error</term>
-
-		<listitem>
-		  <para>Specifies where error output from the external process
-		  should be sent. In addition to the values allowed for
-		  output, the keyword :OUTPUT can be used to indicate that
-		  error output should be sent where standard output goes.</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>if-error-exists</term>
-
-		<listitem>
-		  <para>Analogous to if-output-exists.</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>status-hook</term>
-
-		<listitem>
-		  <para>A user-defined function of one argument (the
-		  EXTERNAL-PROCESS structure.) This function is called
-		  whenever OpenMCL detects a change in the staus of the
-		  EXTERNAL-PROCESS.</para>
-		</listitem>
-	      </varlistentry>
-	    </variablelist>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <para>Runs the specified program in an external (Unix) process,
-	    returning an object of type EXTERNAL-PROCESS if successful.</para>
-	  </refsect1>
-	</refentry>
-
-	<refentry id=3D"f_signal-external-process">
-	  <indexterm zone=3D"f_signal-external-process">
-	    <primary>signal-external-process</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>SIGNAL-EXTERNAL-PROCESS</refname>
-	    <refpurpose></refpurpose>
-	    <refclass>Function</refclass>
-	  </refnamediv>
-
-	  <refsynopsisdiv>
-	    <synopsis><function>signal-external-process</function>
-	    proc signal-number</synopsis>
-	  </refsynopsisdiv>
-
-	  <refsect1>
-	    <title>Arguments and Values</title>
-
-	    <variablelist>
-	      <varlistentry>
-		<term>proc</term>
-
-		<listitem>
-		  <para>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>signal</term>
-
-		<listitem>
-		  <para>A small integer.</para>
-		</listitem>
-	      </varlistentry>
-	    </variablelist>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <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>
-	  </refsect1>
-	</refentry>
-
-	<refentry id=3D"f_external-process-id">
-	  <indexterm zone=3D"f_external-process-id">
-	    <primary>external-process-id</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>EXTERNAL-PROCESS-ID</refname>
-	    <refpurpose>Returns the "process ID" of an OS subprocess,
-	    a positive integer which identifies it.</refpurpose>
-	    <refclass>Function</refclass>
-	  </refnamediv>
-
-	  <refsynopsisdiv>
-	    <synopsis><function>external-process-id</function>
-	    proc</synopsis>
-	  </refsynopsisdiv>
-
-	  <refsect1>
-	    <title>Arguments and Values</title>
-
-	    <variablelist>
-	      <varlistentry>
-		<term>proc</term>
-
-		<listitem>
-		  <para>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.</para>
-		</listitem>
-	      </varlistentry>
-	    </variablelist>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <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>
-	  </refsect1>
-	</refentry>
-
-	<refentry id=3D"f_external-process-input-stream">
-	  <indexterm zone=3D"f_external-process-input-stream">
-	    <primary>external-process-input-stream</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>EXTERNAL-PROCESS-INPUT-STREAM</refname>
-	    <refpurpose>Returns the lisp stream which is used to write
-	    input to a given OS subprocess, if it has one.</refpurpose>
-	    <refclass>Function</refclass>
-	  </refnamediv>
-
-	  <refsynopsisdiv>
-	    <synopsis><function>external-process-input-stream</function>
-	    proc</synopsis>
-	  </refsynopsisdiv>
-
-	  <refsect1>
-	    <title>Arguments and Values</title>
-
-	    <variablelist>
-	      <varlistentry>
-		<term>proc</term>
-
-		<listitem>
-		  <para>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.</para>
-		</listitem>
-	      </varlistentry>
-	    </variablelist>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <para>Returns the stream created when the input argument to
-	    run-program is specified as :STREAM.</para>
-	  </refsect1>
-	</refentry>
-
-	<refentry id=3D"f_external-process-output-stream">
-	  <indexterm zone=3D"f_external-process-output-stream">
-	    <primary>external-process-output-stream</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>EXTERNAL-PROCESS-OUTPUT-STREAM</refname>
-	    <refpurpose>Returns the lisp stream which is used to read
-	    output from an OS subprocess, if there is one.</refpurpose>
-	    <refclass>Function</refclass>
-	  </refnamediv>
-
-	  <refsynopsisdiv>
-	    <synopsis><function>external-process-output-stream</function>
-	    proc</synopsis>
-	  </refsynopsisdiv>
-
-	  <refsect1>
-	    <title>Arguments and Values</title>
-
-	    <variablelist>
-	      <varlistentry>
-		<term>proc</term>
-
-		<listitem>
-		  <para>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.</para>
-		</listitem>
-	      </varlistentry>
-	    </variablelist>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <para>Returns the stream created when the output argument to
-	    run-program is specified as :STREAM.</para>
-	  </refsect1>
-	</refentry>
-
-	<refentry id=3D"f_external-process-error-stream">
-	  <indexterm zone=3D"f_external-process-error-stream">
-	    <primary>external-process-error-stream</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>EXTERNAL-PROCESS-ERROR-STREAM</refname>
-	    <refpurpose>Returns the stream which is used to read
-	    "error" output from a given OS subprocess, if it has
-	    one.</refpurpose>
-	    <refclass>Function</refclass>
-	  </refnamediv>
-
-	  <refsynopsisdiv>
-	    <synopsis><function>external-process-error-stream</function>
-	    proc</synopsis>
-	  </refsynopsisdiv>
-
-	  <refsect1>
-	    <title>Arguments and Values</title>
-
-	    <variablelist>
-	      <varlistentry>
-		<term>proc</term>
-
-		<listitem>
-		  <para>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.</para>
-		</listitem>
-	      </varlistentry>
-	    </variablelist>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <para>Returns the stream created when the error argument to
-	    run-program is specified as :STREAM.</para>
-	  </refsect1>
-	</refentry>
-
-	<refentry id=3D"f_external-process-status">
-	  <indexterm zone=3D"f_external-process-status">
-	    <primary>external-process-status</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>EXTERNAL-PROCESS-STATUS</refname>
-	    <refpurpose>Returns information about whether an OS
-	    subprocess is running; or, if not, why not; and what its
-	    result code was if it completed.</refpurpose>
-	    <refclass>Function</refclass>
-	  </refnamediv>
-
-	  <refsynopsisdiv>
-	    <synopsis><function>external-process-status</function>
-	    proc</synopsis>
-	  </refsynopsisdiv>
-
-	  <refsect1>
-	    <title>Arguments and Values</title>
-
-	    <variablelist>
-	      <varlistentry>
-		<term>proc</term>
-
-		<listitem>
-		  <para>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.</para>
-		</listitem>
-	      </varlistentry>
-	    </variablelist>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <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>
-	  </refsect1>
-	</refentry>
-    </sect1>
-  </chapter>
-
-  <chapter id=3D"Creating-Your-Own-Stream-Classes-with-Gray-Streams">
-    <title>Creating Your Own Stream Classes with Gray Streams</title>
-
-    <sect1 id=3D"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>
- =

-      <simplelist>
-	<member>fundamental-stream</member>
-	<member>fundamental-input-stream</member>
-	<member>fundamental-output-stream</member>
-	<member>fundamental-character-stream</member>
-	<member>fundamental-binary-stream</member>
-	<member>fundamental-character-input-stream</member>
-	<member>fundamental-character-output-stream</member>
-	<member>fundamental-binary-input-stream</member>
-	<member>fundamental-binary-output-stream</member>
-	<member>ccl::buffered-stream-mixin</member>
-	<member>ccl::buffered-input-stream-mixin</member>
-	<member>ccl::buffered-output-stream-mixin</member>
-	<member>ccl::buffered-io-stream-mixin</member>
-	<member>ccl::buffered-character-input-stream-mixin</member>
-	<member>ccl::buffered-character-output-stream-mixin</member>
-	<member>ccl::buffered-character-io-stream-mixin</member>
-	<member>ccl::buffered-binary-input-stream-mixin</member>
-	<member>ccl::buffered-binary-output-stream-mixin</member>
-	<member>ccl::buffered-binary-io-stream-mixin</member>
-	<member>file-stream</member>
-	<member>file-input-stream</member>
-	<member>file-output-stream</member>
-	<member>file-io-stream</member>
-	<member>file-character-input-stream</member>
-	<member>file-character-output-stream</member>
-	<member>file-charcter-io-stream</member>
-	<member>file-binary-input-stream</member>
-	<member>file-binary-output-stream</member>
-	<member>file-binary-io-stream</member>
-	<member>ccl::fd-stream</member>
-	<member>ccl::fd-input-stream</member>
-	<member>ccl::fd-output-stream</member>
-	<member>ccl::fd-io-stream</member>
-	<member>ccl::fd-character-input-stream</member>
-	<member>ccl::fd-character-output-stream</member>
-	<member>ccl::fd-character-io-stream</member>
-	<member>ccl::fd-binary-input-stream</member>
-	<member>ccl::fd-binary-output-stream</member>
-	<member>ccl::fd-binary-io-stream</member>
-      </simplelist>
-
-      <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>
-      <simplelist>
-	<member>stream-direction stream =3D></member>
-	<member>stream-device stream direction =3D></member>
-	<member>stream-length stream &optional; new =3D></member>
-	<member>stream-position stream &optional; new =3D></member>
-	<member>streamp stream =3D> boolean</member>
-	<member>stream-write-char output-stream char =3D></member>
-	<member>stream-write-entire-string output-stream string =3D></member>
-	<member>stream-read-char input-stream =3D></member>
-	<member>stream-unread-char input-stream char =3D></member>
-	<member>stream-force-output output-stream =3D> nil</member>
-	<member>stream-maybe-force-output output-stream =3D> nil</member>
-	<member>stream-finish-output output-stream =3D> nil</member>
-	<member>stream-clear-output output-stream =3D> nil</member>
-	<member>close stream &key; abort =3D> boolean</member>
-	<member>stream-fresh-line stream =3D> t</member>
-	<member>stream-line-length stream =3D> length</member>
-	<member>interactive-stream-p stream =3D> boolean</member>
-	<member>stream-clear-input input-stream =3D> nil</member>
-	<member>stream-listen input-stream =3D> boolean</member>
-	<member>stream-filename stream =3D> string</member>
-	<member>ccl::select-stream-class instance in-p out-p char-p =3D>
-	        class</member>
-      </simplelist>
-      <para>The following functions are standard parts of Common Lisp, but
-behave in special ways with regard to Gray streams.</para>
-      <simplelist>
-	<member>open-stream-p stream =3D> generalized-boolean</member>
-	<member>input-stream-p stream =3D> generalized-boolean</member>
-	<member>output-stream-p stream =3D> generalized-boolean</member>
-	<member>stream-element-type stream =3D></member>
-	<member>stream-error-stream =3D></member>
-	<member>open</member>
-	<member>close</member>
-	<member>with-open-file</member>
-      </simplelist>
-
-      <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>
-       <simplelist>
-	<member>stream-external-format</member>
-      </simplelist>
-    </sect1>
-
-    <sect1 id=3D"Extending-READ-SEQUENCE-and-WRITE-SEQUENCE">
-      <title>Extending READ-SEQUENCE and WRITE-SEQUENCE</title>
-
-      <sect2 id=3D"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=3D"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=3D"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 star=
t end)
-  (if (not (typep vector 'simple-base-string))
-      (call-next-method)
-      (with-slots (string index length)
-        (do* ((outpos start (1+ outpos)))
-             ((or (=3D outpos end)
-                  (=3D index length))
-              outpos))
-          (setf (schar vector outpos)
-                (schar string index))
-          (incf index)))))
-</programlisting>
-      </sect2>
-    </sect1>
-
-    <sect1 id=3D"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=3D"Gray-Streams-Dictionary">
-      <title>Gray Streams Dictionary</title>
-      <refentry id=3D"f_stream-read-list">
-	<indexterm zone=3D"f_stream-read-list">
-	  <primary>stream-read-list</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL:STREAM-READ-LIST</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Generic Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>stream-read-list</function>
-	  stream list count</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>stream</term>
-
-	      <listitem>
-		<para>a stream, presumably a fundamental-input-stream.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>list</term>
-
-	      <listitem>
-		<para>a list. When a STREAM-READ-LIST method is called by
-		READ-SEQUENCE, this argument is guaranteed to be a proper
-		list.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>count</term>
-
-	      <listitem>
-		<para>a non-negative integer. When a STREAM-READ-LIST method
-		is called by READ-SEQUENCE, this argument is guaranteed not
-		to be greater than the length of the list.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_stream-write-list">
-	<indexterm zone=3D"f_stream-write-list">
-	  <primary>stream-write-list</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL:STREAM-WRITE-LIST</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Generic Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>stream-write-list</function>
-	  stream list count</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>stream</term>
-
-	      <listitem>
-		<para>a stream, presumably a fundamental-ouput-stream.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>list</term>
-
-	      <listitem>
-		<para>a list. When a STREAM-WRITE-LIST method is called by
-		WRITE-SEQUENCE, this argument is guaranteed to be a proper
-		list.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>count</term>
-
-	      <listitem>
-		<para>a non-negative integer. When a STREAM-WRITE-LIST
-		method is called by WRITE-SEQUENCE, this argument is
-		guaranteed not to be greater than the length of the list.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>should try to write the first count elements of list to
-	  stream. The return value of this method is ignored.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_stream-read-vector">
-	<indexterm zone=3D"f_stream-read-vector">
-	  <primary>stream-read-vector</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL:STREAM-READ-VECTOR</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Generic Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>stream-read-vector</function>
-	  stream vector start end</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>stream</term>
-
-	      <listitem>
-		<para>a stream, presumably a fundamental-input-stream</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>vector</term>
-
-	      <listitem>
-		<para>a vector. When a STREAM-READ-VECTOR method is called
-		by READ-SEQUENCE, this argument is guaranteed to be a simple
-		one-dimensional array.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>start</term>
-
-	      <listitem>
-		<para>a non-negative integer. When a STREAM-READ-VECTOR
-		method is called by READ-SEQUENCE, this argument is
-		guaranteed to be no greater than end and not greater than
-		the length of vector.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>end</term>
-
-	      <listitem>
-		<para>a non-negative integer. When a STREAM-READ-VECTOR
-		method is called by READ-SEQUENCE, this argument is
-		guaranteed to be no less than end and not greater than the
-		length of vector.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_stream-write-vector">
-	<indexterm zone=3D"f_stream-write-vector">
-	  <primary>stream-write-vector</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL:STREAM-WRITE-VECTOR</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Generic Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>stream-write-vector</function>
-	  stream vector start end</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>stream</term>
-
-	      <listitem>
-		<para>a stream, presumably a fundamental-output-stream</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>vector</term>
-
-	      <listitem>
-		<para>a vector. When a STREAM-WRITE-VECTOR method is called
-		by WRITE-SEQUENCE, this argument is guaranteed to be a
-		simple one-dimensional array.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>start</term>
-
-	      <listitem>
-		<para>a non-negative integer. When a STREAM-WRITE-VECTOR
-		method is called by WRITE-SEQUENCE, this argument is
-		guaranteed to be no greater than end and not greater than
-		the length of vector.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>end</term>
-
-	      <listitem>
-		<para>a non-negative integer. When a STREAM-WRITE-VECTOR
-		method is called by WRITE-SEQUENCE, this argument is
-		guaranteed to be no less than end and not greater than the
-		length of vector.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>should try to write successive elements of vector to stream,
-	  starting at element start (inclusive) and continuing through
-	  element end (exclusive.)</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_stream-device">
-	<indexterm zone=3D"f_stream-device">
-	  <primary>stream-device</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL::STREAM-DEVICE</refname>
-	  <refpurpose>Returns the OS file descriptor associated with a
-	  given lisp stream.</refpurpose>
-	  <refclass>Generic Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>ccl::stream-device</function>
-	  s direction</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Method Signatures</title>
-
-	  <synopsis><function>ccl::stream-device</function>
-	  (s stream) direction =3D> fd</synopsis>
-	</refsect1>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-	  =

-	  <variablelist>
-	    <varlistentry>
-	      <term>s</term>
-	      <listitem>
-		<para>a stream.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>direction</term>
-	      <listitem>
-		<para>either :INPUT or :OUTPUT.</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>fd</term>
-	      <listitem>
-		<para>a file descriptor, which is a non-negative integer
-		used by the OS to refer to an open file, socket, or similar
-		I/O connection.  NIL if there is no file descriptor associated
-		with <varname>s</varname> in the direction given by
-		<varname>direction</varname>.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns the file descriptor associated with
-	  <varname>s</varname> in the direction given by
-	  <varname>direction</varname>.  It is necessary to specify
-	  <varname>direction</varname> 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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_stream-read-ivector">
-	<indexterm zone=3D"f_stream-read-ivector">
-	  <primary>stream-read-ivector</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>STREAM-READ-IVECTOR</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Generic Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>stream-read-ivector</function>
-	  stream ivector start-octet max-octets</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Reads up to max-octets octets from stream into ivector,
-	  storing them at start-octet. Returns the number of octets actually
-	  read.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>Arguments</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>stream</term>
-
-	      <listitem>
-		<para>An input stream. The method defined on
-		BUFFERED-INPUT-STREAMs requires that the size in octets of
-		an instance of the stream's element type is 1.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>ivector</term>
-
-	      <listitem>
-		<para>Any ivector.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>start-octet</term>
-
-	      <listitem>
-		<para>A non-negative integer.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>max-octets</term>
-
-	      <listitem>
-		<para>A non-negative integer. The return value may be less
-		than the value of this parameter if EOF was encountered.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_stream-write-ivector">
-	<indexterm zone=3D"f_stream-write-ivector">
-	  <primary>stream-write-ivector</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>STREAM-WRITE-IVECTOR</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Generic Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>stream-write-ivector stream</function>
-	  ivector start-octet max-octets</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Writes max-octets octets to stream from ivector, starting at
-	  start-octet. Returns max-octets.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>Arguments</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>stream</term>
-
-	      <listitem>
-		<para>An input stream. The method defined on
-		BUFFERED-OUTPUT-STREAMs requires that the size in octets of
-		an instance of the stream's element type is 1.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>ivector</term>
-
-	      <listitem>
-		<para>Any ivector</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>start-octet</term>
-
-	      <listitem>
-		<para>A non-negative integer.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>max-octet</term>
-
-	      <listitem>
-		<para>A non-negative integer.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Examples</title>
-
-<programlisting format=3D"linespecific">;;; Write the contents of a (SIMPL=
E-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).
-;;; (Note that (=3D (- arch::misc-dfloat-offset =

-;;;                  arch::misc-data-offset) 4))
-(defun write-double-float-vector
-  (stream vector &#38;key (start 0) (end (length vector)))
-  (check-type vector (vector double-float))
-  (let* ((start-octet (+ (* start 8) =

-                         (- arch::misc-dfloat-offset
-                         arch::misc-data-offset)))
-         (num-octets (* 8 (- end start))))
-    (stream-write-ivector stream vector start-octet num-octets)))</program=
listing>
-	</refsect1>
-      </refentry>
-    </sect1>
-  </chapter>
-
-  <chapter id=3D"Writing-Portable-Extensions-to-the-Object-System-using-th=
e-MetaObject-Protocol">
-    <title>Writing Portable Extensions to the Object System  using the Met=
aObject Protocol</title>
-
-    <sect1 id=3D"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=3D"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=3D"2" colsep=3D"1"
-      rowsep=3D"1"><colspec align=3D"center" colname=3D"col0" /><colspec
-      align=3D"center" colname=3D"col1" /><thead><row><entry
-      align=3D"center" valign=3D"top"><para>construct</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>status</para></entry></row></thead><tbody><row>=
<entry
-      align=3D"center"
-      valign=3D"top"><para>accessor-method-slot-definition</para></entry><=
entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>add-dependent</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>add-direct-method</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>add-direct-subclass</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>add-method</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>class-default-initargs</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>class-direct-default-initargs</para></entry><en=
try
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>class-direct-slots</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>class-direct-subclasses</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>class-direct-superclasses</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>class-finalized-p</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>class-prototype</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>class-slots</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>compute-applicable-methods</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>-</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>compute-applicable-methods-using-classes</para>=
</entry><entry
-      align=3D"center"
-      valign=3D"top"><para>-</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>compute-class-precedence-list</para></entry><en=
try
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>compute-direct-initargs</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>compute-discriminating-function</para></entry><=
entry
-      align=3D"center"
-      valign=3D"top"><para>-</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>compute-effective-method</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>compute-effective-slot-definition</para></entry=
><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>compute-slots</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>direct-slot-definition-class</para></entry><ent=
ry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>effective-slot-definition-class</para></entry><=
entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>ensure-class</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>ensure-class-using-class</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>ensure-generic-function-using-class</para></ent=
ry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>eql-specializer-object</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>extract-lambda-list</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>extract-specializer-names</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>finalize-inheritance</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>find-method-combination</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>funcallable-standard-instance-access</para></en=
try><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>generic-function-argument-precedence-order</par=
a></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>generic-function-declarations</para></entry><en=
try
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>generic-function-lambda-list</para></entry><ent=
ry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>generic-function-method-class</para></entry><en=
try
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>generic-function-method-combination</para></ent=
ry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>generic-function-methods</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>generic-function-name</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>intern-eql-specializer</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>make-method-lambda</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>-</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>map-dependents</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>method-function</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>method-generic-function</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>method-lambda-list</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>method-qualifiers</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>method-specializers</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>reader-method-class</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>remove-dependent</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>remove-direct-method</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>remove-direct-subclass</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>remove-method</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>set-funcallable-instance-function</para></entry=
><entry
-      align=3D"center"
-      valign=3D"top"><para>-</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>slot-boundp-using-class</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>slot-definition-allocation</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>slot-definition-initargs</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>slot-definition-initform</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>slot-definition-initfunction</para></entry><ent=
ry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>slot-definition-location</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>slot-definition-name</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>slot-definition-readers</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>slot-definition-type</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>slot-definition-writers</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>slot-makunbound-using-class</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>slot-value-using-class</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>specializer-direct-generic-functions</para></en=
try><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>specializer-direct-methods</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>standard-instance-access</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>update-dependent</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>validate-superclass</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row><row><entry
-      align=3D"center"
-      valign=3D"top"><para>writer-method-class</para></entry><entry
-      align=3D"center"
-      valign=3D"top"><para>+</para></entry></row></tbody></tgroup></inform=
altable></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=3D"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=3D"The-Foreign-Function-Interface">
-    <title>The Foreign-Function Interface</title>
-
-    <sect1 id=3D"Specifying-And-Using-Foreign-Types">
-      <title>Specifying And Using Foreign Types</title>
-
-      <sect2 id=3D"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=3D"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> , at fieldlist) is adefinition of
-	    the structure type <emphasis>name</emphasis>,
-	    and (:UNION<emphasis> name</emphasis> , at 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=3D"Foreign-Function-Calls">
-      <title>Foreign Function Calls</title>
-
-      <sect2 id=3D"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=3D"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=3D"Referencing-and-Using-Foreign-Memory-Addresses">a MA=
CPTR</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=3D"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=3D"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=3D"Referencing-and-Using-Foreign-Memory-Addresses">
-      <title>Referencing and Using Foreign Memory Addresses</title>
-
-      <sect2 id=3D"Overview-memory-addresses">
-        <title>Overview</title>
-
-        <sect3 id=3D"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=3D"Stack-allocation-of---and-destructive-operations-on--=
-MACPTRs-">
-          <title>Stack allocation of - and destructive operations on - MAC=
PTRs.</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-PT=
R 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=3D"Stack-allocated-memory--and-stack-allocated-pointers-=
to-it--">
-          <title>Stack-allocated memory (and stack-allocated pointers to i=
t.)</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=3D"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=3D"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=3D"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=3D"iget-bit--Function-">
-	  <title>%get-bit [Function]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>%get-bit ptr bit-offset</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>References and returns the bit-offsetth bit at the address
-		encapsulated by ptr. (Bit 0 at a given address is the most
-		significant bit of the byte at that address.) Can be used with
-		SETF.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para>&#x00A0;</para>
-
-		<variablelist>
-		  <varlistentry>
-		    <term>ptr</term>
-
-		    <listitem>
-		      <para>A MACPTR</para>
-		    </listitem>
-		  </varlistentry>
-
-		  <varlistentry>
-		    <term>bit-offset</term>
-
-		    <listitem>
-		      <para>A fixnum</para>
-		    </listitem>
-		  </varlistentry>
-		</variablelist>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-        </sect3>
-
-        <sect3 id=3D"iget-bitfield--Function-">
-          <title>%get-bitfield [Function]</title>
- 	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>%get-bitfield ptr bit-offset width</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>References and returns an unsigned integer composed from the
-		width bits found bit-offsetbits from the address encapsulated by
-		ptr. (The least significant bit of the result is the value of
-		(%get-bit ptr (1- (+ bit-offset width))). Can be used with SETF.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para>&#x00A0;</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>ptr</term>
-
-	      <listitem>
-		<para>A MACPTR</para>
-
-		<variablelist>
-		  <varlistentry>
-		    <term>bit-offset</term>
-
-		    <listitem>
-		      <para>A fixnum</para>
-		    </listitem>
-		  </varlistentry>
-
-		  <varlistentry>
-		    <term>width</term>
-
-		    <listitem>
-		      <para>A positive fixnum</para>
-		    </listitem>
-		  </varlistentry>
-		</variablelist>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-        </sect3>
-
-	<sect3>
-	  <title>%int-to-ptr [Function]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>%int-to-ptr int</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>Creates and returns a MACPTR whose address matches int.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para>&#x00A0;</para>
-
-		<variablelist>
-		  <varlistentry>
-		    <term>int</term>
-
-		    <listitem>
-		      <para>An (unsigned-byte 32)</para>
-		    </listitem>
-		  </varlistentry>
-		</variablelist>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</sect3>
-
-	<sect3>
-	  <title>%inc-ptr [Function]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>%inc-ptr ptr &#38;optional (delta 1)</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>Creates and returns a MACPTR whose address is the address of
-		ptr plus delta. The idiom (%inc-ptr ptr 0) is sometimes used to
-		copy a MACPTR, e.g., to create a new MACPTR encapsulating the same
-		address as ptr.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para>&#x00A0;</para>
-
-		<variablelist>
-		  <varlistentry>
-		    <term>ptr</term>
-
-		    <listitem>
-		      <para>A MACPTR</para>
-		    </listitem>
-		  </varlistentry>
-
-		  <varlistentry>
-		    <term>delta</term>
-
-		    <listitem>
-		      <para>A fixnum</para>
-		    </listitem>
-		  </varlistentry>
-		</variablelist>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</sect3>
-
-	<sect3>
-	  <title>%ptr-to-int [Function]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>%ptr-to-int ptr</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>Returns the address encapsulated by ptr, as an
-		(unsigned-byte 32).</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para>&#x00A0;</para>
-
-		<variablelist>
-		  <varlistentry>
-		    <term>ptr</term>
-
-		    <listitem>
-		      <para>A MACPTR</para>
-		    </listitem>
-		  </varlistentry>
-		</variablelist>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</sect3>
-
-	<sect3>
-	  <title>%null-ptr [Macro]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>%null-ptr</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>Equivalent to (%ptr-to-int 0).</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</sect3>
-
-	<sect3>
-	  <title>%null-ptr-p [Function]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>%null-ptr-p ptr</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>Returns T If ptr is a MACPTR encapsulating the address 0,
-		NIL if ptr encapsulates some other address.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para>&#x00A0;</para>
-
-		<variablelist>
-		  <varlistentry>
-		    <term>ptr</term>
-
-		    <listitem>
-		      <para>A MACPTR</para>
-		    </listitem>
-		  </varlistentry>
-		</variablelist>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</sect3>
-
-	<sect3>
-	  <title>%setf-macptr [Function]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>%setf-macptr dest-ptr src-ptr</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>Causes dest-ptr to encapsulate the same address that src-ptr
-		does, then returns dest-ptr.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para>&#x00A0;</para>
-
-		<variablelist>
-		  <varlistentry>
-		    <term>dest-ptr</term>
-
-		    <listitem>
-		      <para>A MACPTR</para>
-		    </listitem>
-		  </varlistentry>
-
-		  <varlistentry>
-		    <term>src-ptr</term>
-
-		    <listitem>
-		      <para>A MACPTR</para>
-		    </listitem>
-		  </varlistentry>
-		</variablelist>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</sect3>
-
-	<sect3>
-	  <title>%incf-ptr [Macro]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>%incf-ptr ptr &#38;optional (delta 1)</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>Destructively modifies ptr, by adding delta to the address
-		it encapsulates. Returns ptr.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para>&#x00A0;</para>
-
-		<variablelist>
-		  <varlistentry>
-		    <term>ptr</term>
-
-		    <listitem>
-		      <para>A MACPTR</para>
-		    </listitem>
-		  </varlistentry>
-
-		  <varlistentry>
-		    <term>delta</term>
-
-		    <listitem>
-		      <para>A fixnum</para>
-		    </listitem>
-		  </varlistentry>
-		</variablelist>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</sect3>
-
-	<sect3>
-	  <title>with-macptrs [Macro]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>with-macptrs (var expr)* &#38;body body</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>Executes body in an environment in which each var is bound
-		to a stack-allocated macptr which encapsulates the foreign address
-		yielded by the corresponding expr. Returns whatever value(s) body
-		returns.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para>&#x00A0;</para>
-
-		<variablelist>
-		  <varlistentry>
-		    <term>var</term>
-
-		    <listitem>
-		      <para>A symbol (variable name)</para>
-		    </listitem>
-		  </varlistentry>
-
-		  <varlistentry>
-		    <term>expr</term>
-
-		    <listitem>
-		      <para>A MACPTR-valued expression</para>
-		    </listitem>
-		  </varlistentry>
-		</variablelist>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</sect3>
-
-	<sect3>
-	  <title>%stack-block [Macro]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>%stack-block (var expr)* &#38;body body</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>Executes body in an environment in which each var is bound
-		to a stack-allocated macptr which encapsulates the address of a
-		stack-allocated region of size expr bytes. Returns whatever
-		value(s) body returns.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para>&#x00A0;</para>
-
-		<variablelist>
-		  <varlistentry>
-		    <term>var</term>
-
-		    <listitem>
-		      <para>A symbol (variable name)</para>
-		    </listitem>
-		  </varlistentry>
-
-		  <varlistentry>
-		    <term>expr</term>
-
-		    <listitem>
-		      <para>An expression which should evaluate to a non-negative
-		      fixnum</para>
-		    </listitem>
-		  </varlistentry>
-		</variablelist>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</sect3>
-
-	  <sect3>
-	    <title>make-cstring [Function]</title>
-
-	    <variablelist>
-	      <varlistentry>
-		<term>Syntax</term>
-
-		<listitem>
-		  <para>make-cstring string</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>Description</term>
-
-		<listitem>
-		  <para>Allocates a block of memory (via malloc) of length (1+
-		  (length string)). Copies the string to this block and appends a
-		  trailing NUL byte; returns a MACPTR to the block.</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>Arguments</term>
-
-		<listitem>
-		  <para>&#x00A0;</para>
-
-		  <variablelist>
-		    <varlistentry>
-		      <term>string</term>
-
-		      <listitem>
-			<para>A lisp string</para>
-		      </listitem>
-		    </varlistentry>
-		  </variablelist>
-		</listitem>
-	      </varlistentry>
-	    </variablelist>
-	  </sect3>
-
-	<sect3>
-	  <title>with-cstrs [Macro]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>with-cstrs (var string)* &#38;body body</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>Executes body in an environment in which each var is bound
-		to a stack-allocated macptr which encapsulates the %address of a
-		stack-allocated region of into which each string (and a trailing
-		NUL byte) has been copied. Returns whatever value(s) body returns.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para>&#x00A0;</para>
-
-		<variablelist>
-		  <varlistentry>
-		    <term>var</term>
-
-		    <listitem>
-		      <para>A symbol (variable name)</para>
-		    </listitem>
-		  </varlistentry>
-
-		  <varlistentry>
-		    <term>string</term>
-
-		    <listitem>
-		      <para>An expression which should evaluate to a lisp string</para>
-		    </listitem>
-		  </varlistentry>
-		</variablelist>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</sect3>
-
-	<sect3>
-	  <title>%get-cstring [Function]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>%get-cstring ptr</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>Interprets ptr as a pointer to a (NUL -terminated) C string;
-		returns an equivalent lisp string.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para></para>
-
-		<variablelist>
-		  <varlistentry>
-		    <term>ptr</term>
-
-		    <listitem>
-		      <para>A MACPTR</para>
-		    </listitem>
-		  </varlistentry>
-		</variablelist>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</sect3>
-
-	<sect3>
-	  <title>%str-from-ptr [Function]</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>Syntax</term>
-
-	      <listitem>
-		<para>%str-from-ptr ptr length</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Description</term>
-
-	      <listitem>
-		<para>Returns a lisp string of length <varname>length</varname>,
-		whose contents are initialized from the bytes at<varname> ptr.</varname>
-		</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>Arguments</term>
-
-	      <listitem>
-		<para><variablelist><varlistentry><term>ptr</term><listitem><para>A
-		MACPTR</para></listitem></varlistentry><varlistentry><term>length</term>=
<listitem><para>a
-		non-negative fixnum</para></listitem></varlistentry></variablelist></par=
a>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</sect3>
-      </sect2>
-    </sect1>
-
-    <sect1 id=3D"The-Interface-Database">
-      <title>The Interface Database</title>
-
-      <sect2 id=3D"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>
-	<itemizedlist>
-          <listitem>
-	    <para>#$foo looks up the value of the constant definition of foo</par=
a>
-	  </listitem>
-	  <listitem>
-	    <para>#_foo looks up the foreign function definition for foo</para>
-	  </listitem>
-        =

-        </itemizedlist>
-        <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=3D"Building-the-heap-image"/>).</para>
-      </sect2>
-
-      <sect2 id=3D"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=3D"The-Interface-Translator"/>.</para>
-      </sect2>
-    </sect1>
-
-    <sect1 id=3D"Using-Interface-Directories">
-      <title>Using Interface Directories</title>
-
-      <sect2 id=3D"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=3D"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>
-	<orderedlist continuation=3D"restarts" inheritnum=3D"ignore">
-	  <listitem>
-	    <para>Create a subdirectory of &#34;ccl:headers;&#34; named
-	    &#34;foo&#34;.</para>
-	  </listitem>
-
-	  <listitem>
-	    <para>Create a subdirectory of &#34;ccl:headers;foo;&#34; named
-	    &#34;C&#34;.</para>
-	  </listitem>
-
-	  <listitem>
-	    <para>Create a file in &#34;ccl:headers;foo;C;&#34; named
-	    &#34;populate.sh&#34;.</para>
-
-	    <para>One way of accomplishing the above steps is:</para>
-
-	    <programlisting format=3D"linespecific">? (close (open &#34;ccl:heade=
rs;foo;C;populate.sh&#34; :direction :output :
-               if-does-not-exist :create :if-exists :overwrite))</programl=
isting>
-	  </listitem>
-
-	  <listitem>
-	    <para>Edit the file created above, using the &#34;populate.sh&#34;
-	    files in the distribution as guidelines.</para>
-
-	    <para>The file might wind up looking something like:</para>
-
-	    <programlisting format=3D"linespecific">#/bin/sh
-h-to-ffi.sh `foo-config -cflags` /usr/include/foo/foo.h</programlisting>
-	  </listitem>
-	</orderedlist>
-
-        <para>Refer to <xref linkend=3D"The-Interface-Translator"/> 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
-        <programlisting>
-? (use-interface-dir :foo)
-	</programlisting> =

-	whenever you need to
-        access the foreign type information in those database
-        files.</para>
-      </sect2>
-    </sect1>
-
-    <sect1 id=3D"Using-Shared-Libraries">
-      <title>Using Shared Libraries</title>
-
-      <sect2 id=3D"Shared-Library-Overview">
-	<title>Overview</title>
-
-        <para>OpenMCL provides facilities to open and close shared
-        libraries.</para>
-        <para>"Opening" a shared library, which is done with <xref
-        linkend=3D"f_open-shared-library"/>, 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 <xref
-        linkend=3D"f_close-shared-library"/>, unmaps the library's code
-        and 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=3D"Limitations-and-known-bugs--1-">
-        <title>Limitations and known bugs</title>
-	<itemizedlist>
-          <listitem>
-	    <para>Don't get me started.</para>
-	  </listitem>
-          <listitem>
-	    <para>The underlying functionality has a poor notion of
-	    dependency;it's not always possible to open libraries that
-	    depend on unopened libraries, but it's possible to close
-	    libraries on which other libraries depend. It
-	    <emphasis>may</emphasis> be possible to generate
-	    more explicit dependency information by parsing the output
-	    of the Linux ldd and ldconfig programs.</para>
-	  </listitem>
-        =

-	</itemizedlist>
-      </sect2>
-
-      <sect2 id=3D"Darwin-Notes">
-        <title>>Darwin Notes</title>
-	<para>Darwin shared libraries come in two (basic) flavors:</para>
-	<itemizedlist>
-          <listitem>
-	    <para>"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.</para>
-	  </listitem>
-          <listitem>
-	    <para>"bundles" are intended to serve as application
-	    extensions; they can be opened multiple times (creating
-	    multiple instances of the library!) and closed
-	    properly.</para>
-          </listitem>
-	</itemizedlist>
-        <para>Thanks to Michael Klingbeil for getting both kinds of
-        Darwin shared libraries working in OpenMCL.</para>
-      </sect2>
-    </sect1>
-
-    <sect1 id=3D"The-Interface-Translator">
-      <title>The Interface Translator</title>
-
-      <sect2 id=3D"Inteface-translator-overview">
-	<title>Overview</title>
-	<para>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 FIXTHIS)
-        <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</empha=
sis>;<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=3D"Details--rebuilding-the-CDB-databases--step-by-step">
-        <title>Details: rebuilding the CDB databases, step by step</title>
-	<orderedlist>
-	  <listitem>
-	    <para>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;".</para>
-	  </listitem>
-          <listitem>
-	    <para>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.</para>
-	  </listitem>
-	  <listitem>
-	    <para>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></para>
-	  </listitem>
-	</orderedlist>
-      </sect2>
-    </sect1>
-
-    <sect1 id=3D"Case-sensitivity-of-foreign-names-in-OpenMCL">
-      <title>Case-sensitivity of foreign names in OpenMCL</title>
-
-      <sect2 id=3D"Case-sensitivity-overview">
-	<title>Overview</title>
-	<para>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=3D"Foreign-constant-and-function-names">
-	<title>Foreign constant and function names</title>
-        <para>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=3D"Foreign-type--record--and-field-names">
-	<title>Foreign type, record, and field names</title>
-	<para>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 (<literal>&lt;</literal> and
-        <literal>&gt;</literal>). Such symbols are translated to
-	foreign names via the following set of conventions:</para>
-	<itemizedlist>
-          <listitem>
-	    <para>All instances of &lt; and &gt; in the symbol's pname
-	    are balanced and don't nest.</para>
-	  </listitem>
-          <listitem>
-	    <para>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 case in which they were written.</para>
-	  </listitem>
-          <listitem>
-	    <para>Alphabetic characters that appear within angle
-	    brackets aremapped to upper-case, again regardless of how
-	    they were written orinterned.</para>
-	  </listitem>
-        </itemizedlist>
-	<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=3D"Examples--1-">
-        <title>Examples</title>
-        <programlisting>
-;;; Allocate a record of type "window".
-(rlet ((w :window)) ...)
-;;; Allocate a record of type "Window", which is probably a
-;;;  different type
-(rlet ((w :&lt;w&gt;indow)) ...)
-;;; This is equivalent to the last example
-(rlet ((w :&lt;w&gt;INDOW)))
-</programlisting>
-      </sect2>
-    </sect1>
-
-    <sect1 id=3D"Tutorial--Using-Basic-Calls-and-Types">
-      <title>Tutorial: Using Basic Calls and Types</title>
-      <para>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 &lt;stdio.&gt;
-
-void
-void_void_test(void)
-{
-    printf("Entered %s:\n", __FUNCTION__);
-    printf("Exited  %s:\n", __FUNCTION__);
-    fflush(stdout);
-}
-
-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__);
-    fflush(stdout);
-    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__);
-    fflush(stdout);
-    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>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>
-      <tip><para>Users of 64-bit platforms may need to pass options such
-      as "-m64" to gcc, may need to give the output library a different
-      extension (such as ".so"), and may need to user slightly different
-      values for other options in order to create an equivalent test
-      library.</para></tip>
-
-      <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")
-#&lt;SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E&gt;
-</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*
-(#&lt;SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
- #&lt;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 <xref
-      linkend=3D"m_external-call"/>:</para>
-      <programlisting>
-
-? (external "_void_void_test")
-#&lt;EXTERNAL-ENTRY-POINT "_void_void_test" (#x000CFDF8) /Users/andewl/ope=
nmcl/libtypetest.dylib #x638EDF6>
-
-? (external "_sc_sc_test")
-#&lt;EXTERNAL-ENTRY-POINT "_sc_sc_test" (#x000CFE50) /Users/andewl/openmcl=
/libtypetest.dylib #x638EB3E>
-
-? (external "_uc_uc_test")
-#&lt;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")
-#&lt;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>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__);
-    fflush(stdout);
-    return data;
-}
-
-long
-sl_sl_test(long data)
-{
-    printf("Entered %s:\n", __FUNCTION__);
-    printf("Data In: %ld\n", data);
-    printf("Exited  %s:\n", __FUNCTION__);
-    fflush(stdout);
-    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__);
-    fflush(stdout);
-    return data;
-}
-
-float
-f_f_test(float data)
-{
-    printf("Entered %s:\n", __FUNCTION__);
-    printf("Data In: %e\n", data);
-    printf("Exited  %s:\n", __FUNCTION__);
-    fflush(stdout);
-    return data;
-}
-
-double
-d_d_test(double data)
-{
-    printf("Entered %s:\n", __FUNCTION__);
-    printf("Data In: %e\n", data);
-    printf("Exited  %s:\n", __FUNCTION__);
-    fflush(stdout);
-    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")
-#&lt;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 on 32-bit machines.
-(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")
-#&lt;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-floa=
t,
-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 function=
s 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=3D"Acknowledgement">
-        <title>Acknowledgement</title>
-	<para>This chapter was generously contributed by Andrew
-	P. Lentvorski Jr.</para>
-      </sect2>
-    </sect1>
-
-    <sect1 id=3D"Tutorial--Allocating-Foreign-Data-on-the-Lisp-Heap">
-      <title>Tutorial: Allocating Foreign Data on the Lisp Heap </title>
-      <para>Not every foreign function is so marvelously easy to use
-      as the ones we saw in the last section.  Some of them require
-      you to allocate a C struct, fill it in with your own
-      information, and pass it a pointer to the struct.  Some of them
-      require you to allocate an empty struct so they can fill it in,
-      and then you can read the information out of it.</para>
-      <para>Also, some of them have their own structs and return a
-      pointer to that same struct every time you call them, but those
-      are easier to deal with, so they won't be covered in this
-      section.</para>
-      <para>You might know that Lisp (and, indeed, most programming
-      languages) has two separate regions of memory.  There's the
-      stack, which is where variable bindings are kept.  Memory on the
-      stack is allocated every time any function is called, and
-      deallocated when it returns, so it's useful for anything that
-      doesn't need to last longer than one function call, when there's
-      only one thread.  If that's all you need, you can do it with
-      .</para>
-      <para>Then, there's the heap, which holds everything else, and
-      is our subject here.  There are two advantages and one big
-      disadvantage to putting things on the heap rather than the
-      stack.  First, data allocated on the heap can be passed outside
-      of the scope in which it was created.  This is useful for data
-      which may need to be passed between multiple C calls or multiple
-      threads. Also, some data may be too large to copy multiple times
-      or may be too large to allocate on the stack.</para>
-      <para>The second advantage is security.  If incoming data is
-      being placed directly onto the stack, the input data can cause
-      stack overflows and underflows.  This is not something which
-      Lisp users generally worry about since garbage collection
-      generally handles memory management.  However, "stack smashing"
-      is one of the classic exploits in C which malicious hackers can
-      use to gain control of a machine.  Not checking external data is
-      always a bad idea; however, allocating it into the heap at least
-      offers more protection than direct stack allocation.</para>
-      <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 &lt;stdio.h&gt;
-
-void reverse_int_array(int * data, unsigned int dataobjs)
-{
-  int i, t;
-
-  for(i=3D0; i&lt;dataobjs/2; i++)
-    {
-      t =3D *(data+i);
-      *(data+i) =3D *(data+dataobjs-1-i);
-      *(data+dataobjs-1-i) =3D t;
-    }
-}
-
-void reverse_int_ptr_array(int **ptrs, unsigned int ptrobjs)
-{
-  int *t;
-  int i;
-
-  for(i=3D0; i&lt;ptrobjs/2; i++)
-    {
-      t =3D *(ptrs+i);
-      *(ptrs+i) =3D *(ptrs+ptrobjs-1-i);
-      *(ptrs+ptrobjs-1-i) =3D 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 ./libptr=
test.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 (=3D (logand subtag target::fulltagmask)
-               target::fulltag-immheader)
-      (error "~s is not an ivector subtype." element-type))
-    (let* ((size-in-bytes (ccl::subtag-bytes subtag element-count)))
-      (ccl::%make-heap-ivector subtag size-in-bytes element-count))))
-MAKE-HEAP-IVECTOR
-
-? ;; dispose-heap-ivector created for symmetry
-(defmacro dispose-heap-ivector (a mp)
-  `(progn
-     (ccl::%dispose-heap-ivector ,a)
-     ;; Demolish the arguments for safety
-     (setf ,a nil)
-     (setf ,mp nil)))
-DISPOSE-HEAP-IVECTOR
-</programlisting>
-      <para>If you don't understand how those functions do what they do.
-      That's okay; it gets into very fine detail which really doesn't
-      matter, because you don't need to change them.</para>
-      <para>The function <literal>make-heap-ivector</literal> is the
-      primary tool for allocating objects in heap memory.  It
-      allocates a fixed-size 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.
-#&lt;A Mac Pointer #x10217C>
-
-? a
-#(1396 2578 97862649)
-
-? ap
-#&lt;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")
-#&lt;SHLIB /Users/andrewl/openmcl/openmcl/gtk/libptrtest.dylib #x639D1E6>
-
-? a
-#(6 4 7)
-
-? ap
-#&lt;A Mac Pointer #x10217C>
-
-? (external-call "_reverse_int_array" :address ap :unsigned-int (length a)=
 :address)
-#&lt;A Mac Pointer #x10217C>
-
-? a
-#(7 4 6)
-
-? ap
-#&lt;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=3D"Acknowledgement--1-">
-	<title>Acknowledgement</title>
-	<para>Much of this chapter was generously contributed by
-	Andrew P. Lentvorski Jr.</para>
-      </sect2>
-    </sect1>
-
-    <sect1>
-      <title>The Foreign-Function-Interface Dictionary</title>
-        =

-      <refentry id=3D"m_def-foreign-type">
-	<indexterm zone=3D"m_def-foreign-type">
-	  <primary>def-foreign-type</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>DEF-FOREIGN-TYPE</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>def-foreign-type</function> name foreign-type-spec
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>name</term>
-	      =

-	      <listitem>
-		<para>NIL or a keyword; the keyword may contain
-		<link linkend=3D"Case-sensitivity-of-foreign-names-in-OpenMCL" >escaping=
 constructs</link>.</para>
-	      </listitem>
-	    </varlistentry>
-	    =

-	    <varlistentry>
-	      <term>foreign-type-spec</term>
-	      =

-	      <listitem>
-		<para>A foreign type specifier, whose syntax is (loosely)
-		defined above.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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
-	  <varname>name</varname> refers to depends on
-	  <varname>foreign-type-spec</varname> in the obvious manner.
-	  </para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_make-record">
-	<indexterm zone=3D"m_make-record">
-	  <primary>make-record</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>MAKE-RECORD</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>make-record</function> typespec
-	    &rest; initforms =3D> result
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>typespec</term>
-
-	      <listitem>
-		<para>A foreign type specifier, or a keyword which is used
-		as the name of a foreign struct or union.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>initforms</term>
-
-	      <listitem>
-		<para>If the type denoted by <varname>typespec</varname>
-		is scalar, a single value appropriate for that type;
-		otherwise, a list of alternating field names and
-		values appropriate for the types of those fields.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>result</term>
-
-	      <listitem>
-		<para>
-		  A <type>macptr</type> which encapsulates the address of a
-		  newly-allocated record on the foreign heap.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>
-	    Expands into code which allocates and initalizes
-	    an instance of the type =

-	    denoted by <varname>typespec</varname>, on the foreign
-	    heap.  The record is allocated using the C function
-	    <function>malloc</function>, and the user of
-	    <function>make-record</function> must explicitly call
-	    the C function <function>free</function> to deallocate the
-	    record, when it is no longer needed.
-	  </para>
-
-	  <para>
-	    If <varname>initforms</varname> is provided, its value
-	    or values are used in the initialization.  When the type
-	    is a scalar, <varname>initforms</varname> 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 <type>struct</type>,
-	    <varname>initforms</varname> 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, <varname>initforms</varname> may
-	    not be provided, because <function>make-record</function>
-	    cannot initialize its values.  <function>make-record</function>
-	    is also unable to initialize fields of a <type>struct</type>
-	    which are themselves
-	    <type>struct</type>s.  The user of
-	    <function>make-record</function> 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;
-	    <function>make-record</function> signals an error if this is
-	    not the case.
-	  </para>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <para>
-	    It is inconvenient that <function>make-record</function> is a
-	    macro, because this means that <varname>typespec</varname>
-	    cannot be a variable; it must be an immediate value.
-	  </para>
-	    =

-	  <para>
-	    If it weren't for this requirement,
-	    <function>make-record</function> 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 <xref linkend=3D"The-Interface-Database"/>), which is undesireab=
le
-	    because it's large.
-	  </para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_rlet">
-	<indexterm zone=3D"m_rlet">
-	  <primary>rlet</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>RLET</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>rlet</function> (var typespec &rest; initforms)*
-	    &body; body
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>var</term>
-
-	      <listitem>
-		<para>A symbol (a lisp variable)</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>typespec</term>
-
-	      <listitem>
-		<para>A foreign type specifier or foreign record name.</para>
-	      </listitem>
-	    </varlistentry>
-
- <varlistentry>
-	      <term>initforms</term>
-
-	      <listitem>
-		<para>As described above, for
-		<xref linkend=3D"m_make-record"/></para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Executes <varname>body</varname>
-	  in an environment in which each var is bound
-	  to <link linkend=3D"Referencing-and-Using-Foreign-Memory-Addresses">a M=
ACPTR</link> encapsulating the
-	  address of a stack-allocated foreign memory block, allocated and
-	  initialized from typespec and initforms as per
-	  <xref linkend=3D"m_make-record"/>.
-	  Returns whatever value(s) <varname>body</varname>
-	  returns.</para>
-	  =

-	  <para>Record fields that aren&#39;t explicitly initialized have
-	  unspecified contents.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_rletz">
-	<indexterm zone=3D"m_rletz">
-	  <primary>rletz</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>RLETZ</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>rletz</function> (var typespec &rest; initforms)*
-	    &body; body
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>var</term>
-
-	      <listitem>
-		<para>A symbol (a lisp variable)</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>typespec</term>
-
-	      <listitem>
-		<para>A foreign type specifier or foreign record name.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>initforms</term>
-
-	      <listitem>
-		<para>As described above, for ccl:make-record</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Executes body in an environment in which each var is
-	  bound to <link
-	  linkend=3D"Referencing-and-Using-Foreign-Memory-Addresses">a
-	  MACPTR</link> 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&#39;t explicitly
-	  initialized are set to binary 0.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_pref">
-	<indexterm zone=3D"m_pref">
-	  <primary>pref</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>PREF</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>pref</function> ptr accessor-form
-	  </synopsis>
-
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>ptr</term>
-
-	      <listitem>
-		<para><link linkend=3D"Referencing-and-Using-Foreign-Memory-Addresses">a=
 MACPTR</link>.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>accessor-form</term>
-
-	      <listitem>
-		<para>a keyword which names a foreign type or record, as
-		described in <xref linkend=3D"Foreign-type--record--and-field-names"/>.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_open-shared-library">
-	<indexterm zone=3D"f_open-shared-library">
-	  <primary>open-shared-library</primary>
-	</indexterm>
-	=

-	<refnamediv>
-	  <refname>OPEN-SHARED-LIBRARY</refname>
-	  <refpurpose>Asks the operating system to load a shared library
-	  for OpenMCL to use.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-	=

-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>open-shared-library</function> name =3D> library
-	  </synopsis>
-	</refsynopsisdiv>
-	=

-	<refsect1>
-	  <title>Values</title>
-	  =

-	  <variablelist>
-	    <varlistentry>
-	      <term>name</term>	=

-	      <listitem>
-		<para>A SIMPLE-STRING which is presumed to be the so-name of
-		or a filesystem path to the library.</para>
-	      </listitem>
-	    </varlistentry>
-	    =

-	    <varlistentry>
-	      <term>library</term>
-	      <listitem>
-		<para>An object of type SHLIB which describes the
-		library denoted by <varname>name</varname>.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-	=

-	<refsect1>
-	  <title>Description</title>
-
-	  <para>If the library denoted by <varname>name</varname> 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&#39;t be loaded, signals a
-	  SIMPLE-ERROR which contains an often-cryptic message from the
-	  operating system.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>Examples</title>
-
-	  <programlisting format=3D"linespecific">;;; Try to do something simple.
-? (open-shared-library &#34;libgtk.so&#34;)
-&#62; Error: Error opening shared library &#34;libgtk.so&#34;: /usr/lib/li=
bgtk.so: undefined symbol: gdk_threads_mutex
-&#62; While executing: OPEN-SHARED-LIBRARY
-
-;;; Grovel around, curse, and try to find out where &#34;gdk_threads_mutex=
&#34;
-;;; might be defined. Then try again:
-
-? (open-shared-library &#34;libgdk.so&#34;)
-#&#60;SHLIB libgdk.so #x3046DBB6&#62;
-
-? (open-shared-library &#34;libgtk.so&#34;)
-#&#60;SHLIB libgtk.so #x3046DC86&#62;
-
-;;; Reference an external symbol defined in one of those libraries.
-
-? (external &#34;gtk_main&#34;)
-#&#60;EXTERNAL-ENTRY-POINT &#34;gtk_main&#34; (#x012C3004) libgtk.so #x304=
6FE46&#62;
-
-;;; Close those libraries.
-
-? (close-shared-library &#34;libgtk.so&#34;)
-T
-
-? (close-shared-library &#34;libgdk.so&#34;)
-T
-
-;;; Reference the external symbol again.
-
-? (external &#34;gtk_main&#34;)
-#&#60;EXTERNAL-ENTRY-POINT &#34;gtk_main&#34; {unresolved} libgtk.so #x304=
6FE46&#62;</programlisting>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_close-shared-library">
-	<indexterm zone=3D"f_close-shared-library">
-	  <primary>close-shared-library</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CLOSE-SHARED-LIBRARY</refname>
-	  <refpurpose>Stops using a shared library, informing the operating
-	  system that it can be unloaded if appropriate.</refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>close-shared-library</function> library &key;
-	  completely</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>library</term>
-
-	      <listitem>
-		<para>either an object of type SHLIB, or a string which
-		designates one by its so-name.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>completely</term>
-
-	      <listitem>
-		<para>a boolean.  The default is T.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>If <varname>completely</varname> is T, sets the
-	  reference count of <varname>library</varname> to 0.  Otherwise,
-	  decrements it by 1.  In either case, if the reference count
-	  becomes 0, <function>close-shared-library</function>
-	  frees all memory resources consumed <varname>library</varname>
-	  and
-	  causes any EXTERNAL-ENTRY-POINTs known to be defined by it to
-	  become unresolved.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_external">
-	<indexterm zone=3D"m_external">
-	  <primary>external</primary>
-	</indexterm>
-	=

-	<refnamediv>
-	  <refname>EXTERNAL</refname>
-	  <refpurpose>Resolves a reference to an external symbol which
-	  is defined in a shared library.</refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>external</function> name =3D> entry
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>name</term>
-	      <listitem>
-		<para>
-		  a simple-string which names an external symbol.
-		  Case-sensitive.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>entry</term>
-	      <listitem>
-		<para>
-		  an object of type EXTERNAL-ENTRY-POINT which maintains
-		  the address of the foreign symbol named by
-		  <varname>name</varname>.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>If there is already an EXTERNAL-ENTRY-POINT for
-	  the symbol named by <varname>name</varname>, 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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_Pff-call">
-	<indexterm zone=3D"f_Pff-call">
-	  <primary>%ff-call</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>%FF-CALL</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>%ff-call</function> entrypoint
-	    {arg-type-keyword arg}* &optional; result-type-keyword
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>entrypoint</term>
-	      =

-	      <listitem>
-		<para>A fixnum or MACPTR</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>arg-type-keyword</term>
-
-	      <listitem>
-		<para>One of the foreign argument-type keywords, described
-		above</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>arg</term>
-
-	      <listitem>
-		<para>A lisp value of type indicated by the corresponding
-		arg-type-keyword</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>result-type-keyword</term>
-
-	      <listitem>
-		<para>One of the foreign argument-type keywords, described
-		above</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_ff-call">
-	<indexterm zone=3D"m_ff-call">
-	  <primary>ff-call</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>FF-CALL</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>ff-call</function> entrypoint
-	    {arg-type-specifier arg}* &optional; result-type-specifier
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>entrypoint</term>
-
-	      <listitem>
-		<para>A fixnum or MACPTR</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>arg-type-specifer</term>
-
-	      <listitem>
-		<para>One of the foreign argument-type keywords, described
-		above, or an equivalent <link linkend=3D"Specifying-And-Using-Foreign-Ty=
pes">foreign
-		type specifier</link>.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>arg</term>
-
-	      <listitem>
-		<para>A lisp value of type indicated by the corresponding
-		arg-type-specifier</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>result-type-specifier</term>
-
-	      <listitem>
-		<para>One of the foreign argument-type keywords, described
-		above, or an equivalent <link linkend=3D"Specifying-And-Using-Foreign-Ty=
pes">foreign
-		type specifier</link>.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_Preference-external-entry-point">
-	<indexterm zone=3D"f_Preference-external-entry-point">
-	  <primary>%reference-external-entry-point</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>%REFERENCE-EXTERNAL-ENTRY-POINT</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>%reference-external-entry-point</function> eep
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>eep</term>
-
-	      <listitem>
-		<para>An EXTERNAL-ENTRY-POINT, as obtained by the EXTERNAL
-		macro.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_external-call">
-	<indexterm zone=3D"m_external-call">
-	  <primary>external-call</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>EXTERNAL-CALL</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>external-call</function> name
-	    {arg-type-specifier arg}* &optional; result-type-specifier
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>name</term>
-
-	      <listitem>
-		<para>A lisp string. See external, above.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>arg-type-specifer</term>
-
-	      <listitem>
-		<para>One of the foreign argument-type keywords, described
-		above, or an equivalent <link linkend=3D"Specifying-And-Using-Foreign-Ty=
pes">foreign
-		type specifier</link>.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>arg</term>
-
-	      <listitem>
-		<para>A lisp value of type indicated by the corresponding
-		arg-type-specifier</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>result-type-specifier</term>
-
-	      <listitem>
-		<para>One of the foreign argument-type keywords, described
-		above, or an equivalent <link linkend=3D"Specifying-And-Using-Foreign-Ty=
pes">foreign
-		type specifier</link>.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_foreign-symbol-entry">
-	<indexterm zone=3D"f_foreign-symbol-entry">
-	  <primary>foreign-symbol-entry</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>FOREIGN-SYMBOL-ENTRY</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>foreign-symbol-entry</function> name
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>name</term>
-
-	      <listitem>
-		<para>A lisp string.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Tries to resolve the address of the foreign symbol name. If
-	  successful, returns a fixnum representation of that address, else
-	  returns NIL.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_foreign-symbol-address">
-	<indexterm zone=3D"f_foreign-symbol-address">
-	  <primary>foreign-symbol-address</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>FOREIGN-SYMBOL-ADDRESS</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>foreign-symbol-address</function> name
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>name</term>
-
-	      <listitem>
-		<para>A lisp string.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Tries to resolve the address of the foreign symbol
-	  name. If successful, returns that address encapsulated in
-	  <link
-	  linkend=3D"Referencing-and-Using-Foreign-Memory-Addresses">a
-	  MACPTR</link>, else returns NIL.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_defcallback">
-	<indexterm zone=3D"m_defcallback">
-	  <primary>defcallback</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>DEFCALLBACK</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>defcallback</function> name
-	    ({arg-type-specifier var}* &optional; result-type-specifier)
-	    &body; body
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>name</term>
-
-	      <listitem>
-		<para>A symbol which can be made into a special variable</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>arg-type-specifer</term>
-
-	      <listitem>
-		<para>One of the foreign argument-type keywords,
-		described above, or an equivalent <link
-		linkend=3D"Specifying-And-Using-Foreign-Types">foreign
-		type specifier</link>.  In addition, if the keyword
-		:WITHOUT-INTERRUPTS is specified, the callback will be
-		executed with lisp interrupts disabled if the
-		corresponding var is non-NIL. If :WITHOUT-INTERRUPTS
-		is specified more than once, the rightmost instance
-		wins.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>var</term>
-
-	      <listitem>
-		<para>A symbol (lisp variable), which will be bound to a
-		value of the specified type.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>body</term>
-
-	      <listitem>
-		<para>A sequence of lisp forms, which should return a value
-		which can be coerced to the specified result-type.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Proclaims <varname>name</varname>
-	  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 <varname>name</varname>
-	  is already a callback function pointer, its value is
-	  not changed; instead, it&#39;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><function>defcallback</function>
-	  returns the callback pointer, e.g., the
-	  value of <varname>name</varname>.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"rm_sharpsign-underscore">
-	<indexterm zone=3D"rm_sharpsign-underscore">
-	  <primary>#_</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>#_</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Reader Macro</refclass>
-	</refnamediv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Reads a symbol from the current input stream, with *PACKAGE*
-	  bound to the &#34;OS&#34; package and with readtable-case preserved.</p=
ara>
-	  =

-	  <para>Does a lookup on that symbol in <link
-	  linkend=3D"The-Interface-Database">the OpenMCL interface
-	  database</link>, signalling an error if no foreign function
-	  information can be found for the symbol in any active <link
-	  linkend=3D"Using-Interface-Directories">interface
-	  directory</link>.</para>
-
-	  <para>Notes the foreign function information, including the foreign
-	  function&#39;s return type, the number and type of the foreign
-	  function&#39;s required arguments, and an indication of whether or
-	  not the function accepts additional arguments (via e.g., the
-	  &#34;varargs&#34; 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&#39;s possible to call
-	  foreign functions that take fixed numbers of arguments by simply
-	  providing argument values, as in:</para>
-
-	  <programlisting format=3D"linespecific">(#_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 format=3D"linespecific">(with-cstrs ((format-string &#3=
4;the answer is: %d&#34;))
-  (#_printf format-string :int answer))</programlisting>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"rm_sharpsign-questionmark">
-	<indexterm zone=3D"rm_sharpsign-questionmark">
-	  <primary>#?</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>#?</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Reader Macro</refclass>
-	</refnamediv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>In OpenMCL 0.14.2 and later, the #? reader macro can be used to
-	  access foreign variables; this functionality depends on the presence of
-	  &#34;vars.cdb&#34; files in the interface database. The current behavior
-	  of the #? reader macro is to:</para>
-
-	  <para>Read a symbol from the current input stream, with *PACKAGE*
-	  bound to the &#34;OS&#34; package and with readtable-case preserved.</p=
ara>
-	  =

-	  <para>Use that symbol&#39;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&#39;re generally talking about C and Unix here ...). When
-	  they do match, the form constructed by the #? reader macro manages the
-	  details of resolving and tracking changes to the foreign variable&#39;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
-	  packge-specific (the canonical example - &#34;errno&#34; - is typically
-	  not a variable when threads are involved. )</para>
-
-	  <para>In LinuxPPC, </para>
-
-	  <programlisting>? #?stderr</programlisting>
-
-	  <para>returns a pointer to the stdio error stream (&#34;stderr&#34; is a
-	  macro under OSX/Darwin).</para>
-
-	  <para>On both LinuxPPC and DarwinPPC, </para>
-
-	  <programlisting>? #?sys_errlist</programlisting>
-
-	  <para>returns a pointer to a C array of C error message strings.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_use-interface-dir">
-	<indexterm zone=3D"f_use-interface-dir">
-	  <primary>use-interface-dir</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>USE-INTERFACE-DIR</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>use-interface-dir</function> dir-id
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>dir-id</term>
-
-	      <listitem>
-		<para>A keyword whose pname, mapped to lower case, names a
-		subdirectory of &#34;ccl:headers;&#34; (or
-		"ccl:darwin-headers;")</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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 <function>use-interface-dir</function>
-	  merely adds an entry
-	  to a search list.
-	  If the named directory doesn&#39;t exist in the file system
-	  or doesn&#39;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. <xref linkend=3D"f_unuse-interface-dir"/>
-	  may come in
-	  handy in that case.</para>
-	</refsect1>
-
-	<refsect1>
-	  <title>Examples</title>
-
-	  <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 format=3D"linespecific">(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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_unuse-interface-dir">
-	<indexterm zone=3D"f_unuse-interface-dir">
-	  <primary>unuse-interface-dir</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>UNUSE-INTERFACE-DIR</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>unuse-interface-dir</function> dir-id
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>dir-id</term>
-
-	      <listitem>
-		<para>A keyword whose pname, mapped to lower case, names a
-		subdirectory of &#34;ccl:headers;&#34; (or
-		"ccl:darwin-headers;")</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_terminate-when-unreachable">
-	<indexterm zone=3D"f_terminate-when-unreachable">
-	  <primary>terminate-when-unreachable</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>TERMINATE-WHEN-UNREACHABLE</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>terminate-when-unreachable</function> object
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>object</term>
-
-	      <listitem>
-		<para>A CLOS object of a class for which there exists
-		a method of the generic function
-		<function>ccl:terminate</function>.
-		</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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
-	    <function>ccl:terminate-when-unreachable</function> has been
-	    called on the object at any time, the garbage collector first
-	    invokes the generic function <function>ccl:terminate</function>,
-	    passing it the object as a parameter.
-	  </para>
-
-	  <para>
-	    Therefore, to make termination do something useful, you need to
-	    define a method on <function>ccl:terminate</function>.
-	  </para>
-
-	  <para>
-	    Because calling
-	    <function>ccl:terminate-when-unreachable</function> only
-	    affects a single object, rather than all objects of its
-	    class, you
-	    may wish to put a call to it in the
-	    <function>initialize-instance</function> 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>
-	</refsect1>
-
-	<refsect1>
-	  <title>Example</title>
-
-      <programlisting format=3D"linespecific">
-(defclass resource-wrapper ()
-  ((resource :accessor resource)))
-
-(defmethod initialize-instance :after ((x resource-wrapper) &amp;rest init=
args)
-  (ccl:terminate-when-unreachable x))
-
-(defmethod ccl:terminate ((x resource-wrapper))
-  (when (resource x)
-    (deallocate (resource x))))</programlisting>
-	</refsect1>
-
-	<refsect1>
-	  <title>See Also</title>
-
-	  <simplelist type=3D"inline">
-	    <member><xref linkend=3D"Tutorial--Allocating-Foreign-Data-on-the-Lis=
p-Heap"/></member>
-	  </simplelist>
-	</refsect1>
-
-      </refentry>
-
-    </sect1>
-  </chapter>
-
-  <chapter id=3D"The-Objective-C-Bridge">
-    <title>The Objective-C Bridge</title>
-
-    <para>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=3D"Using-Objective-C-Classes">
-      <title>Using Objective-C Classes</title>
-
-      <para>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 w=
indow
-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=3D"Instantiating-Objective-C-Objects">
-      <title>Instantiating Objective-C Objects</title>
-      <para>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)
-#&lt;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))
-#&lt;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-control=
ler
-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*))
-#&lt;NS-WINDOW-CONTROLLER &lt;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=3D"Calling-Objective-C-Methods">
-      <title>Calling Objective-C Methods</title>
-      <para>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 or=
dinary
-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=3D"Type-Coercion-for-ObjC-Method-Calls">
-	<title>Type Coercion for ObjC Method Calls</title>
-        <para>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>
-      </sect2>
-
-      <sect2 id=3D"Methods-which-Return-Structures">
-	<title>Methods which Return Structures</title>
-        <para>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 =3D [v1 bounds];
-[v2 setBounds r];
-	</programlisting>
-        <para>In Lisp, we must explicitly allocate the memory, which
-        is done most easily and safely with <xref linkend=3D"m_rlet"/>.
-        We do it like this:</para>
-        <programlisting>
-(rlet ((r :&lt;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 conveni=
ence
-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=3D"Variable-Arity-Messages">
-	<title>Variable-Arity Messages</title>
-        <para>
-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 informa=
tion
-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=3D"Optimization">
-	<title>Optimization</title>
-        <para>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=3D"Defining-Objective-C-Classes">
-      <title>Defining Objective-C Classes</title>
-      <para>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=3D"Defining-classes-with-foreign-slots">
-	<title>Defining classes with foreign slots</title>
-        <para>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=3D"Defining-classes-with-Lisp-slots">
-	<title>Defining classes with Lisp slots</title>
-        <para>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=3D"Defining-Objective-C-Methods">
-      <title>Defining Objective-C Methods</title>
-      <para>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 :&lt;BOOL>)
-  (declare (ignore sender))
-  nil)
-
-(define-objc-method ((:&lt;BOOL>
-                      :application-should-terminate sender)
-                     lisp-application-delegate)
-  (declare (ignore sender))
-  nil)
-</programlisting>
-      <sect2 id=3D"Method-Redefinition-Constraints">
-	<title>Method Redefinition Constraints</title>
-        <para>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=3D"How-Objective-C-Names-are-Mapped-to-Lisp-Symbols">
-      <title>How Objective-C Names are Mapped to Lisp Symbols</title>
-      <para>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>
-	<simplelist type=3D"vert">
-	  <member>(ccl::objc-to-lisp-classname string)</member>
-	  <member>(ccl::lisp-to-objc-classname symbol)</member>
-	  <member>(ccl::objc-to-lisp-message string)</member>
-	  <member>(ccl::lisp-to-objc-message string)</member>
-	  <member>(ccl::objc-to-lisp-init string)</member>
-	  <member>(ccl::lisp-to-objc-init keyword-list)</member>
-	</simplelist>
-
-      <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=3D"Platform-specific-notes">
-    <title>Platform-specific notes</title>
-      =

-
-    <sect1 id=3D"Platform-specific-overview">
-      <title>Overview</title>
-      <para> The documentation and whatever experience you may have in
-      using OpenMCL under Linux should also apply to using it under
-      Darwin/MacOS X and FreeBSD. There are some differences between
-      the platforms, and these differences are sometimes exposed in
-      the implementation.</para>
-
-
-      <sect2 id=3D"File-system-case">
-	<title>File-system case</title>
-
-	<para>Darwin and MacOS X use HFS+ file systems by default;
-	HFS+ file systems are usually 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"FOO"
-	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>on 32-bit DarwinPPC 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=3D"Line-Termination-Characters">
-	<title>Line Termination Characters</title>
-        <para>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.  Many modern
-	GUI programs try to support several different line-termination
-	conventions (on the theory that the user shouldn't be too concerned
-	about what conventions are used an that it probably doesn't matter.
-	Sometimes this is true, other times ... not so much.
-	</para>
-        <para>OpenMCL follows the Unix convention on both Darwin and
-        LinuxPPC, but offers some support for reading and writing
-        files that use other conventions (including traditional MacOS
-        conventions) 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=3D"Single-precision-trig---transcendental-functions">
-	<title>Single-precision trig &amp; transcendental functions</title>
-        <para>
-	Despite what Darwin's man pages say, early versions of its math library
-	(up to and including at least OSX 10.2 (Jaguar) don't implement
-	single-precision variants of the transcendental and trig functions
-	(#_sinf, #_atanf, etc.) OpenMCL worked 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=3D"Shared-libraries">
-	<title>Shared libraries</title>
-        <para>Darwin/MacOS X distinguishes between "shared libraries"
-        and "bundles" or "extensions"; Linux and FreeBSD don'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>
-      </sect2>
-    </sect1>
-
-    <sect1 id=3D"Unix-Posix-Darwin-Features">
-      <title>Unix/Posix/Darwin Features</title>
-      <para>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 <xref
-      linkend=3D"Running-Other-Programs-as-Subprocesses"/>.  However,
-      sometimes you may want to specifically ask the shell to invoke a
-      command for you.</para>
-    </sect1>
-
-    <sect1 id=3D"Cocoa-Programming-in-OpenMCL">
-      <title>Cocoa Programming in OpenMCL</title>
-      <para>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=3D"The-Command-Line-and-the-Window-System">
-	<title>The Command Line and the Window System</title>
-        <para>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=3D"Writing--and-reading--Cocoa-code">
-	<title>Writing (and reading) Cocoa code</title> <para>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>
-	<simplelist type=3D"vert" columns=3D"1">
-	  <member><xref linkend=3D"m_class"/></member>
-	  <member><xref linkend=3D"m_selector"/></member>
-	  <member><xref linkend=3D"m_define-objc-method"/></member>
-	  <member><xref linkend=3D"m_define-objc-class-method"/></member>
-	</simplelist>
-      </sect2>
-
-      <sect2 id=3D"The-Application-Kit-and-Multiple-Threads">
-	<title>The Application Kit and Multiple Threads</title>
-        <para>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=3D"Acknowledgement--2-">
-	<title>Acknowledgement</title>
-        <para>The Cocoa bridge was originally developed, and
-        generously contributed by, Randal Beer.</para>
-      </sect2>
-    </sect1>
-
-    <sect1 id=3D"Building-an-Application-Bundle">
-      <title>Building an Application Bundle</title>
-      <para>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 OpenM=
CL 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 sav=
ed
-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=3D"Recommended-Reading">
-      <title>Recommended Reading></title>
-      <variablelist>
-	<varlistentry>
-	   <term>
-	     <ulink url=3D"http://developer.apple.com/documentation/Cocoa/">Cocoa=
 Documentation</ulink>
-	   </term>
-
-	   <listitem>
-	     <para>
-	       This is the top page for all of Apple's documentation on
-	       Cocoa.  If you are unfamiliar with Cocoa, it is a good
-	       place to start.
-	     </para>
-	   </listitem>
-	</varlistentry>
-	<varlistentry>
-	  <term>
-	    <ulink url=3D"http://developer.apple.com/documentation/Cocoa/Referenc=
e/Foundation/ObjC_classic/index.html">Foundation Reference for Objective-C<=
/ulink>
-	  </term>
-
-	  <listitem>
-	    <para>
-	      This is one of the two most important Cocoa references; it
-	      covers all of the basics, except for GUI programming.  This is
-	      a reference, not a tutorial.
-	    </para>
-	  </listitem>
-	</varlistentry>
-
-	<varlistentry>
-	  <term>
-	    <ulink url=3D"http://developer.apple.com/documentation/Cocoa/Referenc=
e/ApplicationKit/ObjC_classic/index.html">Application Kit Reference for Obj=
ective-C</ulink>
-	  </term>
-
-	  <listitem>
-	    <para>
-	      This is the other; it covers GUI programming with Cocoa
-	      in considerable depth.  This is a reference, not a tutorial.
-	    </para>
-	  </listitem>
-	</varlistentry>
-
-	<varlistentry>
-	  <term>
-	    <ulink url=3D"http://developer.apple.com/documentation/index.html">Ap=
ple Developer Documentation</ulink>
-	  </term>
-
-	  <listitem>
-	    <para>
-	      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.
-	    </para>
-	  </listitem>
-	</varlistentry>
-      </variablelist>
-
-    </sect1>
-
-    <sect1 id=3D"Operating-System-Dictionary">
-      <title>Operating-System Dictionary</title>
-
-      <refentry id=3D"f_getenv">
-	<indexterm zone=3D"f_getenv">
-	  <primary>getenv</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL::GETENV</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>getenv</function> name =3D> value</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>name</term>
-
-	      <listitem>
-		<para>a string which is the name of an existing
-		environment variable;
-		case-sensitive</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>value</term>
-
-	      <listitem>
-		<para>if there is an environment variable named
-		<varname>name</varname>, its value, as a string; if there
-		is not, NIL</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>
-	    Looks up the value of the environment variable named by
-	    <varname>name</varname>, in the OS environment.
-	  </para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_setenv">
-	<indexterm zone=3D"f_setenv">
-	  <primary>setenv</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL::SETENV</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>setenv</function> name value =3D> errno</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>name</term>
-
-	      <listitem>
-		<para>a string which is the name of a new or existing
-		environment variable;
-		case-sensitive</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>value</term>
-
-	      <listitem>
-		<para>a string, to be the new value of the
-		environment variable
-		named by <varname>name</varname></para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>errno</term>
-
-	      <listitem>
-		<para>zero if the function call completes successfully;
-		otherwise, a platform-dependent integer which describes
-		the problem</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>
-	    Sets the value of the environment variable named by
-	    <varname>name</varname>, in the OS environment.  If there is
-	    no such environment
-	    variable, creates it.
-	  </para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_current-directory-name">
-	<indexterm zone=3D"f_current-directory-name">
-	  <primary>current-directory-name</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL::CURRENT-DIRECTORY-NAME</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>current-directory-name</function>
-	  =3D> path</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>path</term>
-
-	      <listitem>
-		<para>a string, an absolute pathname in Posix format - with
-		directory components separated by slashes</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_getuid">
-	<indexterm zone=3D"f_getuid">
-	  <primary>getuid</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL::GETUID</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>getuid</function> =3D> uid</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>uid</term>
-
-	      <listitem>
-		<para>a non-negative integer, identifying a specific user
-		account as defined in the OS user database</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>
-	    Returns the ("real") user ID of the current user.
-	  </para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_setuid">
-	<indexterm zone=3D"f_setuid">
-	  <primary>setuid</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL::SETUID</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>setuid</function> uid =3D> errno</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>uid</term>
-
-	      <listitem>
-		<para>a non-negative integer, identifying a specific user
-		account as defined in the OS user database</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>errno</term>
-
-	      <listitem>
-		<para>zero if the function call completes successfully;
-		otherwise, a platform-dependent integer which describes
-		the problem</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_setgid">
-	<indexterm zone=3D"f_setgid">
-	  <primary>setgid</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL::SETGID</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>setgid</function> gid =3D> errno</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>gid</term>
-
-	      <listitem>
-		<para>a non-negative integer, identifying a specific
-		group as defined in the OS user database</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>errno</term>
-
-	      <listitem>
-		<para>zero if the function call completes successfully;
-		otherwise, a platform-dependent integer which describes
-		the problem</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_getpid">
-	<indexterm zone=3D"f_getpid">
-	  <primary>getpid</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL::GETPID</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>getpid</function> =3D> pid</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>pid</term>
-
-	      <listitem>
-		<para>a non-negative integer, identifying an OS process</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>
-	    Returns the ID of the OpenMCL OS process.
-	  </para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_get-user-home-dir">
-	<indexterm zone=3D"f_get-user-home-dir">
-	  <primary>get-user-home-dir</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL::GET-USER-HOME-DIR</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>get-user-home-dir</function> =

-	  uid =3D> path</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>uid</term>
-
-	      <listitem>
-		<para>a non-negative integer, identifying a specific user
-		account as defined in the OS user database</para>
-	      </listitem>
-	    </varlistentry>
-	    <varlistentry>
-	      <term>path</term>
-
-	      <listitem>
-		<para>a string, an absolute pathname in Posix format - with
-		directory components separated by slashes; or NIL</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>
-	    Looks up and returns the defined home directory of the user
-	    identified by <varname>uid</varname>.  This value comes from the
-	    OS user database, not from the <varname>$HOME</varname>
-	    environment variable.  Returns NIL if there is no user with
-	    the ID <varname>uid</varname>.
-	  </para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_os-command">
-	<indexterm zone=3D"f_os-command">
-	  <primary>os-command</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CCL::OS-COMMAND</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>os-command</function> command-line
-	  =3D> exit-code</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>command-line</term>
-
-	      <listitem><para>a string, obeying all the whitespace and
-	      escaping
-	      conventions required by the user's default system shell</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	  <variablelist>
-	    <varlistentry>
-	      <term>exit-code</term>
-
-	      <listitem><para>a non-negative integer, returned as the exit
-	      code of a subprocess; zero indicates success</para></listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>
-	    Invokes the Posix function <function>system()</function>, which
-	    invokes the user's default system shell (such as
-	    sh or tcsh) as a new process, and has that shell execute
-	    <varname>command-line</varname>.
-	  </para>
-	  =

-	  <para>
-	    If the shell was able to find the command specified in
-	    <varname>command-line</varname>, then <varname>exit-code</varname>
-	    is the exit code of that command.  If not, it is the exit
-	    code of the shell itself.
-	  </para>
-	</refsect1>
-
-	<refsect1>
-	  <title>Notes</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"m_class">
-	<indexterm zone=3D"m_class">
-	  <primary>@class</primary>
-	</indexterm>
-	=

-	<refnamediv>
-	  <refname>CCL::@CLASS</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>@class</function> class-name</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>class-name</term>
-
-	      <listitem>
-		<para>a string which denotes an existing class name, or a
-		symbol which can be mapped to such a string via the standard
-		name-mapping conventions for class names</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Used to refer to a known ObjC class by name. (Via the use
-	  LOAD-TIME-VALUE, the results of a class-name -&#62; class lookup
-	  are cached.)</para>
-
-	  <para>
-	    <function>@class</function> 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>
-	</refsect1>
-	</refentry>
-
-	<refentry id=3D"m_selector">
-	  <indexterm zone=3D"m_selector">
-	    <primary>@selector</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>CCL::@SELECTOR</refname>
-	    <refpurpose></refpurpose>
-	    <refclass>Macro</refclass>
-	  </refnamediv>
-
-	  <refsynopsisdiv>
-	    <synopsis><function>@selector</function> string</synopsis>
-	  </refsynopsisdiv>
-
-	  <refsect1>
-	    <title>Arguments and Values</title>
-
-	    <variablelist>
-	      <varlistentry>
-		<term>string</term>
-
-		<listitem>
-		  <para>a string constant, used to canonically refer to an
-		  ObjC method selector</para>
-		</listitem>
-	      </varlistentry>
-	    </variablelist>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <para>Used to refer to an ObjC method selector (method name). Uses
-	    LOAD-TIME-VALUE to cache the result of a string -&#62; selector
-	    lookup.</para>
-	  </refsect1>
-	</refentry>
-
-	<refentry id=3D"m_define-objc-method">
-	  <indexterm zone=3D"m_define-objc-method">
-	    <primary>define-objc-method</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>CCL::DEFINE-OBJC-METHOD</refname>
-	    <refpurpose></refpurpose>
-	    <refclass>Macro</refclass>
-	  </refnamediv>
-
-	  <refsynopsisdiv>
-	    <synopsis><function>define-objc-method</function>
-	    (selector class-name) &body; body</synopsis>
-	  </refsynopsisdiv>
-
-	  <refsect1>
-	    <title>Arguments and Values</title>
-
-	    <variablelist>
-	      <varlistentry>
-		<term>selector</term>
-
-		<listitem>
-		  <para>either a string which represents the name of the
-		  selector or a list which describ+es the method's return
-		  type, selector components, and argument types (see below.)
-		  If the first form is used, then the first form in the body
-		  must be a list which describes the selector's argument
-		  types and return value type, as per DEFCALLBACK.</para>
-		</listitem>
-	      </varlistentry>
-
-	      <varlistentry>
-		<term>class-name</term>
-
-		<listitem>
-		  <para>either a string which names an existing ObjC class
-		  name or a list symbol which can map to such a string via the
-		  standard name-mapping conventions for class names. (Note
-		  that the "canonical" lisp class name is such a
-		  symbol)</para>
-		</listitem>
-	      </varlistentry>
-	    </variablelist>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <para>Defines an ObjC-callable method which implements the
-	    specified message selector for instances of the existing ObjC
-	    class class-name.</para>
-	  </refsect1>
-	</refentry>
-
-	<refentry id=3D"m_define-objc-class-method">
-	  <indexterm zone=3D"m_define-objc-class-method">
-	    <primary>define-objc-class-method</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>CCL::DEFINE-OBJC-CLASS-METHOD</refname>
-	    <refpurpose></refpurpose>
-	    <refclass>Macro</refclass>
-	  </refnamediv>
-
-	  <refsynopsisdiv>
-	    <synopsis><function>define-objc-class-method</function>
-	    (selector class-name) &body; body</synopsis>
-	  </refsynopsisdiv>
-
-	  <refsect1>
-	    <title>Arguments and Values</title>
-
-	    <para>As per DEFINE-OBJC-METHOD</para>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <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>
-
-	    <itemizedlist>
-	      <listitem>
-		<para>a non-keyword symbol, which can be mapped to a selector string
-		for a parameterless method according to the standard name-mapping
-		conventions for method selectors.</para>
-	      </listitem>
-	      =

-	      <listitem>
-		<para>a list of alternating keywords and variable/type specifiers,
-		where the set of keywords can be mapped to a selector string for a
-		parameteriezed method according to the standard name-mapping
-		conventions for method selectors and each variable/type-specifier is
-		either a variable name (denoting a value of type :ID) or a list whose
-		CAR is a variable name and whose CADR is the corresponding
-		argument's foreign type specifier.</para>
-	      </listitem>
-	    </itemizedlist>
-	  </refsect1>
-	</refentry>
-
-	<refentry id=3D"v_alternate-line-terminator">
-	  <indexterm zone=3D"v_alternate-line-terminator">
-	    <primary>*alternate-line-terminator*</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>CCL:*ALTERNATE-LINE-TERMINATOR*</refname>
-	    <refpurpose></refpurpose>
-	    <refclass>Variable</refclass>
-	  </refnamediv>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <para>This variable is currently only used by the standard reader mac=
ro
-	    function for #\; (single-line comments); that function reads successi=
ve
-	    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 LinuxPP=
C,
-	    it&#39;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-terminat=
ed
-	    (Unix) text file contains embedded #\Return characters, and this
-	    mechanism isn&#39;t adequate to handle cases where newlines are embed=
ded
-	    in string constants or other tokens (and presumably should be transla=
ted
-	    from an external convention to the external one) : it doesn&#39;t cha=
nge
-	    what READ-CHAR or READ-LINE &#34;see&#34;, and that may be necessary =
to
-	    handle some more complicated cases.</para>
-	  </refsect1>
-	</refentry>
-
-	<refentry id=3D"k_external-format">
-	  <indexterm zone=3D"k_external-format">
-	    <primary>:external-format</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>:EXTERNAL-FORMAT</refname>
-	    <refpurpose></refpurpose>
-	    <refclass>Keyword Argument</refclass>
-	  </refnamediv>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <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-depend=
ent
-	    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 f=
ile
-	    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 writt=
en
-	    to files verbatim.</para>
-	    =

-	    <para>When specified as :MACOS, all #\Return characters read from the
-	    file are immediately translated to #\Linefeed (#\Newline); all #\Newl=
ine
-	    (#\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&#3=
9;s
-	    external-format is set to :MACOS; otherwise, it is set to :UNIX.</par=
a>
-	    =

-	    <para>All other values of :EXTERNAL-FORMAT - and any combinations that
-	    don&#39;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&#3=
9;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>
-	  </refsect1>
-	</refentry>
-
-	<refentry id=3D"v_default-external-format">
-	  <indexterm zone=3D"v_default-external-format">
-	    <primary>*default-external-format*</primary>
-	  </indexterm>
-	  =

-	  <refnamediv>
-	    <refname>CCL:*DEFAULT-EXTERNAL-FORMAT*</refname>
-	    <refpurpose></refpurpose>
-	    <refclass>Variable</refclass>
-	  </refnamediv>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <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 interpret=
ed
-	    as described above.</para>
-	    =

-	    <para>Because there&#39;s some risk that unsolicited newline translat=
ion
-	    could have undesirable consequences, the initial value of this variab=
le
-	    in OpenMCL is :UNIX.</para>
-	  </refsect1>
-	</refentry>
-
-	<refentry id=3D"c_ns-lisp-string">
-	  <indexterm zone=3D"c_ns-lisp-string">
-	    <primary>ns-lisp-string</primary>
-	  </indexterm>
-
-	  <refnamediv>
-	    <refname>CCL::NS-LISP-STRING</refname>
-	    <refpurpose></refpurpose>
-	    <refclass>Class</refclass>
-	  </refnamediv>
-
-	  <refsect1>
-	    <title>Superclasses</title>
-
-	    <para>NS:NS-STRING</para>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Initargs</title>
-	    =

-	    <variablelist>
-	      <varlistentry>
-		<term>:string</term>
-		=

-		<listitem>
-		  <para>
-		    a Lisp string which is to be the content of
-		    the newly-created ns-lisp-string.
-		  </para>
-		</listitem>
-	      </varlistentry>
-	    </variablelist>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Description</title>
-
-	    <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>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Examples</title>
-
-	    <para>
-	      You can create an ns-lisp-string with
-	      <function>make-instance</function>, just like
-	      any normal Lisp class:
-	    </para>
-
-	    <programlisting format=3D"linespecific"
->? (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 format=3D"linespecific">? (ccl::send *the-string* 'de=
alloc)</programlisting>
-
-	    <para>
-	      You may wish to use an <function>unwind-protect</function>
-	      form to ensure that this happens:
-	    </para>
-
-	    <programlisting format=3D"linespecific"
->(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>
-	  </refsect1>
-
-	  <refsect1>
-	    <title>Notes</title>
-
-	    <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>
-	  </refsect1>
-	</refentry>
-    </sect1>
-  </chapter>
-
-  <chapter id=3D"Understanding-and-Configuring-the-Garbage-Collector">
-    <title>Understanding and Configuring the Garbage Collector</title>
-
-    <sect1 id=3D"Heap-space-allocation">
-      <title>Heap space allocation</title>
-      <para>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=3D"The-Ephemeral-GC">
-      <title>The Ephemeral GC</title>
-      <para>For many programs, the following observations are true to
-      a very large degree:</para>
-
-      <orderedlist continuation=3D"restarts" inheritnum=3D"ignore">
-	<listitem>
-	  <para>Most heap-allocated objects have very short lifetimes ("are
-	  ephemeral"): they become inaccessible soon after they&#39;re created.</=
para>
-	</listitem>
-
-	<listitem>
-	  <para>Most non-ephemeral objects have very long lifetimes: it&#39;s
-	  rarely productive for the GC to consider reclaiming them, since
-	  it&#39;s rarely able to do so. (An object that&#39;s survived a large
-	  number of GCs is likely to survive the next one. That&#39;s not always
-	  true of course, but it&#39;s a reasonable heuristic.)</para>
-	</listitem>
-
-	<listitem>
-	  <para>It&#39;s relatively rare for an old object to be destructively
-	  modified (via SETF) so that it points to a new one, therefore most
-	  references to newly-created objects can be found in the stacks and
-	  registers of active threads. It&#39;s not generally necessary to scan
-	  the entire heap to find references to new objects (or to prove that
-	  such references don&#39;t exists), though it is necessary to keep
-	  track of the (hopefully exceptional) cases where old objects are
-	  modified to point at new ones.</para>
-	</listitem>
-      </orderedlist>
-      <orderedlist continuation=3D"restarts" inheritnum=3D"ignore">
-	<listitem>
-	  <para>Most heap-allocated objects have very short lifetimes ("are
-	  ephemeral"): they become inaccessible soon after they&#39;re created.</=
para>
-	</listitem>
-
-	<listitem>
-	  <para>Most non-ephemeral objects have very long lifetimes: it&#39;s
-	  rarely productive for the GC to consider reclaiming them, since
-	  it&#39;s rarely able to do so. (An object that&#39;s survived a large
-	  number of GCs is likely to survive the next one. That&#39;s not always
-	  true of course, but it&#39;s a reasonable heuristic.)</para>
-	</listitem>
-
-	<listitem>
-	  <para>It&#39;s relatively rare for an old object to be destructively
-	  modified (via SETF) so that it points to a new one, therefore most
-	  references to newly-created objects can be found in the stacks and
-	  registers of active threads. It&#39;s not generally necessary to scan
-	  the entire heap to find references to new objects (or to prove that
-	  such references don&#39;t exists), though it is necessary to keep
-	  track of the (hopefully exceptional) cases where old objects are
-	  modified to point at new ones.</para>
-	</listitem>
-      </orderedlist>
-
-      <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=3D"GC-Page-reclamation-policy">
-      <title>GC Page reclamation policy</title>
-      <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=3D"iPure--areas-are-read-only--paged-from-image-file">
-      <title>"Pure" areas are read-only, paged from image file</title>
-      <para>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=3D"Weak-Hash-Tables">
-      <title>Weak Hash Tables</title>
-      <para>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=3D"Garbage-Collection-Dictionary">
-      <title>Garbage-Collection Dictionary</title>
-
-      <refentry id=3D"f_lisp-heap-gc-threshold">
-	<indexterm zone=3D"f_lisp-heap-gc-threshold">
-	  <primary>lisp-heap-gc-threshold</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>LISP-HEAP-GC-THRESHOLD</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>lisp-heap-gc-threshold</function></synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns the value of the kernel variable that specifies the
-	  amount of free space to leave in the heap after full GC.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_set-lisp-heap-gc-threshold">
-	<indexterm zone=3D"f_set-lisp-heap-gc-threshold">
-	  <primary>set-lisp-heap-gc-threshold</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>SET-LISP-HEAP-GC-THRESHOLD</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>lisp-heap-gc-threshold new-threshold</function>
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>new-value</term>
-
-	      <listitem>
-		<para>The requested new lisp-heap-gc-threshold.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_use-lisp-heap-gc-threshold">
-	<indexterm zone=3D"f_use-lisp-heap-gc-threshold">
-	  <primary>use-lisp-heap-gc-threshold</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>USE-LISP-HEAP-GC-THRESHOLD</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis>
-	    <function>use-lisp-heap-gc-threshold</function>
-	  </synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Tries to grow or shrink lisp&#39;s heap space, so that the
-	  free space is (approximately) equal to the current heap threshold.
-	  Returns NIL</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_egc">
-	<indexterm zone=3D"f_egc">
-	  <primary>egc</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>EGC</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>egc</function> arg</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>arg</term>
-
-	      <listitem>
-		<para>a generalized boolean</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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&#39;t make a whole lot of sense to be
-	  turning the EGC on and off from multiple threads ...</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_egc-enabled-p">
-	<indexterm zone=3D"f_egc-enabled-p">
-	  <primary>egc-enabled-p</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>EGC-ENABLED-P</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>egc-enabled-p</function></synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns T if the EGC was enabled at the time of the call,
-	  NIL otherwise.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_egc-active-p">
-	<indexterm zone=3D"f_egc-active-p">
-	  <primary>egc-active-p</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>EGC-ACTIVE-P</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>egc-active-p</function></synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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&#39;s not clear whether this function serves a
-	  useful purpose when native threads are involved.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_egc-configuration">
-	<indexterm zone=3D"f_egc-configuration">
-	  <primary>egc-configuration</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>EGC-CONFIGURATION</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>egc-configuration</function></synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_configure-gcc">
-	<indexterm zone=3D"f_configure-gcc">
-	  <primary>configure-gcc</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>CONFIGURE-GCC</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>configure-egc</function>
-	  generation-0-size generation-1-size
-	  generation-2-size</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>generation-0-size</term>
-
-	      <listitem>
-		<para>the requested threshold size of the youngest
-		generation, in kilobytes</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>generation-1-size</term>
-
-	      <listitem>
-		<para>the requested threshold size of the middle generation,
-		in kilobytes</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>generation-2-size</term>
-
-	      <listitem>
-		<para>the requested threshold size of the oldest generation,
-		in kilobytes</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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 to a multiple of 32KBytes in earlier
-	  versions.)</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_gc-retain-pages">
-	<indexterm zone=3D"f_gc-retain-pages">
-	  <primary>gc-retain-pages</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>GC-RETAIN-PAGES</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>gc-retain-pages</function> arg</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>arg</term>
-
-	      <listitem>
-		<para>a generalized boolean</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_gc-retaining-pages">
-	<indexterm zone=3D"f_gc-retaining-pages">
-	  <primary>gc-retaining-pages</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>GC-RETAINING-PAGES</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>gc-retaining-pages</function></synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns T if the GC tries to retain pages between full GCs
-	  and NIL if it&#39;s trying to release them to improve VM paging
-	  performance.</para>
-	</refsect1>
-      </refentry>
-    </sect1>
-  </chapter>
-
-  <chapter id=3D"Implementation-Details-of-OpenMCL">
-    <title>Implementation Details of OpenMCL</title>
-    <para>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=3D"Threads-and-exceptions">
-      <title>Threads and exceptions</title>
-      <para>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=3D"The-Thread-Context-Record">
-	<title>The Thread Context Record</title>
-
-	<para>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=3D"Exception-contexts-comma---and-exception-handling-in-ge=
neral">
-	<title>Exception contexts, and exception-handling in general</title>
-        <para>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 i=
n 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=3D"Threads-comma---exceptions-comma---and-the-GC">
-	<title>Threads, exceptions, and the GC</title>
-        <para>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=3D"PC-lusering">
-	<title>PC-lusering</title>
-        <para>It'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>
-
-	<itemizedlist>
-          <listitem>
-<para>On both PPC and x86-64 platforms, consing isn't fully atomic.It take=
s at least a few instructions to allocate an object in memory(and slap a he=
ader 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 ful=
ly initialized at the point in time that theinterrupt occurred.  (There are=
 actually a few different states ofpartial initialization)</para>
-</listitem>
-          <listitem>
-<para>On the PPC, the common act of building a lisp control stack frameinv=
olves allocating a four-word frame and storing three register valuesinto th=
at frame.  (The fourth word - the back pointer to the previousframe - is au=
tomatically set when the frame is allocated.)  The previouscontents of thos=
e three words are unknown (there might have been aforeign stack frame at th=
e 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.</par=
a>
-</listitem>
-          <listitem>
-<para>There are similar problems with the initialization of temp stackfram=
es on the PPC.  (Allocation and initialization doesn't happenatomically, an=
d the newly allocated stack memory may have undefinedcontents.)</para>
-</listitem>
-          <listitem>
-<para>'s write barrier has to be implemented atomically (i.e.,both an inte=
rgenerational store and the update of a correspondingreference bit has to h=
appen without interruption, or neither of theseevents can happen.)</para>
-</listitem>
-          <listitem>
-<para>There are a few more similar cases.</para>
-</listitem>
-        =

-        </itemizedlist>
-
-        <para>Fortunately, the number of these non-atomic instruction sequ=
ences 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 s=
equences
-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=3D"Register-usage-and-tagging">
-      <title>Register usage and tagging</title>
-
-      <sect2 id=3D"Register-usage-and-tagging-overview">
-	<title>Overview</title>
-	<para>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=3D"pc-locatives-on-the-PPC">
-	<title>pc-locatives on the PPC</title>
-        <para>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 in1struction 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=3D"Register-and-stack-usage-conventions">
-        <title>Register and stack usage conventions</title>
-
-        <sect3 id=3D"Stack-conventions">
-	  <title>Stack conventions</title>
-          <para>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>
-	  <itemizedlist>
-            <listitem>
-	      <para>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."</para>
-	    </listitem>
-            <listitem>
-	      <para>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.</para>
-	    </listitem>
-	    <listitem>
-	      <para>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.</para>
-	    </listitem>
-          </itemizedlist>
-        </sect3>
-
-        <sect3 id=3D"Register-conventions">
-	  <title>Register conventions</title>
-          <para>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 involve=
s:</para>
-	  <itemizedlist>
-            <listitem>
-	      <para>(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.</para>
-	    </listitem>
-            <listitem>
-	      <para>(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.)</para>
-	    </listitem>
-            <listitem>
-	      <para>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.)</para>
-</listitem>
-	  </itemizedlist>
-          <para>On the PPC, the static register partitioning scheme involv=
es:</para>
-
-	  <itemizedlist>
-            <listitem>
-	      <para>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.)</para>
-	    </listitem>
-	    <listitem>
-	      <para>9 dedicated registers
-	      <itemizedlist>
-		<listitem>
-		  <para>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.</para>
-		</listitem>
-		<listitem>
-		  <para>r1 (symbolic name sp) is the control stack
-		  pointer, by PPC convention.</para>
-		</listitem>
-                <listitem>
-		  <para>r2 is used to hold the current thread's TCR on
-		  ppc64 systems; it'snot used on ppc32.</para>
-		</listitem>
-                <listitem>
-		  <para>r9 and r10 (symbolic names allocptr and
-		  allocbase) are used to do per-thread memory
-		  allocation</para>
-		</listitem>
-                <listitem>
-		  <para>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.</para>
-		</listitem>
-                <listitem>
-		  <para>r12 (symbolic name tsp) holds the top of the current thread's te=
mp stack.</para>
-		</listitem>
-		<listitem>
-		  <para>r13 is used to hold the TCR on PPC32 sytems; it's not used on PP=
C64.</para>
-		</listitem>
-		<listitem>
-		  <para>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.</para>
-		</listitem>
-                <listitem>
-		  <para>r15 (symbolic name vsp) addresses the top of
-		  the current thread's value stack.</para>
-		</listitem>
-		<listitem>
-		  <para>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.</para>
-		</listitem>
-              =

-	      </itemizedlist>
-	      </para>
-	    </listitem>
-            <listitem>
-	      <para>17 "node" registersr15-r31 are always treated as
-	      node registers</para>
-	    </listitem>
-	    =

-          </itemizedlist>
-        </sect3>
-      </sect2>
-
-      <sect2 id=3D"Tagging-scheme">
-	<title>Tagging scheme</title>
-        <para>OpenMCL 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 =3D 3 for 32-bit
-	OpenMCL and N =3D 4 for 64-bit OpenMCL), this way of
-	representing fixnums with the low M bits forced to 0 works as
-	long as M &lt;=3D 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 =3D 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>
-
-	<itemizedlist>
-	  <listitem>
-	    <para>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 CAR and CDR in memory were chosen to allow
-	    smaller, cheaper addressing modes to 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 in memory.  It doesn't matter, but doing it the way
-	    that the host system did made boostrapping to a new target
-	    system a little easier.)
-	    </para>
-	  </listitem>
-	  <listitem>
-	    <para>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
-	    truth value and probably a few other things.)  Its role as
-	    a LIST is probably much 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 LISTP implicitly 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
-	    straddles two doublenodes; the tag of NIL is unique and
-	    congruent modulo 4 (modulo 8 on 64-bit) with the tag used
-	    for CONS cells.  LISTP is therefore true of any node whose
-	    low 2 (or 3) bits contain the appropriate tag value (it's
-	    not otherwise necessary to special-case NIL.)
-	    SYMBOL accessors (SYMBOL-NAME, SYMBOL-VALUE, SYMBOL-PLIST
-	    ..) -do- have to special-case NIL (and access the
-	    components of an internal proxy symbol.) On PPC64 (where
-	    architectural restrictions dictate the set of tags that can
-	    be used to access fixed components of an object),
-	    that approach wasn't practical.  NIL is just a
-	    distinguished SYMBOL,and it just happens to be the case
-	    that its pname slot and values lots are at the same offsets
-	    from a tagged pointer as a CONS cell's CDR and CAR would be.
-	    NIL's pname is set to NIL (SYMBOL-NAME checks for this and
-	    returns the string "NIL"), and LISTP (and therefore 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 has multiple
-	    condition-code fields keeps that extra test from
-	    being prohibitively expensive.</para>
-	  </listitem>
-	  <listitem>
-	    <para>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.</para>
-	  </listitem>
-          <listitem>
-	    <para>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 the treatment of "memory-allocated
-	    non-CONS objects" isn't entirely uniformaccross all
-	    OpenMCL implementations.  Let's first pretend that
-	    the treatment 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.)</para>
-	  </listitem>
-        =

-	</itemizedlist>
-      </sect2>
-    </sect1>
-
-    <sect1 id=3D"Heap-Allocation">
-      <title>Heap Allocation</title> <para>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 --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 (result from 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=3D"Per-thread-object-allocation">
-	<title>Per-thread object allocation</title>
-        <para>Each 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>
-	<orderedlist>
-	  <listitem>
-	    <para>decrementing the "high" pointer by (- X Y)</para>
-	  </listitem>
-	  <listitem>
-	    <para>trapping if the high pointer is less than the low
-	    pointer</para>
-	  </listitem>
-	  <listitem>
-	    <para>using the (tagged) high pointer to initialize the
-	    object, if necessary</para>
-	  </listitem>
-	  <listitem>
-	    <para>clearing the low bits of the high pointer</para>
-	  </listitem>
-	</orderedlist>
-        <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 ba=
se
-  (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=3D"Allocation-of-reserved-heap-segments">
-	<title>Allocation of reserved heap segments</title>
-        <para>After 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=3D"Heap-growth">
-	<title>Heap growth</title>
-        <para>All 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 fai=
lure 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=3D"GC-details">
-      <title>GC details</title>
-      <para>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 ar=
e</para>
-      <orderedlist>
-	<listitem>
-	  <para>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.)</para>
-	</listitem>
-	<listitem>
-	  <para>the relocation table, which contains a native word for
-	  every 32 or 64 doublenodes in the dynamic heap, plus an
-	  extra word used to keep trackof the end of the heap.</para>
-	</listitem>
-      </orderedlist>
-      <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=3D"Mark-phase">
-	<title>Mark phase</title>
-        <para>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>
-	<orderedlist>
-	  <listitem>
-	    <para>If the object is already marked, do nothing.</para>
-	  </listitem>
-	  <listitem>
-	    <para>Set the object's markbit(s).</para>
-	  </listitem>
-	  <listitem>
-	    <para>If the object is an ivector, do nothing further.</para>
-	  </listitem>
-	  <listitem>
-	    <para>If the object is a cons cell, recursively mark its
-	    car and cdr.</para>
-	  </listitem>
-	  <listitem>
-	    <para>Otherwise, the object is a gvector. Recursively mark
-	    itselements.</para>
-	  </listitem>
-	</orderedlist>
-        <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:</pa=
ra>
-	<orderedlist>
-	<listitem>
-	  <para>To support a feature called <emphasis>GCTWA
-              <footnote>
-		<para>I believe that theacronym comes from MACLISP,
-		where it stood for "Garbage Collection ofTruly
-		Worthless Atoms".</para>
-              </footnote>
-	      , </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.)</para>
-	</listitem>
-	<listitem>
-	  <para>Pools have their first element set to NIL before any
-	  otherelements are marked.</para>
-	</listitem>
-	<listitem>
-	  <para>All hash tables have certain fields (used to cache
-	  previous results) invalidated.</para>
-	</listitem>
-	<listitem>
-	  <para>Weak Hash Tables and other weak objects are put on a
-	  linkedlist as they're encountered; their contents are only
-	  retained if there are other (non-weak) references to
-	  them.</para>
-	</listitem>
-	</orderedlist>
-        <para>At the end of the mark phase, the markbits of all objects wh=
ich
-	are transitively reachable from the roots are set and all other markbits
-	are clear.</para>
-      </sect2>
-
-      <sect2 id=3D"Relocation-phase">
-	<title>Relocation phase</title>
-	<para>The <emphasis>forwarding address</emphasis> of a
-	doublenode in the dynamic heap is (&lt;its current address> -
-	(size_of_doublenode * &lt;the number of unmarked markbits that
-	precede it>)) or alternately (&lt;the base of the heap> +
-	(size_of_doublenode * &lt;the number of marked markbits that
-	preced it &gt;)). 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=3D"Forwarding-phase">
-	<title>Forwarding phase</title>
-        <para>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=3D"Compact-phase">
-	<title>Compact phase</title>
-        <para>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=3D"The-ephemeral-GC">
-      <title>The ephemeral GC</title>
-      <para>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>
-      <itemizedlist>
-	<listitem>
-	  <para>most newly created objects become garbage soon after
-	  they'recreated.</para>
-	</listitem>
-	<listitem>
-	  <para>most objects that have already survived several GCs
-	  are unlikely to ever become garbage.</para>
-	</listitem>
-	<listitem>
-	  <para>old objects can only point to newer objects as the
-	  result of adestructive modification (e.g., via
-	  SETF.)</para>
-	</listitem>
-      </itemizedlist>
-
-      <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).<footnote><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></footnote> 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>
-      <itemizedlist>
-        <listitem>
-	  <para>the "base of the heap" used to determine anobject's
-	  markbit address is the base of the generation
-	  being collected;</para>
-	</listitem>
-        <listitem>
-	  <para>the markbits vector is actually a pointer into the
-	  middle of the global markbits table; preceding entries in
-	  this table are used to note doubleword addresses in older
-	  generations that (may) contain intergenerational
-	  references;</para>
-	</listitem>
-        <listitem>
-	  <para>some steps (notably GCTWA and the handling of weak
-	  objects) are not performed;</para>
-	</listitem>
-        <listitem>
-	  <para>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.</para>
-	</listitem>
-      =

-      </itemizedlist>
-      <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=3D"Fasl-files">
-      <title>Fasl files</title>
-      <para>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=3D"The-Objective-C-Bridge--1-">
-      <title>The Objective-C Bridge</title>
-
-      <sect2 id=3D"How-OpenMCL-Recognizes-Objective-C-Objects">
-	<title>How OpenMCL Recognizes Objective-C Objects</title>
-        <para>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>
-	<title>Recommended Reading</title>
-
-	<variablelist>
-	  <varlistentry>
-	    <term>
-	      <ulink url=3D"http://developer.apple.com/documentation/Cocoa/">Coco=
a Documentation</ulink>
-	    </term>
-	    =

-	   <listitem>
-	     <para>
-	       This is the top page for all of Apple's documentation on
-	       Cocoa.  If you are unfamiliar with Cocoa, it is a good
-	       place to start.
-	     </para>
-	   </listitem>
-	</varlistentry>
-	<varlistentry>
-	  <term>
-	    <ulink url=3D"http://developer.apple.com/documentation/Cocoa/Referenc=
e/Foundation/ObjC_classic/index.html">Foundation Reference for Objective-C<=
/ulink>
-	  </term>
-
-	  <listitem>
-	    <para>
-	      This is one of the two most important Cocoa references; it
-	      covers all of the basics, except for GUI programming.  This is
-	      a reference, not a tutorial.
-	    </para>
-	  </listitem>
-	</varlistentry>
-      </variablelist>
-      </sect2>
-    </sect1>
-  </chapter>
-
-
-  <chapter id=3D"Modifying-OpenMCL">
-    <title>Modifying OpenMCL</title>
-
-    <sect1 id=3D"Contributing-Code-Back-to-the-OpenMCL-Project">
-      <title>Contributing Code Back to the OpenMCL Project</title>
-      <para>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=3D"Using-OpenMCL-in--development--and-in--user--mode">
-      <title>Using OpenMCL in "development" and in  "user" mode</title>
-
-      <para>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=3D"Debugging-facilities-in-the-lisp-kernel">
-      <title>Debugging facilities in the lisp kernel</title>
-      <para> 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 &lt;enter&gt;?
-</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 ((&gt; n 0) "Greater")
-           ((&lt; 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 ((&gt; n 0) "Greater")
-        ((&lt; n 0) "Less")
-        (t (dbg n))))
-CLASSIFY2
-
-? (classify2 0)
-Lisp Breakpoint
- While executing: #&lt;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 reg=
ister
-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 =3D 0x01836015
-nargs =3D 0
-r16 (fn) =3D #&lt;Function CLASSIFY2 #x30379386>
-r23 (arg_z) =3D 0
-r22 (arg_y) =3D 0
-r21 (arg_x) =3D 0
-r20 (temp0) =3D #&lt;26-element vector subtag =3D 2F @#x303793ee>
-r19 (temp1/next_method_context) =3D 6393788
-r18 (temp2/nfn) =3D #&lt;Function CLASSIFY2 #x30379386>
-r17 (temp3/fname) =3D CLASSIFY2
-r31 (save0) =3D 0
-r30 (save1) =3D *TERMINAL-IO*
-r29 (save2) =3D 0
-r28 (save3) =3D (#&lt;RESTART @#x01867f2e> #&lt;RESTART @#x01867f56>)
-r27 (save4) =3D ()
-r26 (save5) =3D ()
-r25 (save6) =3D ()
-r24 (save7) =3D ()
-</programlisting>
-      <para>From this we can conclude that the problematic argument to CLA=
SSIFY2
-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.</par=
a>
-      <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=3D"Using-AltiVec-in-OpenMCL-LAP-functions">
-      <title>Using AltiVec in OpenMCL LAP functions</title>
-
-      <sect2 id=3D"Overview--16-">
-	<title>Overview</title>
-        <para>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=3D"Register-usage-conventions">
-	<title>Register usage conventions</title>
-        <para>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 us=
ed
-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-PROT=
ECT.
-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 wh=
ich 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=3D"Development-Mode-Dictionary">
-      <title>Development-Mode Dictionary</title>
-
-      <refentry id=3D"v_warn-if-redefine-kernel">
-	<indexterm zone=3D"v_warn-if-redefine-kernel">
-	  <primary>*warn-if-redefine-kernel</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>*WARN-IF-REDEFINE-KERNEL*</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Variable</refclass>
-	</refnamediv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>When true, attempts to redefine (via DEFUN or DEFMETHOD)
-	  functions and methods that are marked as being
-	  &#34;predefined&#34; 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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_set-development-environment">
-	<indexterm zone=3D"f_set-development-environment">
-	  <primary>set-development-environment</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>SET-DEVELOPMENT-ENVIRONMENT</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>set-development-environment</function>
-	  &optional;
-	  unmark-builtin-functions</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Arranges that the outermost special bindings of *PACKAGE*
-	  and *WARN-IF-REDEFINE-KERNEL* restore values of the &#34;CCL&#34;
-	  package and NIL to these variables, respectively. If the optional
-	  argument is true, marks all globally defined functions and methods
-	  as being &#34;not predefined&#34; (this is a fairly expensive
-	  operation.)</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_set-user-environment">
-	<indexterm zone=3D"f_set-user-environment">
-	  <primary>set-user-environment</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>SET-USER-ENVIRONMENT</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>set-user-environment</function>
-	  &optional; mark-builtin-functions</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Arranges that the outermost special bindings of *PACKAGE*
-	  and *WARN-IF-REDEFINE-KERNEL* restore values of the
-	  &#34;CL-USER&#34; package and T to these variables, respectively.
-	  If the optional argument is true, marks all globally defined
-	  functions and methods as being &#34;predefined&#34; (this is a
-	  fairly expensive operation.)</para>
-	</refsect1>
-      </refentry>
-      <refentry id=3D"v_altivec-available">
-	<indexterm zone=3D"v_altivec-available">
-	  <primary>*altivec-available*</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>*ALTIVEC-AVAILABLE*</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Variable</refclass>
-	</refnamediv>
-
-	<refsect1>
-	  <title>Description</title>
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"f_altivec-available-p">
-	<indexterm zone=3D"f_altivec-available-p">
-	  <primary>altivec-available-p</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>ALTIVEC-AVAILABLE-P</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Function</refclass>
-	</refnamediv>
-	=

-	<refsynopsisdiv>
-	  <synopsis><function>altivec-available-p</function></synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <para>Returns non-NIL if AltiVec is available.</para>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"v_altivec-lapmacros-maintain-vrsave-p">
-	<indexterm zone=3D"v_altivec-lapmacros-maintain-vrsave-p">
-	  <primary>*altivec-lapmacros-maintain-vrsave-p*</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>*ALTIVEC-LAPMACROS-MAINTAIN-VRSAVE-P*</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>Variable</refclass>
-	</refnamediv>
-	=

-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"lapm_with-altivec-registers">
-	<indexterm zone=3D"lapm_with-altivec-registers">
-	  <primary>with-altivec-registers</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>WITH-ALTIVEC-REGISTERS</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>LAP Macro</refclass>
-	</refnamediv>
-
-	<refsynopsisdiv>
-	  <synopsis><function>with-altivec-registers</function>
-	  reglist &body; body</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>reglist</term>
-
-	      <listitem>
-		<para>A list of vector register names (vr0 .. vr31).</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>body</term>
-
-	      <listitem>
-		<para>A sequence of PPC LAP instructions.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-
-	  <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>
-	</refsect1>
-      </refentry>
-
-      <refentry id=3D"lapm_with-vector-buffer">
-	<indexterm zone=3D"lapm_with-vector-buffer">
-	  <primary>with-vector-buffer</primary>
-	</indexterm>
-
-	<refnamediv>
-	  <refname>WITH-VECTOR-BUFFER</refname>
-	  <refpurpose></refpurpose>
-	  <refclass>LAP Macro</refclass>
-	</refnamediv>
-	=

-	<refsynopsisdiv>
-	  <synopsis>with-vector-buffer base n &body; body</synopsis>
-	</refsynopsisdiv>
-
-	<refsect1>
-	  <title>Arguments and Values</title>
-
-	  <variablelist>
-	    <varlistentry>
-	      <term>base</term>
-
-	      <listitem>
-		<para>Any available general-purpose register.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>n</term>
-
-	      <listitem>
-		<para>An integer between 1 and 254, inclusive. (Should
-		typically be much, much closer to 1.) Specifies the size of
-		the buffer, in 16-byte units.</para>
-	      </listitem>
-	    </varlistentry>
-
-	    <varlistentry>
-	      <term>body</term>
-
-	      <listitem>
-		<para>A sequence of PPC LAP instructions.</para>
-	      </listitem>
-	    </varlistentry>
-	  </variablelist>
-	</refsect1>
-
-	<refsect1>
-	  <title>Description</title>
-	  <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>
-	</refsect1>
-      </refentry>
-    </sect1>
-  </chapter>
-  <index id=3D"Symbol-Index"><title>Symbol Index</title></index>
-</book>



More information about the Openmcl-cvs-notifications mailing list