[Openmcl-cvs-notifications] r8520 - /trunk/source/doc/src/openmcl-documentation.xml
gb at clozure.com
gb at clozure.com
Wed Feb 20 09:18:19 EST 2008
Author: gb
Date: Wed Feb 20 09:18:19 2008
New Revision: 8520
Log:
valid XML. Buggy, incomplete, valid XML
Modified:
trunk/source/doc/src/openmcl-documentation.xml
Modified: 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 Wed Feb 20 09:18:19 2008
@@ -1,12 +1,11 @@
<?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><property>&rest</property></varname>">
-<!ENTITY key "<varname><property>&key</property></varname>">
-<!ENTITY optional "<varname><property>&optional</property></varname>">
-<!ENTITY body "<varname><property>&body</property></varname>">
-<!ENTITY aux "<varname><property>&aux</property></varname>">
-<!ENTITY allow-other-keys
- "<varname><property>&allow-other-keys</property></varname>">
+<!ENTITY rest "<varname>&rest</varname>">
+<!ENTITY key "<varname>&key</varname>">
+<!ENTITY optional "<varname>&optional</varname>">
+<!ENTITY body "<varname>&body</varname>">
+<!ENTITY aux "<varname>&aux</varname>">
+<!ENTITY allow-other-keys "<varname>&allow-other-keys</varname>">
]>
<book lang=3D"en">
<bookinfo>
@@ -1073,10 +1072,10 @@
argument</para>
<programlisting>
$ cd ccl # wherever your ccl directory is
-$ ./<replaceable><kernel> <boot_image></replaceable>
+$ ./KERNEL BOOT_IMAGE
</programlisting>
- <para>Where <replaceable><kernel></replaceable> and
- <replaceable><boot_image></replaceable> are the names of
+ <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
@@ -1291,7 +1290,7 @@
code written to run under OpenMCL's interface to the native
scheduler may be less portable to other CL implementations, many
of which offer a cooperative scheduler and an API similar to
- OpenMCL (< 0.14) 's.) At the same time, there's a large
+ OpenMCL (< 0.14) 's.) At the same time, there's a large
overlap in functionality in the two scheduling models, and it'll
hopefully be possible to write interesting and useful MP code
that's largely independent of the underlying scheduling
@@ -1475,7 +1474,7 @@
?
=
? (process-run-function "sleeper" #'(lambda () (sleep 5) (break "broken")))
-#<PROCESS sleeper(1) [Enabled] #x3063B33E>
+#<PROCESS sleeper(1) [Enabled] #x3063B33E>
=
?
;;
@@ -1494,11 +1493,11 @@
;; process sleeper(1) now controls terminal input
;;
> Break in process sleeper(1): broken
-> While executing: #<Anonymous Function #x3063B276>
+> While executing: #<Anonymous Function #x3063B276>
> Type :GO to continue, :POP to abort.
> If continued: Return from BREAK.
Type :? for other options.
-1 > :b
+1 > :b
(30C38E30) : 0 "Anonymous Function #x3063B276" 52
(30C38E40) : 1 "Anonymous Function #x304984A6" 376
(30C38E90) : 2 "RUN-PROCESS-INITIAL-FORM" 340
@@ -1522,10 +1521,10 @@
?
=
? (process-run-function "sleep-60" #'(lambda () (sleep 60) (break "Huh?")))
-#<PROCESS sleep-60(1) [Enabled] #x3063BF26>
+#<PROCESS sleep-60(1) [Enabled] #x3063BF26>
=
? (process-run-function "sleep-5" #'(lambda () (sleep 5) (break "quicker")=
))
-#<PROCESS sleep-5(2) [Enabled] #x3063D0A6>
+#<PROCESS sleep-5(2) [Enabled] #x3063D0A6>
=
? ;;
;; Process sleep-5(2) needs access to terminal input.
@@ -1601,7 +1600,8 @@
</sect1>
=
<sect1 id=3D"The-Threads-which-OpenMCL-Uses-for-Its-Own-Purposes">
- <para>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
@@ -1722,7 +1722,6 @@
=
<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>
@@ -1758,11 +1757,11 @@
<title>Description</title>
=
<para>Returns a list of all lisp processes (threads) known
- to OpenMCL as of the precise instant it's
- called. It's safe to traverse this list and to modify
- the cons cells that comprise that list (it's freshly
- consed.) Since other threads can create and kill threads at
- any time, there's generally no way to get an
+ to OpenMCL as of
+ the precise instant it's called. It's safe to traverse
+ this list and to modify the cons cells that comprise that list
+ (it's freshly consed.) Since other threads can create and kill
+ threads at any time, there's generally no way to get an
"accurate" list of all threads, and (generally) no
sense in which such a list can be accurate.</para>
</refsect1>
@@ -1776,8 +1775,7 @@
</refsect1>
</refentry>
=
-
- <refentry id=3D"f_make-process">
+ <refentry id=3D"f_make-process">
<indexterm zone=3D"f_make-process">
<primary>make-process</primary>
</indexterm>
@@ -1944,1187 +1942,2444 @@
</refsect1>
</refentry>
=
- <sect2 id=3D"PROCESS-SUSPEND">
- <para>PROCESS-SUSPEND</para>
- <informalfigure>process-suspend</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-SUSPEND — Suspends a specified process.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-suspend process
- =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>process
- <variablelist>a lisp process (thread).</variablelist>
- </indexterm><indexterm>result
- <variablelist>T if <literal>process</literal> had been runnabl=
eand is now suspended; NIL otherwise. That is, T if<literal>process</liter=
al>'stransitioned from 0 to 1.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Suspends <literal>process</literal>, preventing it from
-running, and stopping it if it was already running. This is a fairly
-expensive operation, because it involves a few
-calls to the OS. It also risks creating deadlock if used
-improperly, for instance, if the process being suspended owns a
-lock or other resource which another process will wait for.</para>
- <para>Each
-call to <literal>process-suspend</literal> must be reversed by
-a matching call to =
-before <literal>process</literal> is able to run. What
-<literal>process-suspend</literal> actually does is increment
-the of
-<literal>process</literal>.</para>
- <para>A process cannot suspend itself (although that was possible =
in
-some older OpenMCL releases and this documentation claimed that
-it still was.)</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">,</para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para><literal>process-suspend</literal> was previously called
-<literal>process-disable</literal>.</para>
- <para>now names a function for which there is no
-obvious inverse, so <literal>process-disable</literal>
-is no longer
-defined.</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-RESUME">
- <para>PROCESS-RESUME</para>
- <informalfigure>process-resume</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-RESUME — Resumes a specified process which had=
previously
-been suspended by process-suspend.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-resume process
- =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>process
- <variablelist>a lisp process (thread).</variablelist>
- </indexterm><indexterm>result
- <variablelist>T if <literal>process</literal> had been suspend=
edand is now runnable; NIL otherwise. That is, T if<literal>process</liter=
al>'stransitioned from to 0.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Undoes the effect of a previous call to
-; if
-all such calls are undone, makes the process runnable. Has no
-effect if the process is not suspended. What
-<literal>process-resume</literal> actually does is decrement
-the of
-<literal>process</literal>, to a minimum of 0.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">,</para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para>This was previously called PROCESS-ENABLE;
- now does something slightly
-different.</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-SUSPEND-COUNT">
- <para>PROCESS-SUSPEND-COUNT</para>
- <informalfigure>process-suspend-count</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-SUSPEND-COUNT — Returns the number of currentl=
y-pending suspensions
-applicable to a given process.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- process-suspend-count
+ <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'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
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>process
- <variablelist>a lisp process (thread).</variablelist>
- </indexterm><indexterm>result
- <variablelist>The number of "outstanding" calls on<literal>pro=
cess</literal>, or NIL if<literal>process</literal> has expired.</variablel=
ist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>An "outstanding" call
-is one which has not yet been reversed by a call to
-. A process expires when
-its initial function returns, although it may later be
-reset.</para>
- <para>A process is <emphasis>runnable</emphasis> when it has a
-<literal>process-suspend-count</literal> of 0, has been
-preset as by , and has been
-enabled as by . Newly-created
-processes have a <literal>process-suspend-count</literal> of
-0.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">,</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-PRESET">
- <para>PROCESS-PRESET</para>
- <informalfigure>process-preset</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-PRESET — Sets the initial function and argumen=
ts of a specified
-process.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-preset
- process function &rest args
- =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>process
- <variablelist>a lisp process (thread).</variablelist>
- </indexterm><indexterm>function
- <variablelist>a function, designated by itself or by a symbolw=
hich names it.</variablelist>
- </indexterm><indexterm>args
- <variablelist>a list of values, appropriate as arguments to<li=
teral>function</literal>.</variablelist>
- </indexterm><indexterm>result
- <variablelist>undefined.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Typically used to initialize a newly-created or newly-reset
-process, setting things up so that when <literal>process</literal>
-becomes enabled, it will begin execution by
-applying <literal>function</literal> to <literal>args</literal>.
-<literal>process-preset</literal> does not enable
-<literal>process</literal>,
-although a process must be <literal>process-preset</literal>
-before it can be enabled. Processes are normally enabled by
-.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, ,</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-ENABLE">
- <para>PROCESS-ENABLE</para>
- <informalfigure>process-enable</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-ENABLE — Begins executing the initial function=
of a specified
-process.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-enable
- process &optional timeout
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>process
- <variablelist>a lisp process (thread).</variablelist>
- </indexterm><indexterm>timeout
- <variablelist>a time interval in seconds. May be anynon-negat=
ive real number the <literal>floor</literal> ofwhich fits in 32 bits. The =
default is 1.</variablelist>
- </indexterm><indexterm>result
- <variablelist>undefined.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Tries to begin the execution of <literal>process</literal>.
-An error is signaled if <literal>process</literal> has never
-been . Otherwise,
-<literal>process</literal> invokes its initial function.</para>
- <para><literal>process-enable</literal> attempts to
-synchronize with <literal>process</literal>, which is presumed
-to be reset or in the act of resetting itself. If this attempt
-is not successful within the time interval specified by
-<literal>timeout</literal>, a continuable error is signaled,
-which offers the opportunity to continue waiting.</para>
- <para>A process cannot meaningfully attempt to enable itself.</par=
a>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, ,</para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para>It would be nice to have more discussion of what it means
-to synchronize with the process.</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-RUN-FUNCTION">
- <para>PROCESS-RUN-FUNCTION</para>
- <informalfigure>process-run-function</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-RUN-FUNCTION — Creates a process, presets it, =
and enables it.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-run-function
- process-specifier function &rest args =3D> process
-</programlisting>
- <term><indexterm>process-specifier
- <variablelist><literal>name</literal> |(<literal>&key</lit=
eral> <literal>name</literal><literal>persistent</literal><literal>priority=
</literal><literal>class</literal><literal>stack-size</literal><literal>vst=
ack-size</literal><literal>tstack-size</literal>)</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>name
- <variablelist>a string, used to identify the process.Passed to=
<literal>make-process</literal>.</variablelist>
- </indexterm><indexterm>function
- <variablelist>a function, designated by itself or by a symbolw=
hich names it. Passed to<literal>preset-process</literal>.</variablelist>
- </indexterm><indexterm>persistent
- <variablelist>a boolean, passed to <literal>make-process</lite=
ral>.</variablelist>
- </indexterm><indexterm>priority
- <variablelist>ignored.</variablelist>
- </indexterm><indexterm>class
- <variablelist>a subclass of CCL:PROCESS. Passed to<literal>ma=
ke-process</literal>.</variablelist>
- </indexterm><indexterm>stack-size
- <variablelist>a size, in bytes. Passed to<literal>make-proces=
s</literal>.</variablelist>
- </indexterm><indexterm>vstack-size
- <variablelist>a size, in bytes. Passed to<literal>make-proces=
s</literal>.</variablelist>
- </indexterm><indexterm>tstack-size
- <variablelist>a size, in bytes. Passed to<literal>make-proces=
s</literal>.</variablelist>
- </indexterm><indexterm>process
- <variablelist>the newly-created process.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Creates a lisp process (thread) via
-,
-presets it via , and
-enables it via . This means
-that <literal>process</literal> will immediately begin to
-execute.
-<literal>process-run-function</literal> is
-the simplest way to create and run a process.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, ,</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-INTERRUPT">
- <para>PROCESS-INTERRUPT</para>
- <informalfigure>process-interrupt</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-INTERRUPT — Arranges for the target process to=
invoke a
-specified function at some point in the near future, and then
-return to what it was doing.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-interrupt
- process function &rest args =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>process
- <variablelist>a lisp process (thread).</variablelist>
- </indexterm><indexterm>function
- <variablelist>a function.</variablelist>
- </indexterm><indexterm>args
- <variablelist>a list of values, appropriate as arguments to<li=
teral>function</literal>.</variablelist>
- </indexterm><indexterm>result
- <variablelist>the result of applying <literal>function</litera=
l>to <literal>args</literal> if <literal>proceess</literal>is the <literal>=
current-process</literal>, otherwiseNIL.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Arranges for <literal>process</literal> to apply <literal>fu=
nction</literal> to <literal>args</literal> at
-some point in the near future (interrupting whatever <literal>process</lit=
eral>
-was doing.) If <literal>function</literal> returns normally, <literal>proc=
ess</literal>
-resumes execution at the point at which it was interrupted.</para>
- <para><literal>process</literal> must be in an enabled state in or=
der to respond to a
-<literal>process-interrupt</literal> request. It's perfectly legal for a =
process
-to call <literal>process-interrupt</literal> on itself.</para>
- <para><literal>process-interrupt</literal> uses asynchronous POSIX=
signals to interrupt
-threads. If the thread being interrupted is executing lisp code, it
-can respond to the interrupt almost immediately (as soon as it has
-finished pseudo-atomic operations like consing and stack-frame
-initialization.)</para>
- <para>If the interrupted thread is blocking in a system call, that=
system
-call is aborted by the signal and the interrupt is handled on return.</par=
a>
- <para>Beginning with the version 1.1 prereleases of OpenMCL interr=
upts are
-disabled in <literal>unwind-protect</literal> cleanup forms and in any sta=
ck-unwinding
-code between the point of the <literal>throw</literal> and the correspondi=
ng CATCH
-target. If interrupts were enabled at the time that the CATCH was
-established, then any interrupt that had been deferred during
-unwinding will be taken just before the transfer to <literal>catch</litera=
l> target
-(after all of that unwinding is complete.)</para>
- <para>If an <literal>unwind-protect</literal> cleanup form actuall=
y does something that
-needs to be interruptible, it's necessary to use
-<literal>with-interrupts-enabled</literal>. (This actually happens somewh=
ere in
-the code which waits for external processes to complete; some of that
-waiting occurred within an unwind-protect cleanup, and interrupts
-needed to be explicitly enabled in that case in order to make the wait
-interruptible.)</para>
- <para>Note that <literal>(without-interrupts (throw ...))</literal=
> wouldn't have the intended
-effect, since the <literal>throw</literal> would cause execution to exit t=
he extent of
-the <literal>without-interrupts</literal>.</para>
- <para>In versions prior to 1.1, interrupts could occur at arbitrar=
y times
-during the process of unwinding the stack and executing intervening
-cleanup forms.</para>
- <para>It is still difficult to reliably interrupt arbitrary foreig=
n code
-(that may be stateful or otherwise non-reentrant); the interrupt
-request is handled when such foreign code returns to or enters lisp.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues"></para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para>It would probably be better for <literal>result</literal> to=
always be NIL, since
-the present behaviour is inconsistent.</para>
- <para><literal>Process-interrupt</literal> works by sending signal=
s between threads, via
-the C function <literal>#_pthread_signal</literal>. It could be argued th=
at it
-should be done in one of several possible other ways under Darwin, to
-make it practical to asynchronously interrupt things which make heavy
-use of the Mach nanokernel.</para>
- </sect2>
-
- <sect2 id=3D"iCURRENT-PROCESS-">
- <para>*CURRENT-PROCESS*</para>
- <informalfigure>*current-process*</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>*CURRENT-PROCESS* — Bound in each process, to that pro=
cess
-itself.</para>
- <para>Variable</para>
- <bridgehead renderas=3D"sect3">Value Type</bridgehead>
- <para>A lisp process (thread).</para>
- <bridgehead renderas=3D"sect3">Initial Value</bridgehead>
- <para>Bound separately in each process, to that process itself.</p=
ara>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Used when lisp code needs to find out what process it is
-executing in. Shouldn't be set by user code.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues"></para>
- </sect2>
-
- <sect2 id=3D"PROCESS-RESET">
- <para>PROCESS-RESET</para>
- <informalfigure>process-reset</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-RESET — Causes a specified process to cleanly =
exit from
-any ongoing computation.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-reset
- process &optional kill-option =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>process
- <variablelist>a lisp process (thread).</variablelist>
- </indexterm><indexterm>kill-option
- <variablelist>a generalized boolean. The default is T.</varia=
blelist>
- </indexterm><indexterm>result
- <variablelist>undefined.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Causes <literal>process</literal> to cleanly exit
-from any ongoing computation. If <literal>kill-option</literal>
-is true, <literal>process</literal> then exits. Otherwise, it
-enters a state where it can be
-. This
-is implemented by signaling a condition of type PROCESS-RESET;
-user-defined condition handlers should generally refrain from
-attempting to handle conditions of this type.</para>
- <para>A process can meaningfully reset itself.</para>
- <para>There is in general no way to know precisely when
-<literal>process</literal>
-has completed the act of resetting or killing itself; a process
-which has either entered the limbo of the reset state or exited
-has few ways of communicating either fact.</para>
- <para>can reliably determine when a process has entered
-the "limbo of the reset state", but can't predict how long the
-clean exit from ongoing computation might take: that depends on
-the behavior of <literal>unwind-protect</literal> cleanup
-forms, and of the OS scheduler.</para>
- <para>Resetting a process other than
- involves the
-use of .</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">,</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-KILL">
- <para>PROCESS-KILL</para>
- <informalfigure>process-kill</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-KILL — Causes a specified process to cleanly e=
xit from any
-ongoing computation, and then exit.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-kill process
- =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>process
- <variablelist>a lisp process (thread).</variablelist>
- </indexterm><indexterm>result
- <variablelist>undefined.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Entirely equivalent to calling
-(PROCESS-RESET PROCESS T). Causes <literal>process</literal>
-to cleanly exit from any ongoing computation, and then exit.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">,</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-ABORT">
- <para>PROCESS-ABORT</para>
- <informalfigure>process-abort</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-ABORT — Causes a specified process to process =
an abort
-condition, as if it had invoked
-<literal>abort</literal>.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-abort process
- &optional condition
- =3D> NIL
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>process
- <variablelist>a lisp process (thread).</variablelist>
- </indexterm><indexterm>condition
- <variablelist>a lisp condition. The default is NIL.</variable=
list>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Entirely equivalent to calling
-( <literal>process</literal>
-(<literal>lambda</literal> ()
-(<literal>abort</literal> <literal>condition</literal>))).
-Causes <literal>process</literal> to transfer control to the
-applicable handler or restart for <literal>abort</literal>.</para>
- <para>If <literal>condition</literal> is non-NIL,
-<literal>process-abort</literal> does not consider any
-handlers which are explicitly bound to conditions other than
-<literal>condition</literal>.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">,</para>
- </sect2>
-
- <sect2 id=3D"iTICKS-PER-SECOND-">
- <para>*TICKS-PER-SECOND*</para>
- <informalfigure>*ticks-per-second*</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>*TICKS-PER-SECOND* — Bound to the clock resolution of =
the OS
-scheduler.</para>
- <para>Variable</para>
- <bridgehead renderas=3D"sect3">Value Type</bridgehead>
- <para>A positive integer.</para>
- <bridgehead renderas=3D"sect3">Initial Value</bridgehead>
- <para>The clock resoluton of the OS scheduler. Currently,
-both LinuxPPC and DarwinPPC yeild an initial value of 100.</para>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>This value is ordinarily of marginal interest at best,
-but, for backward compatibility, some functions accept timeout
-values expressed in "ticks". This value gives the number of
-ticks per second.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues"></para>
- </sect2>
-
- <sect2 id=3D"PROCESS-WHOSTATE">
- <para>PROCESS-WHOSTATE</para>
- <informalfigure>process-whostate</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-WHOSTATE — Returns a string which describes th=
e status of
-a specified process.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-whostate process
- =3D> whostate
-</programlisting>
- <term><indexterm>process
- <variablelist>a lisp process (thread).</variablelist>
- </indexterm><indexterm>whostate
- <variablelist>a string which describes the "state" of<literal>=
process</literal>.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>This information is primarily for the benefit of
-debugging tools. <literal>whostate</literal> is a terse report
-on what <literal>process</literal> is doing, or not doing,
-and why.</para>
- <para>If the process is currently waiting in a call to
- or
-, its
-<literal>process-whostate</literal> will be the value
-which was passed to that function as <literal>whostate</literal>.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, ,</para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para>This should arguably be SETFable, but doesn't seem to
-ever have been.</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-ALLOW-SCHEDULE">
- <para>PROCESS-ALLOW-SCHEDULE</para>
- <informalfigure>process-allow-schedule</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-ALLOW-SCHEDULE — Used for cooperative multitas=
king; probably never
-necessary.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-allow-schedule
-</programlisting>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Advises the OS scheduler that the current thread has nothing
-useful to do and that it should try to find some other thread to
-schedule in its place. There's almost always a better
-alternative, such as waiting for some specific event to
-occur. For example, you could use a lock or semaphore.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , ,</para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para>This is a holdover from the days of cooperative
-multitasking. All modern general-purpose operating systems use
-preemptive multitasking.</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-WAIT">
- <para>PROCESS-WAIT</para>
- <informalfigure>process-wait</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-WAIT — Causes the current lisp process (thread=
) to wait for
-a given
-predicate to return true.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-wait
- whostate function &rest args =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>whostate
- <variablelist>a string, which will be the value ofwhile the pr=
ocess is waiting.</variablelist>
- </indexterm><indexterm>function
- <variablelist>a function, designated by itself or by a symbolw=
hich names it.</variablelist>
- </indexterm><indexterm>args
- <variablelist>a list of values, appropriate as arguments to<li=
teral>function</literal>.</variablelist>
- </indexterm><indexterm>result
- <variablelist>NIL.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Causes the current lisp process (thread) to repeatedly
-apply <literal>function</literal> to
-<literal>args</literal> until the call returns a true result, then
-returns NIL. After
-each failed call, yields the CPU as if by
-.</para>
- <para>As with , it's almost
-always more efficient to wait for some
-specific event to occur; this isn't exactly busy-waiting, but
-the OS scheduler can do a better job of scheduling if it's given
-the relevant information. For example, you could use a lock
-or semaphore.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , , ,</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-WAIT-WITH-TIMEOUT">
- <para>PROCESS-WAIT-WITH-TIMEOUT</para>
- <informalfigure>process-wait-with-timeout</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-WAIT-WITH-TIMEOUT — Causes the current thread =
to wait for a given
-predicate to return true, or for a timeout to expire.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-wait-with-timeout
- whostate ticks function args =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>whostate
- <variablelist>a string, which will be the value ofwhile the pr=
ocess is waiting.</variablelist>
- </indexterm><indexterm>ticks
- <variablelist>either a positive integer expressing a durationi=
n "ticks" (see ),or NIL.</variablelist>
- </indexterm><indexterm>function
- <variablelist>a function, designated by itself or by a symbolw=
hich names it.</variablelist>
- </indexterm><indexterm>args
- <variablelist>a list of values, appropriate as arguments to<li=
teral>function</literal>.</variablelist>
- </indexterm><indexterm>result
- <variablelist>T if <literal>process-wait-with-timeout</literal=
>returned because its <literal>function</literal> returnedtrue, or NIL if i=
t returned because the duration<literal>ticks</literal> has been exceeded.<=
/variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>If <literal>ticks</literal> is NIL, behaves exactly like
-, except for returning T.
-Otherwise, <literal>function</literal> will be tested repeatedly,
-in the same
-kind of test/yield loop as in >
-until either <literal>function</literal> returns true,
-or the duration <literal>ticks</literal> has been exceeded.</para>
- <para>Having already read the descriptions of
- and
-, the
-astute reader has no doubt anticipated the observation that
-better alternatives should be used whenever possible.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , , , ,</para>
- </sect2>
-
- <sect2 id=3D"WITHOUT-INTERRUPTS">
- <para>WITHOUT-INTERRUPTS</para>
- <informalfigure>without-interrupts</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>WITHOUT-INTERRUPTS — Evaluates its body in an environm=
ent in which
-process-interrupt requests are deferred.</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-without-interrupts
- &body body =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>body
- <variablelist>an implicit progn.</variablelist>
- </indexterm><indexterm>result
- <variablelist>the primary value returned by<literal>body</lite=
ral>.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Executes <literal>body</literal> in an environment in which
- requests are deferred. As noted in the
-description of , this has nothing to do with
-the scheduling of other threads; it may be necessary to inhibit
- handling when (for instance) modifying some
-data structure (for which the current thread holds an appropriate
-lock) in some manner that's not reentrant.</para>
- <para>Beginning with the version 1.1 prereleases of OpenMCL interr=
upts are
-disabled in <literal>unwind-protect</literal> cleanup forms and in any
-stack-unwinding code between the point of the <literal>throw</literal> and=
the
-corresponding CATCH target. If an <literal>unwind-protect</literal> cleanu=
p form
-actually does something that needs to be interruptible, it's necessary
-to use <literal>with-interrupts-enabled</literal>. In versions prior to 1.=
1,
-interrupts can occur at arbitrary times during the process of
-unwinding the stack and executing intervening cleanup forms.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues"></para>
- </sect2>
-
- <sect2 id=3D"MAKE-LOCK">
- <para>MAKE-LOCK</para>
- <informalfigure>make-lock</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>MAKE-LOCK — Creates and returns a lock object, which c=
an
-be used for synchronization between threads.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-make-lock &optional
- name =3D> lock
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>name
- <variablelist>any lisp object; saved as part of<literal>lock</=
literal>. Typically a string or symbolwhich may appear in the sof threads =
which are waiting for <literal>lock</literal>.</variablelist>
- </indexterm><indexterm>lock
- <variablelist>a newly-allocated object of type CCL:LOCK.</vari=
ablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Creates and returns a lock object, which can
-be used to synchronize access to some shared resource.
-<literal>lock</literal> is
-initially in a "free" state; a lock can also be
-"owned" by a
-thread.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , , , ,</para>
- </sect2>
-
- <sect2 id=3D"WITH-LOCK-GRABBED">
- <para>WITH-LOCK-GRABBED</para>
- <informalfigure>with-lock-grabbed</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>WITH-LOCK-GRABBED — Waits until a given lock can be ob=
tained, then
-evaluates its body with the lock held.</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-with-lock-grabbed
- (lock) &body body
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>lock
- <variablelist>an object of type CCL:LOCK.</variablelist>
- </indexterm><indexterm>body
- <variablelist>an implicit progn.</variablelist>
- </indexterm><indexterm>result
- <variablelist>the primary value returned by<literal>body</lite=
ral>.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Waits until <literal>lock</literal> is either free or
-owned by the calling
-thread, then excutes <literal>body</literal> with the
-lock owned by the calling thread. If <literal>lock</literal>
-was free when <literal>with-lock-grabbed</literal> was called,
-it is restored to a free state after <literal>body</literal>
-is executed.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , , , ,</para>
- </sect2>
-
- <sect2 id=3D"GRAB-LOCK">
- <para>GRAB-LOCK</para>
- <informalfigure>grab-lock</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>GRAB-LOCK — Waits until a given lock can be obtained, =
then
-obtains it.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-grab-lock lock
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>lock
- <variablelist>an object of type CCL:LOCK.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Blocks until <literal>lock</literal> is owned by the
-calling thread.</para>
- <para>The macro =
-<emphasis>could</emphasis> be defined in
-terms of <literal>grab-lock</literal> and
-, but it is actually
-implemented at a slightly lower level.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , , , ,</para>
- </sect2>
-
- <sect2 id=3D"RELEASE-LOCK">
- <para>RELEASE-LOCK</para>
- <informalfigure>release-lock</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>RELEASE-LOCK — Relinquishes ownership of a given lock.=
</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-release-lock lock
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>lock
- <variablelist>an object of type CCL:LOCK.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Signals an error of type CCL:LOCK-NOT-OWNER if
-<literal>lock</literal>
-is not already owned by the calling thread; otherwise, undoes the
-effect of one previous
-. If this means that
-<literal>release-lock</literal> has now been called on
-<literal>lock</literal> the same number of times as
- has, <literal>lock</literal>
-becomes free.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , , , ,</para>
- </sect2>
-
- <sect2 id=3D"TRY-LOCK">
- <para>TRY-LOCK</para>
- <informalfigure>try-lock</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>TRY-LOCK — Obtains the given lock, but only if it is n=
ot
-necessary to wait for it.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-try-lock lock =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>lock
- <variablelist>an object of type CCL:LOCK.</variablelist>
- </indexterm><indexterm>result
- <variablelist>T if <literal>lock</literal> has been obtained,o=
r NIL if it has not.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Tests whether <literal>lock</literal>
-can be obtained without blocking - that is, either
-<literal>lock</literal> is already free, or it is already owned
-by . If it can,
-causes it to
-be owned by the calling lisp process (thread) and returns T.
-Otherwise, the lock
-is already owned by another thread and cannot be obtained without
-blocking; NIL is returned in this case.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , , , ,</para>
- </sect2>
-
- <sect2 id=3D"MAKE-READ-WRITE-LOCK">
- <para>MAKE-READ-WRITE-LOCK</para>
- <informalfigure>make-read-write-lock</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>MAKE-READ-WRITE-LOCK — Creates and returns a read-writ=
e lock, which can
-be used for synchronization between threads.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-make-read-write-lock
- =3D> read-write-lock
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>read-write-lock
- <variablelist>a newly-allocated object of typeCCL:READ-WRITE-L=
OCK.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Creates and returns an object of type CCL::READ-WRITE-LOCK.
-A read-write lock may, at any given time, belong to any number
-of lisp processes (threads) which act as "readers"; or, it may
-belong to at most one process which acts as a "writer". A
-read-write lock may never be held by a reader at the same time as
-a writer. Intially, <literal>read-write-lock</literal> has
-no readers and no writers.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , ,</para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para>There probably should be some way to
-atomically "promote" a reader, making it a writer without
-releasing the lock, which could otherwise cause delay.</para>
- </sect2>
-
- <sect2 id=3D"WITH-READ-LOCK">
- <para>WITH-READ-LOCK</para>
- <informalfigure>with-read-lock</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>WITH-READ-LOCK — Waits until a given lock is available=
for
-read-only access, then evaluates its body with the lock
-held.</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-with-read-lock
- (read-write-lock) &body body =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>read-write-lock
- <variablelist>an object of typeCCL:READ-WRITE-LOCK.</variablel=
ist>
- </indexterm><indexterm>body
- <variablelist>an implicit progn.</variablelist>
- </indexterm><indexterm>result
- <variablelist>the primary value returned by<literal>body</lite=
ral>.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Waits until <literal>read-write-lock</literal> has no
-writer,
-ensures that is a
-reader of it, then executes <literal>body</literal>.</para>
- <para>After executing <literal>body</literal>, if
- was not a reader of
-<literal>read-write-lock</literal> before
-<literal>with-read-lock</literal> was called, the lock is
-released. If it was already a reader, it remains one.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , ,</para>
- </sect2>
-
- <sect2 id=3D"WITH-WRITE-LOCK">
- <para>WITH-WRITE-LOCK</para>
- <informalfigure>with-write-lock</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>WITH-WRITE-LOCK — Waits until the given lock is availa=
ble for write
-access, then executes its body with the lock held.</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-with-write-lock
- (read-write-lock) &body body
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>read-write-lock
- <variablelist>an object of typeCCL:READ-WRITE-LOCK.</variablel=
ist>
- </indexterm><indexterm>body
- <variablelist>an implicit progn.</variablelist>
- </indexterm><indexterm>result
- <variablelist>the primary value returned by<literal>body</lite=
ral>.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Waits until <literal>read-write-lock</literal> has no
-readers and no writer other than ,
-then ensures that is the
-writer of it. With the lock held, executes <literal>body</literal>.</para>
- <para>After executing <literal>body</literal>, if
- was not the writer of
-<literal>read-write-lock</literal> before
-<literal>with-write-lock</literal> was called, the lock is
-released. If it was already the writer, it remains the
-writer.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , ,</para>
- </sect2>
-
- <sect2 id=3D"MAKE-SEMAPHORE">
- <para>MAKE-SEMAPHORE</para>
- <informalfigure>make-semaphore</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>MAKE-SEMAPHORE — Creates and returns a semaphore, whic=
h can be used
-for synchronization between threads.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-make-semaphore
- =3D> semaphore
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>semaphore
- <variablelist>a newly-allocated object of type CCL:SEMAPHORE.<=
/variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Creates and returns an object of type CCL:SEMAPHORE.
-A semaphore has an associated "count" which may be incremented
-and decremented atomically; incrementing it represents sending
-a signal, and decrementing it represents handling that signal.
-<literal>semaphore</literal> has an initial count of 0.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , , ,</para>
- </sect2>
-
- <sect2 id=3D"SIGNAL-SEMAPHORE">
- <para>SIGNAL-SEMAPHORE</para>
- <informalfigure>signal-semaphore</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SIGNAL-SEMAPHORE — Atomically increments the count of =
a given
-semaphore.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-signal-semaphore
- semaphore =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>semaphore
- <variablelist>an object of type CCL:SEMAPHORE.</variablelist>
- </indexterm><indexterm>result
- <variablelist>an integer representing an error identifierwhich=
was returned by the underlying OS call.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Atomically increments <literal>semaphore</literal>'s
-"count" by 1; this
-may enable a waiting thread to resume execution.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , , ,</para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para><literal>result</literal> should probably be interpreted
-and acted on by <literal>signal-semaphore</literal>, because
-it is not likely to be meaningful to a lisp program, and the
-most common cause of failure is a type error.</para>
- </sect2>
-
- <sect2 id=3D"WAIT-ON-SEMAPHORE">
- <para>WAIT-ON-SEMAPHORE</para>
- <informalfigure>wait-on-semaphore</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>WAIT-ON-SEMAPHORE — Waits until the given semaphore ha=
s a positive
-count which can be atomically decremented.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-wait-on-semaphore
- semaphore =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>semaphore
- <variablelist>an object of type CCL:SEMAPHORE.</variablelist>
- </indexterm><indexterm>result
- <variablelist>WAIT-ON-SEMAPHORE always returns T.</variablelis=
t>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Waits until <literal>semaphore</literal>
-has a positive count that can be
-atomically decremented; this will succeed exactly once for each
-corresponding call to SIGNAL-SEMAPHORE.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , , ,</para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- </sect2>
-
- <sect2 id=3D"TIMED-WAIT-ON-SEMAPHORE">
- <para>TIMED-WAIT-ON-SEMAPHORE</para>
- <informalfigure>timed-wait-on-semaphore</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>TIMED-WAIT-ON-SEMAPHORE — Waits until the given semaph=
ore has a postive
-count which can be atomically decremented, or until a timeout
-expires.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-timed-wait-on-semaphore
- semaphore timeout =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>semaphore
- <variablelist>An object of type CCL:SEMAPHORE.</variablelist>
- </indexterm><indexterm>timeout
- <variablelist>a time interval in seconds. May be anynon-negat=
ive real number the <literal>floor</literal> ofwhich fits in 32 bits. The =
default is 1.</variablelist>
- </indexterm><indexterm>result
- <variablelist>T if <literal>timed-wait-on-semaphore</literal>r=
eturned because it was able to decrement the count of<literal>semaphore</li=
teral>; NIL if it returned becausethe duration <literal>timeout</literal> h=
as beenexceeded.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Waits until <literal>semaphore</literal>
-has a positive count that can be
-atomically decremented, or until the duration
-<literal>timeout</literal> has
-elapsed.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , ,</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-INPUT-WAIT">
- <para>PROCESS-INPUT-WAIT</para>
- <informalfigure>process-input-wait</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-INPUT-WAIT — Waits until input is available on=
a given
-file-descriptor.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-input-wait
- fd &optional timeout
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>fd
- <variablelist>a file descriptor, which is a non-negative integ=
erused by the OS to refer to an open file, socket, or similarI/O connection=
. See CCL::STREAM-DEVICE.</variablelist>
- </indexterm><indexterm>timeout
- <variablelist>either NIL, or a time interval in seconds. May =
be anynon-negative real number the <literal>floor</literal> ofwhich fits in=
32 bits. The default is NIL.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Wait until input is available on <literal>fd</literal>.
-This uses the <literal>select()</literal> system call, and is
-generally a fairly
-efficient way of blocking while waiting for input. More
-accurately, <literal>process-input-wait</literal>
-waits until it's possible to read
-from fd without blocking, or until <literal>timeout</literal>, if
-it is not NIL, has been exceeded.</para>
- <para>Note that it's possible to read without blocking if
-the file is at its end - although, of course, the read will
-return zero bytes.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , ,</para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para><literal>process-input-wait</literal> has a timeout paramete=
r,
-and
- does not. This
-inconsistency should probably be corrected.</para>
- </sect2>
-
- <sect2 id=3D"PROCESS-OUTPUT-WAIT">
- <para>PROCESS-OUTPUT-WAIT</para>
- <informalfigure>process-output-wait</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PROCESS-OUTPUT-WAIT — Waits until output is possible o=
n a given file
-descriptor.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-process-output-wait fd
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>fd
- <variablelist>a file descriptor, which is a non-negative integ=
erused by the OS to refer to an open file, socket, or similarI/O connection=
. See CCL::STREAM-DEVICE.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Wait until output is possible on <literal>fd</literal>.
-This uses the <literal>select()</literal> system call, and is
-generally a fairly
-efficient way of blocking while waiting to output.</para>
- <para>If <literal>process-output-wait</literal> is called on
-a network socket which has not yet established a connection, it
-will wait until the connection is established. This is an
-important use, often overlooked.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , ,</para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead> =
- <para>has a timeout parameter,
-and
-<literal>process-output-wait</literal> does not. This
-inconsistency should probably be corrected.</para>
- </sect2>
-
- <sect2 id=3D"WITH-TERMINAL-INPUT">
- <para>WITH-TERMINAL-INPUT</para>
- <informalfigure>with-terminal-input</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>WITH-TERMINAL-INPUT — Executes its body in an environm=
ent with exclusive
-read access to the terminal.</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-with-terminal-input
- &body body =3D> result
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>body
- <variablelist>an implicit progn.</variablelist>
- </indexterm><indexterm>result
- <variablelist>the primary value returned by<literal>body</lite=
ral>.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Requests exclusive read access to the standard terminal
-stream, <literal>*terminal-io*</literal>. Executes
-<literal>body</literal> in an environment with that access.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, :Y, , , , ,</para>
- </sect2>
-
- <sect2 id=3D"iREQUEST-TERMINAL-INPUT-VIA-BREAK-">
- <para>*REQUEST-TERMINAL-INPUT-VIA-BREAK*</para>
- <informalfigure>request-terminal-input-via-break</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>*REQUEST-TERMINAL-INPUT-VIA-BREAK* — Controls how atte=
mpts to obtain ownership of
-terminal input are made.</para>
- <para>Variable</para>
- <bridgehead renderas=3D"sect3">Value Type</bridgehead>
- <para>A boolean.</para>
- <bridgehead renderas=3D"sect3">Initial Value</bridgehead>
- <para>NIL.</para>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Controls how attempts to obtain ownership of terminal input
-are made. When NIL, a message is printed on *TERMINAL-IO*;
-it's expected that the user will later yield
-control of the terminal via the :Y toplevel command. When T, a
-BREAK condition is signaled in the owning process; continuing from
-the break loop will yield the terminal to the requesting process
-(unless the :Y command was already used to do so in the break
-loop.)</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, :Y, , , , ,</para>
- </sect2>
-
- <sect2 id=3D"iY">
- <para>:Y</para>
- <informalfigure>:y</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>:Y — Yields control of terminal input to a specified
-lisp process (thread).</para>
- <para>Toplevel Command</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-(:y p)
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>p
- <variablelist>a lisp process (thread), designated either byan =
integer which matches its<literal>process-serial-number</literal>,or by a s=
tring which is <literal>equal</literal> toits <literal>process-name</litera=
l>.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>:Y is a toplevel command, not a function. As such, it
-can only be used interactively, and only from the initial
-process.</para>
- <para>The command yields control of terminal input to the
-process <literal>p</literal>, which must have used
- to request access to the
-terminal input stream.</para>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">, , , , , ,</para>
- </sect2>
+ </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'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 "free" state; a lock can also be
+ "owned" 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 "promote" 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'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'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>
=
@@ -3132,7 +4387,9 @@
<title>Programming with Sockets</title>
=
<sect1 id=3D"Sockets-Overview">
- <para>OverviewOpenMCL supports the socket abstraction for
+ <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
@@ -3143,629 +4400,1372 @@
<para>OpenMCL supports three types of sockets: TCP sockets, UDP
sockets, and Unix-domain sockets. This should be enough for all
but the most esoteric network situations. All sockets are
- created by . The type of socket depends on the arguments to it,
- as follows:</para>
- <term><indexterm>tcp-stream
- <variablelist>A buffered bi-directional stream over a TCP/IP con=
nection.tcp-stream is a subclass of stream, and you can read and write to i=
tusing all the usual stream functions. Created by (make-socket:addess-famil=
y :internet :type :stream :connect :active ...) or by(accept-connection ...=
).</variablelist>
- </indexterm><indexterm>file-socket-stream
- <variablelist>A buffered bi-directional stream over a "UNIX doma=
in"connection. file-socket-stream is a subclass of stream, and you canread =
and write to it using all the usual stream functions. Createdby (make-socke=
t :address-family :file :type :stream :connect :active...) or by (accept-co=
nnection ...),</variablelist>
- </indexterm><indexterm>listener-socket
- <variablelist>A passive socket used to listen for incoming TCP/I=
Pconnections on a particular port. A listener-socket is not a stream.It doe=
sn't support I/O. It can only be used to create newtcp-streams by accept-co=
nnection. Created by (make-socket :type:stream :connect :passive ...)</vari=
ablelist>
- </indexterm><indexterm>file-listener-socket
- <variablelist>A passive socket used to listen for incoming UNIX =
domainconnections named by a file in the local filesystem. Alistener-socket=
is not a stream. It doesn't support I/O. It canonly be used to create new =
file-socket-streams by accept-connection.Created by (make-socket :address-f=
amily :file :type :stream :connect:passive ...)</variablelist>
- </indexterm><indexterm>udp-socket
- <variablelist>A socket representing a packet-based UDP/IP connec=
tion. Audp-socket supports I/O but it is not a stream. Instead, you mustuse=
the special functions send-to and receive-from to read and writeto it. Cre=
ated by (make-socket :type :datagram ...)</variablelist>
- </indexterm>
- </term>
+ 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 "UNIX domain"
+ 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'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'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>
-
- <sect2 id=3D"MAKE-SOCKET">
- <para>MAKE-SOCKET</para>
- <informalfigure>make-socket</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>MAKE-SOCKET —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-make-socket
- &key address-family type connect eol format
+ <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
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>address-family
- <variablelist>The address/protocol family of this socket. Curr=
entlyonly :internet (the default), meaning IP, and :file,referring to UNIX =
domain addresses, are supported.</variablelist>
- </indexterm><indexterm>type
- <variablelist>One of :stream (the default) to request aconnect=
ion-oriented socket, or :datagram to request aconnectionless socket. The de=
fault is :stream.</variablelist>
- </indexterm><indexterm>connect
- <variablelist>This argument is only relevant to sockets of typ=
e:stream. One of :active (the default) to request a :passiveto request a fi=
le or TCP listener socket.</variablelist>
- </indexterm><indexterm>eol
- <variablelist>This argument is currently ignored (it is accept=
ed forcompatibility with Franz Allegro).</variablelist>
- </indexterm><indexterm>format
- <variablelist>One of :text (the default), :binary, or :bivalen=
t.This argument is ignored for :stream sockets for now, as:stream sockets a=
re currently always bivalent (i.e. theysupport both character and byte I/O)=
. For :datagram sockets,the format determines the type of buffer created by=
receive-from.</variablelist>
- </indexterm><indexterm>remote-host
- <variablelist>Required for TCP streams, it specifies the host =
toconnect to (in any format acceptable to lookup-hostname).Ignored for list=
ener sockets. For UDP sockets, it can beused to specify a default host for =
subsequent calls tosend-to or receive-from.</variablelist>
- </indexterm><indexterm>remote-port
- <variablelist>Required for TCP streams, it specifies the port =
toconnect to (in any format acceptable to lookup-port).Ignored for listener=
sockets. For UDP sockets, it can beused to specify a default port for subs=
equent calls to forsubsequent calls to send-to or receive-from.</variableli=
st>
- </indexterm><indexterm>remote-filename
- <variablelist>Required for file-socket streams, it specifies t=
hename of a file in the local filesystem (e.g., NOT mountedvia NFS, AFP, SM=
B, ...) which names and controls access to aUNIX-domain socket.</variableli=
st>
- </indexterm><indexterm>local-host
- <variablelist>Allows you to specify a local host address for a=
listener or UDP socket, for the rare case where you want torestrict connect=
ions to those coming to a specific localaddress for security reasons.</vari=
ablelist>
- </indexterm><indexterm>local-port
- <variablelist>Specify a local port for a socket. Most useful f=
orlistener sockets, where it is the port on which the socketwill listen for=
connections.</variablelist>
- </indexterm><indexterm>local-filename
- <variablelist>Required for file-listener-sockets. Specifies th=
e nameof a file in the local filesystem which is used to name aUNIX-domain =
socket. The actual filesystem file should notpreviously exist when the file=
-listener-socket is created;its parent directory should exist and be writab=
le by thecaller. The file used to name the socket will be deletedwhen the f=
ile-listener-socket is closed.</variablelist>
- </indexterm><indexterm>keepalive
- <variablelist>If true, enables the periodic transmission of"ke=
epalive" messages.</variablelist>
- </indexterm><indexterm>reuse-address
- <variablelist>If true, allows the reuse of local ports in list=
enersockets, overriding some TCP/IP protocol specifications. Youwill need t=
his if you are debugging a server..</variablelist>
- </indexterm><indexterm>nodelay
- <variablelist>If true, disables Nagle's algorithm, which tries=
to minimize TCP packet fragmentation by introducingtransmission delays in t=
he absence of replies. Try settingthis if you are using a protocol which in=
volves sending asteady stream of data with no replies and are seeingsignifi=
cant degradations in throughput.</variablelist>
- </indexterm><indexterm>broadcast
- <variablelist>If true, requests permission to broadcast datagr=
ams ona UDP socket.</variablelist>
- </indexterm><indexterm>linger
- <variablelist>If specified and non-nil, should be the number o=
fseconds the OS is allowed to wait for data to be pushedthrough when a clos=
e is done. Only relevant for TCP sockets.</variablelist>
- </indexterm><indexterm>backlog
- <variablelist>For a listener socket, specifies the number ofco=
nnections which can be pending but not accepted. Thedefault is 5, which is =
also the maximum on some operatingsystems.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Creates and returns a new socket</para>
- </sect2>
-
- <sect2 id=3D"ACCEPT-CONNECTION">
- <para>ACCEPT-CONNECTION</para>
- <informalfigure>accept-connection</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>ACCEPT-CONNECTION —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-accept-connection
- (socket listener-socket) &key wait
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The listener-socket to listen on.</variablelist>
- </indexterm><indexterm>wait
- <variablelist>If true (the default), and there are no connecti=
onswaiting to be accepted, waits until one arrives. If false,returns NIL im=
mediately.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Extracts the first connection on the queue of pending
-connections, accepts it (i.e. completes the connection startup
-protocol) and returns a new tcp-stream or file-socket-stream
-representing the newly established connection. The tcp stream
-inherits any properties of the listener socket that are relevant
-(e.g. :keepalive, :nodelay, etc.) The original listener socket
-continues to be open listening for more connections, so you can
-call accept-connection on it again.</para>
- </sect2>
-
- <sect2 id=3D"DOTTED-TO-IPADDR">
- <para>DOTTED-TO-IPADDR</para>
- <informalfigure>dotted-to-ipaddr</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>DOTTED-TO-IPADDR —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-dotted-to-ipaddr
- dotted &key errorp
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>dotted
- <variablelist>A string representing an IP address in the"nn.nn=
.nn.nn" format</variablelist>
- </indexterm><indexterm>errorp
- <variablelist>If true (the default) an error is signaled if do=
ttedis invalid. If false, NIL is returned.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Converts a dotted-string representation of a host address to
-a 32-bit unsigned IP address.</para>
- </sect2>
-
- <sect2 id=3D"IPADDR-TO-DOTTED">
- <para>IPADDR-TO-DOTTED</para>
- <informalfigure>ipaddr-to-dotted</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>IPADDR-TO-DOTTED —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-ipaddr-to-dotted
- ipaddr &key values
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>ipaddr
- <variablelist>A 32-bit integer representing an internet host a=
ddress</variablelist>
- </indexterm><indexterm>values
- <variablelist>If false (the default), returns a string in the =
form"nn.nn.nn.nn". If true, returns four valuesrepresenting the four octets=
of the address as unsigned8-bit integers.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Converts a 32-bit unsigned IP address into octets.</para>
- </sect2>
-
- <sect2 id=3D"IPADDR-TO-HOSTNAME">
- <para>IPADDR-TO-HOSTNAME</para>
- <informalfigure>ipaddr-to-hostname</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>IPADDR-TO-HOSTNAME —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-ipaddr-to-hostname
- ipaddr &key ignore-cache
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>ipaddr
- <variablelist>a 32-bit integer representing an internet host a=
ddress</variablelist>
- </indexterm><indexterm>ignore-cache
- <variablelist>This argument is ignored (it is accepted forcomp=
atibility with Franz Allegro)</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Converts a 32-bit unsigned IP address into a host name
-string</para>
- </sect2>
-
- <sect2 id=3D"LOOKUP-HOSTNAME">
- <para>LOOKUP-HOSTNAME</para>
- <informalfigure>lookup-hostname</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>LOOKUP-HOSTNAME —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-lookup-hostname
- host
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>host
- <variablelist>Specifies the host. It can be either a host name=
string such as "clozure.com", or a dotted addressstring such as "192.168.0.=
1", or a 32-bit unsignedIP address such as 3232235521.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Converts a host spec in any of the acceptable formats into a
-32-bit unsigned IP address</para>
- </sect2>
-
- <sect2 id=3D"LOOKUP-PORT">
- <para>LOOKUP-PORT</para>
- <informalfigure>lookup-port</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>LOOKUP-PORT —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-lookup-port
- port protocol
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>port
- <variablelist>Specifies the port. It can be either a string, s=
uch as"http" or a symbol, such as :http, or an unsignedport number. Note th=
at a string is case-sensitive. A symbolis lowercased before lookup.</variab=
lelist>
- </indexterm><indexterm>protocol
- <variablelist>Must be one of "tcp" or "udp".</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Finds the port number for the specified port and protocol</p=
ara>
- </sect2>
-
- <sect2 id=3D"RECEIVE-FROM">
- <para>RECEIVE-FROM</para>
- <informalfigure>receive-from</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>RECEIVE-FROM —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-receive-from
- (socket udp-socket) size &key buffer
- extract offset
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket to read from</variablelist>
- </indexterm><indexterm>size
- <variablelist>Maximum number of bytes to read. If the packet i=
slarger than this, any extra bytes are discarded.</variablelist>
- </indexterm><indexterm>buffer
- <variablelist>If specified, must be either a string or a byte =
vectorwhich will be used to read in the data. If not specified, anew buffer=
will be created (of type determined bysocket-format).</variablelist>
- </indexterm><indexterm>extract
- <variablelist>If true, the subsequence of the buffer correspon=
dingonly to the data read in is extracted and returned as thefirst value. I=
f false (the default) the original buffer isreturned even if it is only par=
tially filled.</variablelist>
- </indexterm><indexterm>offset
- <variablelist>Specifies the start offset into the buffer at wh=
ichdata is to be stored. The default is 0.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Reads a UDP packet from a socket. If no packets are
-available, waits for a packet to arrive. Returns four values:</para>
- <varlistentry numeration=3D"arabic">
- <variablelist>The buffer with the data</variablelist>
- <variablelist>The number of bytes read</variablelist>
- <variablelist>The 32-bit unsigned IP address of the sender of th=
e data</variablelist>
- <variablelist>The port number of the sender of the data</variabl=
elist>
- </varlistentry>
- </sect2>
-
- <sect2 id=3D"SEND-TO">
- <para>SEND-TO</para>
- <informalfigure>send-to</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SEND-TO —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-send-to
- (socket udp-socket) buffer size &key remote-host
- remote-port offset
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket to write to</variablelist>
- </indexterm><indexterm>buffer
- <variablelist>A vector containing the data to send. It must be=
either a string or a byte vector (either one is acceptableregardless of the=
stream format).</variablelist>
- </indexterm><indexterm>size
- <variablelist>Number of bytes to send</variablelist>
- </indexterm><indexterm>remote-host
- <variablelist>The host to send the packet to, in any formatacc=
eptable to lookup-hostname. The default is the remotehost specified in the =
call to make-socket.</variablelist>
- </indexterm><indexterm>remote-port
- <variablelist>The port to send the packet to, in any formatacc=
eptable to lookup-port. The default is the remote portspecified in the call=
to make-socket.</variablelist>
- </indexterm><indexterm>offset
- <variablelist>The offset in the buffer where the packet data s=
tarts</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Send a UDP packet over a socket.</para>
- </sect2>
-
- <sect2 id=3D"SHUTDOWN">
- <para>SHUTDOWN</para>
- <informalfigure>shutdown</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SHUTDOWN —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-shutdown
- socket &key direction
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket to shut down (typically a tcp-stream)=
</variablelist>
- </indexterm><indexterm>direction
- <variablelist>One of :input to disallow further input, or :out=
put todisallow further output.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Shuts down part of a bidirectional connection. This is
-useful if e.g. you need to read responses after sending an
-end-of-file signal.</para>
- </sect2>
-
- <sect2 id=3D"SOCKET-OS-FD">
- <para>SOCKET-OS-FD</para>
- <informalfigure>socket-os-fd</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SOCKET-OS-FD —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-socket-os-fd
- socket
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the native OS's representation of the socket, or
-NIL if the socket is closed. On Unix, this is the Unix 'file
-descriptor', a small non-negative integer. Note that it is
-rather dangerous to mess around with tcp-stream fd's, as there
-is all sorts of buffering and asynchronous I/O going on above the
-OS level. listener-socket and udp-socket fd's are safer to
-mess with directly as there is less magic going on.</para>
- </sect2>
-
- <sect2 id=3D"REMOTE-HOST">
- <para>REMOTE-HOST</para>
- <informalfigure>remote-host</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>REMOTE-HOST —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-remote-host
- socket
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the 32-bit unsigned IP address of the remote host,
-or NIL if the socket is not connected.</para>
- </sect2>
-
- <sect2 id=3D"REMOTE-PORT">
- <para>REMOTE-PORT</para>
- <informalfigure>remote-port</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>REMOTE-PORT —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-remote-port
- socket
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the remote port number, or NIL if the socket is not
-connected.</para>
- </sect2>
-
- <sect2 id=3D"LOCAL-HOST">
- <para>LOCAL-HOST</para>
- <informalfigure>local-host</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>LOCAL-HOST —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-local-host
- socket
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns 32-bit unsigned IP address of the local host.</para>
- </sect2>
-
- <sect2 id=3D"LOCAL-PORT">
- <para>LOCAL-PORT</para>
- <informalfigure>local-port</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>LOCAL-PORT —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-local-port
- socket
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the local port number</para>
- </sect2>
-
- <sect2 id=3D"SOCKET-ADDRESS-FAMILY">
- <para>SOCKET-ADDRESS-FAMILY</para>
- <informalfigure>socket-address-family</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SOCKET-ADDRESS-FAMILY —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-socket-address-family
- socket
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns :internet or :file, as appropriate.</para>
- </sect2>
-
- <sect2 id=3D"SOCKET-CONNECT">
- <para>SOCKET-CONNECT</para>
- <informalfigure>socket-connect</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SOCKET-CONNECT —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-socket-connect
- socket
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns :active for tcp-stream, :passive for
-listener-socket, and NIL for udp-socket</para>
- </sect2>
-
- <sect2 id=3D"SOCKET-FORMAT">
- <para>SOCKET-FORMAT</para>
- <informalfigure>socket-format</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SOCKET-FORMAT —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-socket-format
- socket
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the socket format as specified by the :format
-argument to make-socket.</para>
- </sect2>
-
- <sect2 id=3D"SOCKET-TYPE">
- <para>SOCKET-TYPE</para>
- <informalfigure>socket-type</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SOCKET-TYPE —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-socket-type
- socket
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>returns :stream for tcp-stream and listener-socket, and
-:datagram for udp-socket.</para>
- </sect2>
-
- <sect2 id=3D"SOCKET-ERROR">
- <para>SOCKET-ERROR</para>
- <informalfigure>socket-error</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SOCKET-ERROR —</para>
- <para>Class</para>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>The class of OS errors signaled by socket functions</para>
- <bridgehead renderas=3D"sect3">Superclasses</bridgehead>
- <para>simple-error</para>
- </sect2>
-
- <sect2 id=3D"SOCKET-ERROR-CODE">
- <para>SOCKET-ERROR-CODE</para>
- <informalfigure>socket-error-code</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SOCKET-ERROR-CODE —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-socket-error-code
- socket-error
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket-error
- <variablelist>the condition</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>The OS error code of the error</para>
- </sect2>
-
- <sect2 id=3D"SOCKET-ERROR-IDENTIFIER">
- <para>SOCKET-ERROR-IDENTIFIER</para>
- <informalfigure>socket-error-identifier</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SOCKET-ERROR-IDENTIFIER —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-socket-error-identifier
- socket-error
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket-error
- <variablelist>the condition</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>A symbol representing the error code in a more
-OS-independent way.</para>
- <para>One of: :address-in-use :connection-aborted :no-buffer-space
-:connection-timed-out :connection-refused :host-unreachable
-:host-down :network-down :address-not-available :network-reset
-:connection-reset :shutdown :access-denied or :unknown.</para>
- </sect2>
-
- <sect2 id=3D"SOCKET-ERROR-SITUATION">
- <para>SOCKET-ERROR-SITUATION</para>
- <informalfigure>socket-error-situation</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SOCKET-ERROR-SITUATION —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-socket-error-situation
- socket-error
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket-error
- <variablelist>the condition</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>A string describing the context where the error happened. On
-Linux, this is the name of the system call which returned the
-error.</para>
- </sect2>
-
- <sect2 id=3D"CLOSE">
- <para>CLOSE</para>
- <informalfigure>close</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CLOSE —</para>
- <para>Method</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-close
- (socket socket) &key abort
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>socket
- <variablelist>The socket to close</variablelist>
- </indexterm><indexterm>abort
- <variablelist>If false (the default), closes the socket in ano=
rderly fashion, finishing up any buffered pending I/O,before closing the co=
nnection. If true, aborts/ignorespending I/O. (For listener and udp sockets=
, this argument iseffectively ignored since there is never any buffered I/O=
toclean up).</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>The close generic function can be applied to sockets. It
-releases the operating system resources associated with the
-socket.</para>
- </sect2>
-
- <sect2 id=3D"WITH-OPEN-SOCKET">
- <para>WITH-OPEN-SOCKET</para>
- <informalfigure>with-open-socket</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>WITH-OPEN-SOCKET —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-with-open-socket
- (var . make-socket-args) &body body
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>var
- <variablelist>variable to bind</variablelist>
- </indexterm><indexterm>make-socket-args
- <variablelist>arguments suitable for passing to make-socket</v=
ariablelist>
- </indexterm><indexterm>body
- <variablelist>body to execute</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>executes body with var bound to the result of applying
-make-socket to make-socket-args. The socket gets closed on exit.</para>
- </sect2>
+ 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
+ "keepalive" 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'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
+ "nn.nn.nn.nn" 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
+ "nn.nn.nn.nn". 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 "clozure.com", or a dotted address
+ string such as "192.168.0.1", 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
+ "http" 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 "tcp" or "udp".</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's representation of the socket, or
+ NIL if the socket is closed. On Unix, this is the Unix 'file
+ descriptor', a small non-negative integer. Note that it is
+ rather dangerous to mess around with tcp-stream fd's, as there
+ is all sorts of buffering and asynchronous I/O going on above the
+ OS level. listener-socket and udp-socket fd's are safer to
+ mess with directly as there is less magic going on.</para>
+ </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>
=
@@ -3804,7 +5804,7 @@
</sect1>
=
<sect1 id=3D"Limitations-and-known-bugs">
- <para>Limitations and known bugs</para>
+ <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
@@ -3820,199 +5820,423 @@
=
<sect1 id=3D"External-Program-Dictionary">
<title>External-Program Dictionary</title>
-
- <sect2 id=3D"RUN-PROGRAM">
- <para>RUN-PROGRAM</para>
- <informalfigure>run-program</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>RUN-PROGRAM — Invokes an external program as an OS sub=
process
-of lisp.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-run-program
- program args &key (wait t) pty input
+ <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
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>program
- <variablelist>A string or pathname which denotes an executable=
file.The PATH environment variable is used to find programs whosename does=
n't contain a directory component.</variablelist>
- </indexterm><indexterm>args
- <variablelist>A list of simple-strings</variablelist>
- </indexterm><indexterm>wait
- <variablelist>Indicates whether or not run-program should wait=
forthe EXTERNAL-PROCESS to complete or should returnimmediately.</variable=
list>
- </indexterm><indexterm>pty
- <variablelist>This option is accepted but currently ignored;it=
's intended to make it easier to run external programsthat need to interact=
with a terminal device.</variablelist>
- </indexterm><indexterm>input
- <variablelist>Selects the input source used by the EXTERNAL-PR=
OCESS.May be any of the following:
- <listitem mark=3D"bullet">
- <variablelist>NIL Specifies that a null input stream (e.g.=
,/dev/null) should be used.</variablelist>
- <variablelist>T Specifies that the EXTERNAL-PROCESS should=
usethe input source with which OpenMCL was invoked.</variablelist>
- <variablelist>A string or pathname. Specifies that theEXTE=
RNAL-PROCESS should receive its input from the namedexisting file.</variabl=
elist>
- <variablelist>:STREAM Creates a Lisp stream opened for cha=
racteroutput. Any data written to this stream (accessible asthe EXTERNAL-PR=
OCESS-INPUT-STREAM of theEXTERNAL-PROCESS object) appears as input to theex=
ternal process.</variablelist>
- <variablelist>A stream. Specifies that the lisp stream sho=
uldprovide input to the EXTERNAL-PROCESS.</variablelist>
- =
- </listitem>
-</variablelist>
- </indexterm><indexterm>if-input-does-not-exist
- <variablelist>If the input argument specifies the name of anex=
isting file, this argument is used as theif-does-not-exist argument to OPEN=
when that file is opened.</variablelist>
- </indexterm><indexterm>output
- <variablelist>Specifies where standard output from the externa=
lprocess should be sent. Analogous to input above.</variablelist>
- </indexterm><indexterm>if-output-exists
- <variablelist>If output is specified as a string or pathname, =
thisargument is used as the if-exists argument to OPEN when thatfile is ope=
ned.</variablelist>
- </indexterm><indexterm>error
- <variablelist>Specifies where error output from the external p=
rocessshould be sent. In addition to the values allowed foroutput, the keyw=
ord :OUTPUT can be used to indicate thaterror output should be sent where s=
tandard output goes.</variablelist>
- </indexterm><indexterm>if-error-exists
- <variablelist>Analogous to if-output-exists.</variablelist>
- </indexterm><indexterm>status-hook
- <variablelist>A user-defined function of one argument (theEXTE=
RNAL-PROCESS structure.) This function is calledwhenever OpenMCL detects a =
change in the staus of theEXTERNAL-PROCESS.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Runs the specified program in an external (Unix) process,
-returning an object of type EXTERNAL-PROCESS if successful.</para>
- </sect2>
-
- <sect2 id=3D"SIGNAL-EXTERNAL-PROCESS">
- <para>SIGNAL-EXTERNAL-PROCESS</para>
- <informalfigure>signal-external-process</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SIGNAL-EXTERNAL-PROCESS —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-signal-external-process
- proc signal-number
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>proc
- <variablelist>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.=
</variablelist>
- </indexterm><indexterm>signal
- <variablelist>A small integer.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Sends the specified "signal" to the specified
-external process. (Typically, it would only be useful tocall
-this function if the EXTERNAL-PROCESS was created with :WAIT
-NIL. ) Returns T if successful; signals an error otherwise.</para>
- </sect2>
-
- <sect2 id=3D"EXTERNAL-PROCESS-ID">
- <para>EXTERNAL-PROCESS-ID</para>
- <informalfigure>external-process-id</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>EXTERNAL-PROCESS-ID — Returns the "process ID" of an O=
S subprocess,
-a positive integer which identifies it.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-external-process-id
- proc
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>proc
- <variablelist>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.=
</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the <emphasis>process id</emphasis> assigned to
-the external process by the operating system. This is typically
-a positive, 16-bit number.</para>
- </sect2>
-
- <sect2 id=3D"EXTERNAL-PROCESS-INPUT-STREAM">
- <para>EXTERNAL-PROCESS-INPUT-STREAM</para>
- <informalfigure>external-process-input-stream</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>EXTERNAL-PROCESS-INPUT-STREAM — Returns the lisp strea=
m which is used to write
-input to a given OS subprocess, if it has one.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-external-process-input-stream
- proc
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>proc
- <variablelist>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.=
</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the stream created when the input argument to
-run-program is specified as :STREAM.</para>
- </sect2>
-
- <sect2 id=3D"EXTERNAL-PROCESS-OUTPUT-STREAM">
- <para>EXTERNAL-PROCESS-OUTPUT-STREAM</para>
- <informalfigure>external-process-output-stream</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>EXTERNAL-PROCESS-OUTPUT-STREAM — Returns the lisp stre=
am which is used to read
-output from an OS subprocess, if there is one.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-external-process-output-stream
- proc
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>proc
- <variablelist>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.=
</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the stream created when the output argument to
-run-program is specified as :STREAM.</para>
- </sect2>
-
- <sect2 id=3D"EXTERNAL-PROCESS-ERROR-STREAM">
- <para>EXTERNAL-PROCESS-ERROR-STREAM</para>
- <informalfigure>external-process-error-stream</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>EXTERNAL-PROCESS-ERROR-STREAM — Returns the stream whi=
ch is used to read
-"error" output from a given OS subprocess, if it has
-one.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-external-process-error-stream
- proc
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>proc
- <variablelist>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.=
</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the stream created when the error argument to
-run-program is specified as :STREAM.</para>
- </sect2>
-
- <sect2 id=3D"EXTERNAL-PROCESS-STATUS">
- <para>EXTERNAL-PROCESS-STATUS</para>
- <informalfigure>external-process-status</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>EXTERNAL-PROCESS-STATUS — Returns information about wh=
ether an OS
-subprocess is running; or, if not, why not; and what its
-result code was if it completed.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-external-process-status
- proc
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>proc
- <variablelist>An EXTERNAL-PROCESS, as returned by RUN-PROGRAM.=
</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns, as multiple values, a keyword denoting the status
-of the external process (one of :running, :stopped, :signaled, or
-:exited), and the exit code or terminating signal if the first
-value is other than :running.</para>
- </sect2>
+ :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>
=
@@ -4037,370 +6261,147 @@
why standards are important.</para>
<para>Here's a list of some classes which you might wish for
your new stream class to inherit from:</para>
- <colspec>
- <thead cols=3D"1">
- <tbody colwidth=3D"100*"></tbody>
- <row>
- <abstract>
- <entry>fundamental-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>fundamental-input-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>fundamental-output-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>fundamental-character-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>fundamental-binary-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>fundamental-character-input-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>fundamental-character-output-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>fundamental-binary-input-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>fundamental-binary-output-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::buffered-stream-mixin</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::buffered-input-stream-mixin</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::buffered-output-stream-mixin</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::buffered-io-stream-mixin</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::buffered-character-input-stream-mixin</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::buffered-character-output-stream-mixin</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::buffered-character-io-stream-mixin</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::buffered-binary-input-stream-mixin</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::buffered-binary-output-stream-mixin</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::buffered-binary-io-stream-mixin</entry>
- =
- </abstract>
- <abstract>
- <entry>file-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>file-input-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>file-output-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>file-io-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>file-character-input-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>file-character-output-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>file-charcter-io-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>file-binary-input-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>file-binary-output-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>file-binary-io-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::fd-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::fd-input-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::fd-output-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::fd-io-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::fd-character-input-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::fd-character-output-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::fd-character-io-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::fd-binary-input-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::fd-binary-output-stream</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::fd-binary-io-stream</entry>
- =
- </abstract>
- </row>
- </thead>
- </colspec>
- <para>All of these are defined in ccl/level-1/l1-streams.lisp, excep=
t 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 in=
herit
-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::buffere=
d-*
-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 wit=
h 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>
+ =
+ <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>
- <colspec>
- <thead cols=3D"1">
- <tbody colwidth=3D"100*"></tbody>
- <row>
- <abstract>
- <entry>stream-direction stream =3D></entry>
- =
- </abstract>
- <abstract>
- <entry>stream-device stream direction =3D></entry>
- =
- </abstract>
- <abstract>
- <entry>stream-length stream <literal>&optional</literal>=
new =3D></entry>
- =
- </abstract>
- <abstract>
- <entry>stream-position stream <literal>&optional</litera=
l>new =3D></entry>
- =
- </abstract>
- <abstract>
- <entry>streamp stream =3D> boolean</entry>
- =
- </abstract>
- <abstract>
- <entry>stream-write-char output-stream char =3D></entry>
- =
- </abstract>
- <abstract>
- <entry>stream-write-entire-string output-stream string =3D><=
/entry>
- =
- </abstract>
- <abstract>
- <entry>stream-read-char input-stream =3D></entry>
- =
- </abstract>
- <abstract>
- <entry>stream-unread-char input-stream char =3D></entry>
- =
- </abstract>
- <abstract>
- <entry>stream-force-output output-stream =3D> nil</entry>
- =
- </abstract>
- <abstract>
- <entry>stream-maybe-force-output output-stream =3D> nil</ent=
ry>
- =
- </abstract>
- <abstract>
- <entry>stream-finish-output output-stream =3D> nil</entry>
- =
- </abstract>
- <abstract>
- <entry>stream-clear-output output-stream =3D> nil</entry>
- =
- </abstract>
- <abstract>
- <entry>close stream <literal>&key</literal>abort =3D> bo=
olean</entry>
- =
- </abstract>
- <abstract>
- <entry>stream-fresh-line stream =3D> t</entry>
- =
- </abstract>
- <abstract>
- <entry>stream-line-length stream =3D> length</entry>
- =
- </abstract>
- <abstract>
- <entry>interactive-stream-p stream =3D> boolean</entry>
- =
- </abstract>
- <abstract>
- <entry>stream-clear-input input-stream =3D> nil</entry>
- =
- </abstract>
- <abstract>
- <entry>stream-listen input-stream =3D> boolean</entry>
- =
- </abstract>
- <abstract>
- <entry>stream-filename stream =3D> string</entry>
- =
- </abstract>
- <abstract>
- <entry>ccl::select-stream-class instance in-p out-p char-p =
=3D>class</entry>
- =
- </abstract>
- </row>
- </thead>
- </colspec>
+ (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>
- <colspec>
- <thead cols=3D"1">
- <tbody colwidth=3D"100*"></tbody>
- <row>
- <abstract>
- <entry>open-stream-p stream =3D> generalized-boolean</entry>
- =
- </abstract>
- <abstract>
- <entry>input-stream-p stream =3D> generalized-boolean</entry>
- =
- </abstract>
- <abstract>
- <entry>output-stream-p stream =3D> generalized-boolean</entr=
y>
- =
- </abstract>
- <abstract>
- <entry>stream-element-type stream =3D></entry>
- =
- </abstract>
- <abstract>
- <entry>stream-error-stream =3D></entry>
- =
- </abstract>
- <abstract>
- <entry>open</entry>
- =
- </abstract>
- <abstract>
- <entry>close</entry>
- =
- </abstract>
- <abstract>
- <entry>with-open-file</entry>
- =
- </abstract>
- </row>
- </thead>
- </colspec>
- <para>Specifically, (open) and (with-open-file) accept a new keyword
-argument, :class, which may be a symbol naming a class; the class
-itself; or an instance of it. The class so given must be a subtype
-of 'stream, and an instance of it with no particular contents will
-be passed to ccl::select-stream-class to determine what class to
-actually instantiate.</para>
- <para>The following are standard, and do not behave specially with
-regard to Gray streams, but probably should.</para>
- <colspec>
- <thead cols=3D"1">
- <tbody colwidth=3D"100*"></tbody>
- <row>
- <abstract>
- <entry>stream-external-format</entry>
- =
- </abstract>
- </row>
- </thead>
- </colspec>
+ <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">
@@ -4475,209 +6476,467 @@
=
<sect1 id=3D"Gray-Streams-Dictionary">
<title>Gray Streams Dictionary</title>
-
- <sect2 id=3D"CCL-STREAM-READ-LIST">
- <para>CCL:STREAM-READ-LIST</para>
- <informalfigure>stream-read-list</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL:STREAM-READ-LIST —</para>
- <para>Generic Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-stream-read-list
- stream list count
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>stream
- <variablelist>a stream, presumably a fundamental-input-stream.=
</variablelist>
- </indexterm><indexterm>list
- <variablelist>a list. When a STREAM-READ-LIST method is called=
byREAD-SEQUENCE, this argument is guaranteed to be a properlist.</variable=
list>
- </indexterm><indexterm>count
- <variablelist>a non-negative integer. When a STREAM-READ-LIST =
methodis called by READ-SEQUENCE, this argument is guaranteed notto be grea=
ter than the length of the list.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Should try to read up to count elements from stream into the
-list list, returning the number of elements actually read (which
-may be less than count in case of a premature end-of-file.)</para>
- </sect2>
-
- <sect2 id=3D"CCL-STREAM-WRITE-LIST">
- <para>CCL:STREAM-WRITE-LIST</para>
- <informalfigure>stream-write-list</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL:STREAM-WRITE-LIST —</para>
- <para>Generic Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-stream-write-list
- stream list count
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>stream
- <variablelist>a stream, presumably a fundamental-ouput-stream.=
</variablelist>
- </indexterm><indexterm>list
- <variablelist>a list. When a STREAM-WRITE-LIST method is calle=
d byWRITE-SEQUENCE, this argument is guaranteed to be a properlist.</variab=
lelist>
- </indexterm><indexterm>count
- <variablelist>a non-negative integer. When a STREAM-WRITE-LIST=
method is called by WRITE-SEQUENCE, this argument isguaranteed not to be gr=
eater than the length of the list.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>should try to write the first count elements of list to
-stream. The return value of this method is ignored.</para>
- </sect2>
-
- <sect2 id=3D"CCL-STREAM-READ-VECTOR">
- <para>CCL:STREAM-READ-VECTOR</para>
- <informalfigure>stream-read-vector</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL:STREAM-READ-VECTOR —</para>
- <para>Generic Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-stream-read-vector
- stream vector start end
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>stream
- <variablelist>a stream, presumably a fundamental-input-stream<=
/variablelist>
- </indexterm><indexterm>vector
- <variablelist>a vector. When a STREAM-READ-VECTOR method is ca=
lledby READ-SEQUENCE, this argument is guaranteed to be a simpleone-dimensi=
onal array.</variablelist>
- </indexterm><indexterm>start
- <variablelist>a non-negative integer. When a STREAM-READ-VECTO=
Rmethod is called by READ-SEQUENCE, this argument isguaranteed to be no gre=
ater than end and not greater thanthe length of vector.</variablelist>
- </indexterm><indexterm>end
- <variablelist>a non-negative integer. When a STREAM-READ-VECTO=
Rmethod is called by READ-SEQUENCE, this argument isguaranteed to be no les=
s than end and not greater than thelength of vector.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>should try to read successive elements from stream into
-vector, starting at element start (inclusive) and continuing
-through element end (exclusive.) Should return the index of the
-vector element beyond the last one stored into, which may be less
-than end in case of premature end-of-file.</para>
- </sect2>
-
- <sect2 id=3D"CCL-STREAM-WRITE-VECTOR">
- <para>CCL:STREAM-WRITE-VECTOR</para>
- <informalfigure>stream-write-vector</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL:STREAM-WRITE-VECTOR —</para>
- <para>Generic Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-stream-write-vector
- stream vector start end
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>stream
- <variablelist>a stream, presumably a fundamental-output-stream=
</variablelist>
- </indexterm><indexterm>vector
- <variablelist>a vector. When a STREAM-WRITE-VECTOR method is c=
alledby WRITE-SEQUENCE, this argument is guaranteed to be asimple one-dimen=
sional array.</variablelist>
- </indexterm><indexterm>start
- <variablelist>a non-negative integer. When a STREAM-WRITE-VECT=
ORmethod is called by WRITE-SEQUENCE, this argument isguaranteed to be no g=
reater than end and not greater thanthe length of vector.</variablelist>
- </indexterm><indexterm>end
- <variablelist>a non-negative integer. When a STREAM-WRITE-VECT=
ORmethod is called by WRITE-SEQUENCE, this argument isguaranteed to be no l=
ess than end and not greater than thelength of vector.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>should try to write successive elements of vector to stream,
-starting at element start (inclusive) and continuing through
-element end (exclusive.)</para>
- </sect2>
-
- <sect2 id=3D"CCL--STREAM-DEVICE">
- <para>CCL::STREAM-DEVICE</para>
- <informalfigure>stream-device</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::STREAM-DEVICE — Returns the OS file descriptor as=
sociated with a
-given lisp stream.</para>
- <para>Generic Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-ccl::stream-device
- s direction
-</programlisting>
- <bridgehead renderas=3D"sect3">Method Signatures</bridgehead>
- <programlisting>
-ccl::stream-device
- (s stream) direction =3D> fd
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>s
- <variablelist>a stream.</variablelist>
- </indexterm><indexterm>direction
- <variablelist>either :INPUT or :OUTPUT.</variablelist>
- </indexterm><indexterm>fd
- <variablelist>a file descriptor, which is a non-negative integ=
erused by the OS to refer to an open file, socket, or similarI/O connection=
. NIL if there is no file descriptor associatedwith <literal>s</literal> i=
n the direction given by<literal>direction</literal>.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the file descriptor associated with
-<literal>s</literal> in the direction given by
-<literal>direction</literal>. It is necessary to specify
-<literal>direction</literal> because the input and output
-file descriptors may be different; the most common case is when
-one of them has been redirected by the Unix shell.</para>
- </sect2>
-
- <sect2 id=3D"STREAM-READ-IVECTOR">
- <para>STREAM-READ-IVECTOR</para>
- <informalfigure>stream-read-ivector</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>STREAM-READ-IVECTOR —</para>
- <para>Generic Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-stream-read-ivector
- stream ivector start-octet max-octets
-</programlisting>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Reads up to max-octets octets from stream into ivector,
-storing them at start-octet. Returns the number of octets actually
-read.</para>
- <bridgehead renderas=3D"sect3">Arguments</bridgehead>
- <term><indexterm>stream
- <variablelist>An input stream. The method defined onBUFFERED-I=
NPUT-STREAMs requires that the size in octets ofan instance of the stream's=
element type is 1.</variablelist>
- </indexterm><indexterm>ivector
- <variablelist>Any ivector.</variablelist>
- </indexterm><indexterm>start-octet
- <variablelist>A non-negative integer.</variablelist>
- </indexterm><indexterm>max-octets
- <variablelist>A non-negative integer. The return value may be =
lessthan the value of this parameter if EOF was encountered.</variablelist>
- </indexterm>
- </term>
- </sect2>
-
- <sect2 id=3D"STREAM-WRITE-IVECTOR">
- <para>STREAM-WRITE-IVECTOR</para>
- <informalfigure>stream-write-ivector</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>STREAM-WRITE-IVECTOR —</para>
- <para>Generic Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-stream-write-ivector stream
- ivector start-octet max-octets
-</programlisting>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Writes max-octets octets to stream from ivector, starting at
-start-octet. Returns max-octets.</para>
- <bridgehead renderas=3D"sect3">Arguments</bridgehead>
- <term><indexterm>stream
- <variablelist>An input stream. The method defined onBUFFERED-O=
UTPUT-STREAMs requires that the size in octets ofan instance of the stream'=
s element type is 1.</variablelist>
- </indexterm><indexterm>ivector
- <variablelist>Any ivector</variablelist>
- </indexterm><indexterm>start-octet
- <variablelist>A non-negative integer.</variablelist>
- </indexterm><indexterm>max-octet
- <variablelist>A non-negative integer.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Examples</bridgehead>
- <programlisting>
-;;; Write the contents of a (SIMPLE-ARRAY(UNSIGNED-BYTE 16) 3)
+ <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
+(let* ((a (make-array 3 =
:element-type '(unsigned-byte 16)
:initial-contents '(26725 27756 28449))))
(with-open-file (s "junk"
@@ -4692,20 +6951,20 @@
(read-line s)))
=
;;; Write a vector of DOUBLE-FLOATs. Note that (to maintain
-;;; alignment) there are 4 octets of padding before the 0th
-;;; element of a (VECTOR DOUBLE-FLOAT) in 32-bit OpenMCL.
-;;; (Note that (=3D (- ppc32::misc-dfloat-offset
-;;; ppc32::misc-data-offset) 4))
+;;; 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 &key (start 0) (end (length vector)))
+ (stream vector &key (start 0) (end (length vector)))
(check-type vector (vector double-float))
- (let* ((start-octet (+ (* start 8)
- (- target::misc-dfloat-offset
- target::misc-data-offset)))
+ (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)))
-</programlisting>
- </sect2>
+ (stream-write-ivector stream vector start-octet num-octets)))</program=
listing>
+ </refsect1>
+ </refentry>
</sect1>
</chapter>
=
@@ -5270,7 +7529,7 @@
=
<listitem>
<para>The argument/return values
- is <link linkend=3D"arb24">a MACPTR</link>.</para>
+ is <link linkend=3D""Referencing-and-Using-Foreign-Memory-Addresses">a M=
ACPTR</link>.</para>
</listitem>
</varlistentry>
=
@@ -5615,258 +7874,677 @@
</sect3>
=
<sect3 id=3D"iget-bit--Function-">
- <para>%get-bit [Function]</para>
- <term><indexterm>Syntax
- <variablelist>%get-bit ptr bit-offset</variablelist>
- </indexterm><indexterm>Description
- <variablelist>References and returns the bit-offsetth bit at=
the addressencapsulated by ptr. (Bit 0 at a given address is the mostsigni=
ficant bit of the byte at that address.) Can be used withSETF.</variablelis=
t>
- </indexterm><indexterm>Arguments
- <variablelist> =
- <term><indexterm>ptr
- <variablelist>A MACPTR</variablelist>
- </indexterm><indexterm>bit-offset
- <variablelist>A fixnum</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
+ <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> </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-">
- <para>%get-bitfield [Function]</para>
- <term><indexterm>Syntax
- <variablelist>%get-bitfield ptr bit-offset width</variableli=
st>
- </indexterm><indexterm>Description
- <variablelist>References and returns an unsigned integer com=
posed from thewidth bits found bit-offsetbits from the address encapsulated=
byptr. (The least significant bit of the result is the value of(%get-bit p=
tr (1- (+ bit-offset width)))). Can be used with SETF.</variablelist>
- </indexterm><indexterm>Arguments
- <variablelist> </variablelist>
- </indexterm><indexterm>ptr
- <variablelist>A MACPTR
- <term><indexterm>bit-offset
- <variablelist>A fixnum</variablelist>
- </indexterm><indexterm>width
- <variablelist>A positive fixnum</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
+ <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> </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 id=3D"iint-to-ptr--Function-">
- <para>%int-to-ptr [Function]</para>
- <term><indexterm>Syntax
- <variablelist>%int-to-ptr int</variablelist>
- </indexterm><indexterm>Description
- <variablelist>Creates and returns a MACPTR whose address mat=
ches int.</variablelist>
- </indexterm><indexterm>Arguments
- <variablelist> =
- <term><indexterm>int
- <variablelist>An (unsigned-byte 32)</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
- </sect3>
-
- <sect3 id=3D"iinc-ptr--Function-">
- <para>%inc-ptr [Function]</para>
- <term><indexterm>Syntax
- <variablelist>%inc-ptr ptr &optional (delta 1)</variable=
list>
- </indexterm><indexterm>Description
- <variablelist>Creates and returns a MACPTR whose address is =
the address ofptr plus delta. The idiom (%inc-ptr ptr 0) is sometimes used =
tocopy a MACPTR, e.g., to create a new MACPTR encapsulating the sameaddress=
as ptr.</variablelist>
- </indexterm><indexterm>Arguments
- <variablelist> =
- <term><indexterm>ptr
- <variablelist>A MACPTR</variablelist>
- </indexterm><indexterm>delta
- <variablelist>A fixnum</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
- </sect3>
-
- <sect3 id=3D"iptr-to-int--Function-">
- <para>%ptr-to-int [Function]</para>
- <term><indexterm>Syntax
- <variablelist>%ptr-to-int ptr</variablelist>
- </indexterm><indexterm>Description
- <variablelist>Returns the address encapsulated by ptr, as an=
(unsigned-byte 32).</variablelist>
- </indexterm><indexterm>Arguments
- <variablelist> =
- <term><indexterm>ptr
- <variablelist>A MACPTR</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
- </sect3>
-
- <sect3 id=3D"inull-ptr--Macro-">
- <para>%null-ptr [Macro]</para>
- <term><indexterm>Syntax
- <variablelist>%null-ptr</variablelist>
- </indexterm><indexterm>Description
- <variablelist>Equivalent to (%ptr-to-int 0).</variablelist>
- </indexterm>
- </term>
- </sect3>
-
- <sect3 id=3D"inull-ptr-p--Function-">
- <para>%null-ptr-p [Function]</para>
- <term><indexterm>Syntax
- <variablelist>%null-ptr-p ptr</variablelist>
- </indexterm><indexterm>Description
- <variablelist>Returns T If ptr is a MACPTR encapsulating the=
address 0,NIL if ptr encapsulates some other address.</variablelist>
- </indexterm><indexterm>Arguments
- <variablelist> =
- <term><indexterm>ptr
- <variablelist>A MACPTR</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
- </sect3>
-
- <sect3 id=3D"isetf-macptr--Function-">
- <para>%setf-macptr [Function]</para>
- <term><indexterm>Syntax
- <variablelist>%setf-macptr dest-ptr src-ptr</variablelist>
- </indexterm><indexterm>Description
- <variablelist>Causes dest-ptr to encapsulate the same addres=
s that src-ptrdoes, then returns dest-ptr.</variablelist>
- </indexterm><indexterm>Arguments
- <variablelist> =
- <term><indexterm>dest-ptr
- <variablelist>A MACPTR</variablelist>
- </indexterm><indexterm>src-ptr
- <variablelist>A MACPTR</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
- </sect3>
-
- <sect3 id=3D"iincf-ptr--Macro-">
- <para>%incf-ptr [Macro]</para>
- <term><indexterm>Syntax
- <variablelist>%incf-ptr ptr &optional (delta 1)</variabl=
elist>
- </indexterm><indexterm>Description
- <variablelist>Destructively modifies ptr, by adding delta to=
the addressit encapsulates. Returns ptr.</variablelist>
- </indexterm><indexterm>Arguments
- <variablelist> =
- <term><indexterm>ptr
- <variablelist>A MACPTR</variablelist>
- </indexterm><indexterm>delta
- <variablelist>A fixnum</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
- </sect3>
-
- <sect3 id=3D"with-macptrs--Macro-">
- <para>with-macptrs [Macro]</para>
- <term><indexterm>Syntax
- <variablelist>with-macptrs (var expr)* &body body</varia=
blelist>
- </indexterm><indexterm>Description
- <variablelist>Executes body in an environment in which each =
var is boundto a stack-allocated macptr which encapsulates the foreign addr=
essyielded by the corresponding expr. Returns whatever value(s) bodyreturns=
.</variablelist>
- </indexterm><indexterm>Arguments
- <variablelist> =
- <term><indexterm>var
- <variablelist>A symbol (variable name)</variablelist>
- </indexterm><indexterm>expr
- <variablelist>A MACPTR-valued expression</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
- </sect3>
-
- <sect3 id=3D"istack-block--Macro-">
- <para>%stack-block [Macro]</para>
- <term><indexterm>Syntax
- <variablelist>%stack-block (var expr)* &body body</varia=
blelist>
- </indexterm><indexterm>Description
- <variablelist>Executes body in an environment in which each =
var is boundto a stack-allocated macptr which encapsulates the address of a=
stack-allocated region of size expr bytes. Returns whatevervalue(s) body re=
turns.</variablelist>
- </indexterm><indexterm>Arguments
- <variablelist> =
- <term><indexterm>var
- <variablelist>A symbol (variable name)</variablelist>
- </indexterm><indexterm>expr
- <variablelist>An expression which should evaluate to a=
non-negativefixnum</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
- </sect3>
-
- <sect3 id=3D"make-cstring--Function-">
- <para>make-cstring [Function]</para>
- <term><indexterm>Syntax
- <variablelist>make-cstring string</variablelist>
- </indexterm><indexterm>Description
- <variablelist>Allocates a block of memory (via malloc) of le=
ngth (1+(length string)). Copies the string to this block and appends atrai=
ling NUL byte; returns a MACPTR to the block.</variablelist>
- </indexterm><indexterm>Arguments
- <variablelist> =
- <term><indexterm>string
- <variablelist>A lisp string</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
- </sect3>
-
- <sect3 id=3D"with-cstrs--Macro-">
- <para>with-cstrs [Macro]</para>
- <term><indexterm>Syntax
- <variablelist>with-cstrs (var string)* &body body</varia=
blelist>
- </indexterm><indexterm>Description
- <variablelist>Executes body in an environment in which each =
var is boundto a stack-allocated macptr which encapsulates the %address of =
astack-allocated region of into which each string (and a trailingNUL byte) =
has been copied. Returns whatever value(s) body returns.</variablelist>
- </indexterm><indexterm>Arguments
- <variablelist> =
- <term><indexterm>var
- <variablelist>A symbol (variable name)</variablelist>
- </indexterm><indexterm>string
- <variablelist>An expression which should evaluate to a=
lisp string</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
- </sect3>
-
- <sect3 id=3D"iget-cstring--Function-">
- <para>%get-cstring [Function]</para>
- <term><indexterm>Syntax
- <variablelist>%get-cstring ptr</variablelist>
- </indexterm><indexterm>Description
- <variablelist>Interprets ptr as a pointer to a (NUL -termina=
ted) C string;returns an equivalent lisp string.</variablelist>
- </indexterm><indexterm>Arguments
- <variablelist>
- <term><indexterm>ptr
- <variablelist>A MACPTR</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
- </sect3>
-
- <sect3 id=3D"istr-from-ptr--Function-">
- <para>%str-from-ptr [Function]</para>
- <term><indexterm>Syntax
- <variablelist>%str-from-ptr ptr length</variablelist>
- </indexterm><indexterm>Description
- <variablelist>Returns a lisp string of length <literal>lengt=
h</literal>,whose contents are initialized from the bytes at<literal> ptr.<=
/literal></variablelist>
- </indexterm><indexterm>Arguments
- <variablelist>
- <term><indexterm>ptr
- <variablelist>AMACPTR</variablelist>
- </indexterm><indexterm>length
- <variablelist>anon-negative fixnum</variablelist>
- </indexterm>
- </term></variablelist>
- </indexterm>
- </term>
- </sect3>
+ <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> </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 &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> </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> </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> </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> </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 &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> </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)* &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> </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)* &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> </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> </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)* &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> </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>
=
@@ -5884,11 +8562,15 @@
obtaining current interface database files.</para>
<para>Not surprisingly, different platforms use different database=
files.</para>
<para>OpenMCL defines reader macros that consult these databases:<=
/para>
- <listitem mark=3D"bullet">
- <variablelist>#$foo looks up the value of the constant definitio=
n of FIXTHIS</variablelist>
- <variablelist>#_foo looks up the foreign function definition for=
FIXTHIS</variablelist>
+ <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>
=
- </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
@@ -6026,172 +8708,255 @@
used instead.</para>
<para>To create a new interface directory, "foo", and a set of
database files in that directory:</para>
- <varlistentry numeration=3D"arabic">
- <variablelist>Create a subdirectory of "ccl:headers;" named"foo"=
.</variablelist>
- <variablelist>Create a subdirectory of "ccl:headers;foo;" named"=
C".</variablelist>
- <variablelist>Create a file in "ccl:headers;foo;C;" named"popula=
te.sh".One way of accomplishing the above steps is:
- <programlisting>
-? (close (open "ccl:headers;foo;C;populate.sh" :direction :output :
- if-does-not-exist :create :if-exists :overwrite))
-</programlisting></variablelist>
- <variablelist>Edit the file created above, using the "populate.s=
h"files in the distribution as guidelines.The file might wind up looking so=
mething like:
- <programlisting>
-#/bin/sh
-h-to-ffi.sh `foo-config -cflags` /usr/include/foo/foo.h
-</programlisting></variablelist>
- </varlistentry>
- <para>Refer to =
-for information about running the
-interface translator and .ffi parser.</para>
- <para>Assuming that all went well, there should now be .cdb files =
in
-"ccl:headers;foo;". You can then do
-<code>(use-interface-dir :foo)</code> whenever you need to
-access the foreign type information in those database files.</para>
+ <orderedlist continuation=3D"restarts" inheritnum=3D"ignore">
+ <listitem>
+ <para>Create a subdirectory of "ccl:headers;" named
+ "foo".</para>
+ </listitem>
+
+ <listitem>
+ <para>Create a subdirectory of "ccl:headers;foo;" named
+ "C".</para>
+ </listitem>
+
+ <listitem>
+ <para>Create a file in "ccl:headers;foo;C;" named
+ "populate.sh".</para>
+
+ <para>One way of accomplishing the above steps is:</para>
+
+ <programlisting format=3D"linespecific">? (close (open "ccl:heade=
rs;foo;C;populate.sh" :direction :output :
+ if-does-not-exist :create :if-exists :overwrite))</programl=
isting>
+ </listitem>
+
+ <listitem>
+ <para>Edit the file created above, using the "populate.sh"
+ 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">
- <para>Using Shared Libraries</para>
-
- <sect2 id=3D"Overview--13-">
- <para>Overview
-OpenMCL provides facilities to open and close shared libraries.</para>
- <para>"Opening" a shared library, which is done with
-, maps the library's
-code and
-data into OpenMCL's address space and makes its exported symbols
-accessible to OpenMCL.</para>
- <para>"Closing" a shared library, which is done with
-, unmaps the
-library's code and
-data and removes the library's symbols from the global namespace.</para>
- <para>A small number of shared libraries (including libc, libm, li=
bdl
-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 i=
n 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.</par=
a>
- <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.</pa=
ra>
- <para>All of the global symbols described below are exported from =
the CCL
-package.</para>
+ <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-">
- <para>Limitations and known bugs</para>
- <listitem mark=3D"bullet">
- <variablelist>Don't get me started.</variablelist>
- <variablelist>The underlying functionality has a poor notion of =
dependency;it's not always possible to open libraries that depend on unopen=
edlibraries, but it's possible to close libraries on which otherlibraries d=
epend.It <emphasis>may</emphasis> be possible to generate moreexplicit depe=
ndency information by parsing the output of the Linux lddand ldconfig progr=
ams.</variablelist>
+ <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>
=
- </listitem>
+ </itemizedlist>
</sect2>
=
<sect2 id=3D"Darwin-Notes">
- <para>Darwin Notes
-Darwin shared libraries come in two (basic) flavors:</para>
- <listitem mark=3D"bullet">
- <variablelist>"dylibs" (which often have the extension".dylib") =
are primarily intended to be linked against atcompile/link time. They can b=
e loaded dynamically,<emphasis>but can't be unloaded</emphasis>. Accordingl=
y,OPEN-SHARED-LIBRARY can be used to open a .dylib-style library;calling CL=
OSE-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 .dylibs=
hared-libraries that are already open can cause memory corruptionunless the=
full pathname of the .dylib file is specified on thefirst and all subseque=
nt calls.</variablelist>
- <variablelist>"bundles" are intended to serve as applicationexte=
nsions; they can be opened multiple times (creating multipleinstances of th=
e library!) and closed properly.</variablelist>
- =
- </listitem>
- <para>Thanks to Michael Klingbeil for getting both kinds of Darwin=
shared
-libraries working in OpenMCL.</para>
+ <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">
- <para>The Interface Translator</para>
-
- <sect2 id=3D"Overview--14-">
- <para>Overview
-OpenMCL uses an interface translation system based on the FFIGEN
-system, which is described at
-http://www.ccs.neu.edu/home/lth/ffigen/.
-The interface translator makes
-the constant, type, structure, and function definitions in a set of
-C-language header files available to lisp code.</para>
- <para>The basic idea of the FFIGEN scheme is to use the C compiler=
's
-frontend and parser to translate .h files into semantically equivalent
-.ffi files, which represent the definitions from the headers using a
-syntax based on S-expressions.
-Lisp code can then concentrate on
-the .ffi representation, without having to concern itself with the
-semantics of header file inclusion or the arcana of C parsing.</para>
- <para>The original FFIGEN system used a modified version of the LC=
C 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 th=
e 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.ta=
r.gz.</para>
- <para>For Darwin, the binary of the older FFIGEN is available at f=
tp://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 packa=
ges)
-called h-to-ffi.sh reads a specified .h file (and optional
-preprocessor arguments) and writes a (hopefully) equivalent .ffi file to
-standard output, calling the installed C preprocessor and the ffigen
-program with appropriate arguments.</para>
- <para>For each interface directory (see )
-<emphasis>subdir</emphasis> distributed with OpenMCL, a shell script
-(distributed with OpenMCL as "ccl:headers;<emphasis>subdir</emphasis>;C;po=
pulate.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</emphas=
is>;C;<emphasis>system</emphasis>;<emphasis>header</emphasis>;<emphasis>pat=
h</emphasis>;"
-(or "ccl:darwin-headers;<emphasis>subdir</emphasis>;C;<emphasis>system</em=
phasis>;<emphasis>header</emphasis>;<emphasis>path</emphasis>;"),
-populating that directory with .ffi files.</para>
+ <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 an=
d are
-used in the expansion of RREF, RLET, and related macros.</para>
+ 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">
- <para>Details: rebuilding the CDB databases, step by step</para>
- <varlistentry numeration=3D"arabic">
- <variablelist>Ensure that the FFIGEN program is installed. See t=
he"README" file in the source or binary archive for specificinstallation in=
structions.This example assumes LinuxPPC; for 32-bit DarwinPPC, substitute"=
ccl:darwin-headers;" for "ccl:headers;". For 64-bit DarwinPPC,substitute =
"ccl:darwin-headers64;".</variablelist>
- <variablelist>Edit the "ccl:headers;<emphasis>subdir</emphasis>;=
C;populate.sh"shell script. When you're confident that the files andpreproc=
essor options match your environment, cd to the"ccl:headers;<emphasis>subdi=
r</emphasis>;C;" directory andinvoke ./populate.sh. Repeat this step until =
you're able tocleanly translate all files refrenced in the shell script.</v=
ariablelist>
- <variablelist>Run OpenMCL:
+ <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
@@ -6200,55 +8965,55 @@
;;; lots of output ... after a while, shiny new .cdb files should
;;; appear in "ccl:headers;subdir;"
;;; (or "ccl:darwin-headers;subdir;" under Darwin)
-</programlisting></variablelist>
- </varlistentry>
- <para>PARSE-STANDARD-FFI-FILES accepts a :PREPEND-UNDERSCORES keyw=
ord
-argument. Darwin (and some other platforms) use a convention wherein the
-symbols associated with C-visible external function and variables have
-underscore characters prepended to their names. When this argument is
-true, PARSE-STANDARD-FFI-FILES will prepend underscores to all foreign
-function names written to the database, so that (#_foo ...) expands into
-an EXTERNAL-CALL to "_foo".</para>
+</programlisting></para>
+ </listitem>
+ </orderedlist>
</sect2>
</sect1>
=
<sect1 id=3D"Case-sensitivity-of-foreign-names-in-OpenMCL">
- <para>Case-sensitivity of foreign names in OpenMCL</para>
-
- <sect2 id=3D"Overview--15-">
- <para>Overview
-As of release 0.11, OpenMCL addresses the fact that foreign type,
-constant, record, field, and function nams are case-sensitive and provides
-mechanisms to refer to these names via lisp symbols.</para>
- <para>Previous versions of OpenMCL have tried to ignore that fact,=
under
-the belief that case conflicts were rare and that many users (and
-implementors) would prefer not to deal with case-related issues. The fact
-that some information in the interface databases was incomplete or
-inaccessable because of this policy made it clearer that the policy was
-untenable. I can't claim that the approach described here is
-aesthetically pleasing, but I can honestly say that it's less
-unpleasant than other approaches that I'd thought of. I'd be
-interested to hear alternate proposals.</para>
- <para>The issues described here have to do with how lisp symbols a=
re 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>
+ <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">
- <para>Foreign constant and function names
-The primary way of referring to foreign constant and function names
-in OpenMCL is via the #$ and #_ reader macros. These reader macro
-functions each read a symbol into the "OS" package, look up its
-constant or function definition in the interface database, and assign the
-value of the constant to the symbol or install a macroexpansion function
-on the symbol.</para>
- <para>In order to observe case-sensitivity, the reader-macros now =
read the
-symbol with (READTABLE-CASE :PRESERVE) in effect.</para>
- <para>This means that it's necessary to type the foreign constant =
or
-function name in correct case, but it isn't necessary to use any
-special escaping constructs when writing the variable name. For instance:<=
/para>
+ <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
@@ -6259,79 +9024,99 @@
</sect2>
=
<sect2 id=3D"Foreign-type--record--and-field-names">
- <para>Foreign type, record, and field names
-Constructs like RLET expect a foreign type or record name to be
-denoted by a symbol (typically a keyword); RREF (and PREF) expect an
-"accessor" form, typically a keyword formed by concatenating a
-foreign type or record name with a sequence of one or more foreign field
-names, separated by dots. These names are interned by the reader as other
-lisp symbols are, with an arbitrary value of READTABLE-CASE in effect
-(typically :UPCASE.) It seems like it would be very tedious to force users
-to manually escape (via vertical bar or backslash syntax) all lowercase
-characters in symbols used to specify foreign type, record, and field
-names (especially given that many traditional POSIX structure, type, and
-field names are entirely lowercase.)</para>
- <para>The approach taken by OpenMCL is to allow the symbols (keywo=
rds)
-used to denote foreign type, record, and field names to contain angle
-brackets (< and >). Such symbols are translated to foreign names
-via the following set of conventions:</para>
- <listitem mark=3D"bullet">
- <variablelist>All instances of < and > in the symbol's pname are=
balanced and don't nest.</variablelist>
- <variablelist>Any alphabetic characters in the symbol's pname th=
ataren't enclosed in angle brackets are treated as lower-case,regardless of=
the value of READTABLE-CASE and regardless of the casein which they were w=
ritten.</variablelist>
- <variablelist>Alphabetic characters that appear within angle bra=
ckets aremapped to upper-case, again regardless of how they were written or=
interned.</variablelist>
- =
- </listitem>
- <para>There may be many ways of "escaping" (with angle brackets)
-sequences of upper-case and non-lower-case characters in a symbol used to
-denote a foreign name. When translating in the other direction, OpenMCL
-always escapes the longest sequence that starts with an upper-case
-character and doesn't contain a lower-case character.</para>
- <para>It's often preferable to use this canonical form of a foreign
-type name.</para>
- <para>The accessor forms used by PREF/RREF should be viewed as a s=
eries 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 typ=
e,
-record, and field names; there are only a few cases in the OpenMCL sources
-where mixed-case names need to be escaped.</para>
+ <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><</literal> and
+ <literal>></literal>). Such symbols are translated to
+ foreign names via the following set of conventions:</para>
+ <itemizedlist>
+ <listitem>
+ <para>All instances of < and > 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-">
- <para>Examples</para>
+ <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 :<w>indow)) ...)
+(rlet ((w :<w>indow)) ...)
;;; This is equivalent to the last example
-(rlet ((w :<w>INDOW)))
+(rlet ((w :<w>INDOW)))
</programlisting>
</sect2>
</sect1>
=
<sect1 id=3D"Tutorial--Using-Basic-Calls-and-Types">
- <para>Tutorial: Using Basic Calls and Types
-This tutorial is meant to cover the basics of OpenMCL for calling
-external C functions and passing data back and forth. These basics
-will provide the foundation for more advanced techniques which will
-allow access to the various external libraries and toolkits.</para>
- <para>The first step is to start with a simple C dynamic library in =
order to
-actually observe what is actually passing between OpenMCL and C. So,
-some C code is in order:</para>
- <para>Create the file typetest.c, and put the following code into it=
:</para>
+ <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 <stdio.h>
+#include <stdio.>
=
void
void_void_test(void)
{
printf("Entered %s:\n", __FUNCTION__);
printf("Exited %s:\n", __FUNCTION__);
+ fflush(stdout);
}
=
signed char
@@ -6340,6 +9125,7 @@
printf("Entered %s:\n", __FUNCTION__);
printf("Data In: %d\n", (signed int)data);
printf("Exited %s:\n", __FUNCTION__);
+ fflush(stdout);
return data;
}
=
@@ -6349,128 +9135,125 @@
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, noti=
ce
-that there's no <literal>main()</literal>, because we're just
-building a library, not an executable.</para>
- <para>The function <literal>void_void_test()</literal> doesn't take
-any parameters, and doesn't return anything, but it prints two
-lines to let us know it was called.
-<literal>sc_sc_test()</literal> takes a signed char as a
-parameter, prints it, and returns it.
-<literal>uc_uc_test()</literal> does the same thing, but with
-an unsigned char. Their purpose is just to prove to us
-that we really can call C functions, pass them values, and get
-values back from them.</para>
- <para><inlinemediaobject name=3D"arb36"></inlinemediaobject></para>
- <para>This code is compiled into a dynamic library on OS X 10.3.4 wi=
th the
-command:</para>
+ </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")
+#<SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
</programlisting>
- <para>The -dynamiclib tells gcc that we will be compiling this into a
-dynamic library and not an executable binary program. The output
-filename is "libtypetest.dylib". Notice that we chose a name which
-follows the normal OS X convention, being in the form
-"libXXXXX.dylib", so that other programs can link to the library.
-OpenMCL doesn't need it to be this way, but it is a good idea to
-adhere to existing conventions.</para>
- <para>The -install_name flag is primarily used when
-building OS X "bundles". In this case, we are not using it, so we
-put a placeholder into it, "./libtypetest.dylib". If we wanted
-to use typetest in a bundle, the -install_name argument would
-be a relative path from some "current" directory.</para>
- <para>After creating this library, the first step is to tell OpenMCL=
to open
-the dynamic library. This is done by calling
-.</para>
- <programlisting>
-
-Welcome to OpenMCL Version (Beta: Darwin) 0.14.2-040506!
-
-? (open-shared-library "/Users/andewl/openmcl/libtypetest.dylib")
-#<SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
-</programlisting>
- <para>You should use an absolute path here; using a relative one, su=
ch
-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>You should use an absolute path here; using a relative
+ one, such as just "libtypetest.dylib", would appear to work, but
+ there are subtle problems which occur after reloading it. See
+ the Darwin notes on for details. It would be a bad idea anyway,
+ because software should never rely on its starting directory
+ being anything in particular.</para>
<para>This command returns a reference to the opened shared library,=
and
OpenMCL also adds one to the global variable
<literal>ccl::*shared-libraries*</literal>:</para>
<programlisting>
=
? ccl::*shared-libraries*
-(#<SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
- #<SHLIB /usr/lib/libSystem.B.dylib #x606179E>)
-</programlisting>
- <para>Before we call anything, let's check that the individual funct=
ions can
-actually be found by the system. We don't have to do this, but
-it helps to know how to find out whether this is the problem,
-when something goes wrong.
-We use :</para>
+(#<SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
+ #<SHLIB /usr/lib/libSystem.B.dylib #x606179E>)
+ </programlisting>
+ <para>Before we call anything, let's check that the individual
+ functions can actually be found by the system. We don't have to
+ do this, but it helps to know how to find out whether this is
+ the problem, when something goes wrong. We use <xref
+ linkend=3D"m_external-call"/>:</para>
<programlisting>
=
? (external "_void_void_test")
-#<EXTERNAL-ENTRY-POINT "_void_void_test" (#x000CFDF8) /Users/andewl/openmc=
l/libtypetest.dylib #x638EDF6>
+#<EXTERNAL-ENTRY-POINT "_void_void_test" (#x000CFDF8) /Users/andewl/ope=
nmcl/libtypetest.dylib #x638EDF6>
=
? (external "_sc_sc_test")
-#<EXTERNAL-ENTRY-POINT "_sc_sc_test" (#x000CFE50) /Users/andewl/openmcl/li=
btypetest.dylib #x638EB3E>
+#<EXTERNAL-ENTRY-POINT "_sc_sc_test" (#x000CFE50) /Users/andewl/openmcl=
/libtypetest.dylib #x638EB3E>
=
? (external "_uc_uc_test")
-#<EXTERNAL-ENTRY-POINT "_uc_uc_test" (#x000CFED4) /Users/andewl/openmcl/li=
btypetest.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>
+#<EXTERNAL-ENTRY-POINT "_uc_uc_test" (#x000CFED4) /Users/andewl/openmcl=
/libtypetest.dylib #x638E626>
+ </programlisting>
+ <para>Notice that the actual function names have been "mangled"
+ by the C linker. The first function was named "void_void_test"
+ in typetest.c, but in libtypetest.dylib, it has an underscore (a
+ "_" symbol) before it: "_void_void_test". So, this is the name
+ which you have to use. The mangling - the way the name is
+ changed - may be different for other operating systems or other
+ versions, so you need to "just know" how it's done...</para>
+ <para>Also, pay particular attention to the fact that a
+ hexadecimal value appears in the EXTERNAL-ENTRY-POINT.
+ (#x000CFDF8, for example - but what it is doesn't matter.)
+ These hex numbers mean that the function can be dereferenced.
+ Functions which aren't found will not have a hex number. For
+ example:</para>
<programlisting>
=
? (external "functiondoesnotexist")
-#<EXTERNAL-ENTRY-POINT "functiondoesnotexist" {unresolved} #x638E3F6>
+#<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>.</par=
a>
- <para>At this point, we are ready to try our first external function
-call:</para>
+ function, which means you would get an error, "Can't resolve foreign
+ symbol," if you tried to call it.</para>
+ <para>These external function references also are stored in a
+ hash table which is accessible through a global variable,
+ <literal>ccl::*eeps*</literal>.</para>
+ <para>At this point, we are ready to try our first external
+ function call:</para>
<programlisting>
=
? (external-call "_void_void_test" :void)
Entered void_void_test:
Exited void_void_test:
NIL
-</programlisting>
- <para>We used , which is
-is the normal mechanism for
-accessing externally linked code. The "_void_void_test"
-is the mangled name of the external function.
-The :void
-refers to the return type of the function.</para>
- <para>If you're using ILISP to run OpenMCL inside of Emacs, you won't
-see the "Entered" and "Exited" lines until you quit (as of
-July 2004). It's not
-clear why this is, but it's a pity. If you want to see them, run
-OpenMCL from Terminal.app or in some other way.</para>
+ </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>
@@ -6481,13 +9264,12 @@
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>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>
+ the range which fits in one byte:</para>
<programlisting>
=
? (external-call "_sc_sc_test" :signed-byte -567 :signed-byte)
@@ -6496,8 +9278,8 @@
Exited sc_sc_test:
-55
</programlisting>
- <para>Hmmmm. A little odd. Let's look at the unsigned stuff
-to see how it reacts:</para>
+ <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)
@@ -6520,21 +9302,22 @@
Data In: 201
Exited uc_uc_test:
201
-</programlisting>
+ </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>
+ 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 foll=
owing
-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>
+ 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>
=
@@ -6544,6 +9327,7 @@
printf("Entered %s:\n", __FUNCTION__);
printf("Data In: %d\n", data);
printf("Exited %s:\n", __FUNCTION__);
+ fflush(stdout);
return data;
}
=
@@ -6553,6 +9337,7 @@
printf("Entered %s:\n", __FUNCTION__);
printf("Data In: %ld\n", data);
printf("Exited %s:\n", __FUNCTION__);
+ fflush(stdout);
return data;
}
=
@@ -6562,6 +9347,7 @@
printf("Entered %s:\n", __FUNCTION__);
printf("Data In: %lld\n", data);
printf("Exited %s:\n", __FUNCTION__);
+ fflush(stdout);
return data;
}
=
@@ -6571,6 +9357,7 @@
printf("Entered %s:\n", __FUNCTION__);
printf("Data In: %e\n", data);
printf("Exited %s:\n", __FUNCTION__);
+ fflush(stdout);
return data;
}
=
@@ -6580,6 +9367,7 @@
printf("Entered %s:\n", __FUNCTION__);
printf("Data In: %e\n", data);
printf("Exited %s:\n", __FUNCTION__);
+ fflush(stdout);
return data;
}
</programlisting>
@@ -6589,15 +9377,16 @@
gcc -dynamiclib -Wall -o libtypetest.dylib typetest.c \
-install_name ./libtypetest.dylib
</programlisting>
- <para>Now, restart OpenMCL. This step is required because OpenMCL c=
annot
-close and reload a dynamic library on OS X.</para>
+ <para>Now, restart OpenMCL. This step is required because
+ OpenMCL cannot close and reload a dynamic library on OS
+ X.</para>
<para>Have you restarted? Okay, try out the new code:</para>
<programlisting>
=
Welcome to OpenMCL Version (Beta: Darwin) 0.14.2-040506!
=
? (open-shared-library "/Users/andewl/openmcl/libtypetest.dylib")
-#<SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
+#<SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
=
? (external-call "_si_si_test" :signed-fullword -178965 :signed-fullword)
Entered si_si_test:
@@ -6605,7 +9394,7 @@
Exited si_si_test:
-178965
=
-? ;; long is the same size as int
+? ;; 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
@@ -6619,11 +9408,12 @@
Exited sll_sll_test:
-973891578912
</programlisting>
- <para>Okay, everything seems to be acting as expected. However, jus=
t 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>
+ <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"
@@ -6632,17 +9422,19 @@
Data In: -227
Exited sl_sl_test:
-974957576192
-</programlisting>
- <para>Ouch. The C function changes the value with no warning that s=
omething
-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 n=
umbers.</para>
+ </programlisting>
+ <para>Ouch. The C function changes the value with no warning
+ that something is wrong. Even worse, it manages to pass the
+ original value back to OpenMCL, which hides the fact that
+ something is wrong.</para>
+ <para>Finally, let's take a look at doing this with
+ floating-point numbers.</para>
<programlisting>
=
Welcome to OpenMCL Version (Beta: Darwin) 0.14.2-040506!
=
? (open-shared-library "/Users/andewl/openmcl/libtypetest.dylib")
-#<SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
+#<SHLIB /Users/andewl/openmcl/libtypetest.dylib #x638EF3E>
=
? (external-call "_f_f_test" :single-float -1.256791e+11 :single-float)
Entered f_f_test:
@@ -6655,7 +9447,7 @@
Data In: -1.256791e+290
Exited d_d_test:
-1.256791D+290
-</programlisting>
+ </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
@@ -6669,90 +9461,89 @@
to pass more complex data structures around.</para>
=
<sect2 id=3D"Acknowledgement">
- <para>Acknowledgement
-This chapter was generously contributed by
-Andrew P. Lentvorski Jr.</para>
+ <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">
- <para>Tutorial: Allocating Foreign Data on the Lisp Heap
-Not every foreign function is so marvelously easy to use as the
-ones we saw in the last section. Some of them require you to
-allocate a C struct, fill it in with your own information, and
-pass it a pointer to the struct. Some of them require you to
-allocate an empty struct so they can fill it in, and then you can
-read the information out of it.</para>
- <para>Also, some of them have their own structs and return a pointer=
to
-that same struct every time you call them, but those are easier to
-deal with,
-so they won't
-be covered in this section.</para>
- <para>You might know that Lisp (and, indeed, most programming langua=
ges)
-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 p=
laced
-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 lo=
se
-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>
+ <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>
+ 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>
+ is to create a local dynamic library in order to help show
+ what is actually going on between OpenMCL and C. So, create the file
+ ptrtest.c, with the following code:</para>
<programlisting>
-#include <stdio.h>
+#include <stdio.h>
=
void reverse_int_array(int * data, unsigned int dataobjs)
{
int i, t;
=
- for(i=3D0; i<dataobjs/2; i++)
+ for(i=3D0; i<dataobjs/2; i++)
{
t =3D *(data+i);
*(data+i) =3D *(data+dataobjs-1-i);
@@ -6765,7 +9556,7 @@
int *t;
int i;
=
- for(i=3D0; i<ptrobjs/2; i++)
+ for(i=3D0; i<ptrobjs/2; i++)
{
t =3D *(ptrs+i);
*(ptrs+i) =3D *(ptrs+ptrobjs-1-i);
@@ -6781,26 +9572,27 @@
reverse_int_array(*(ptrs+0), 4);
reverse_int_array(*(ptrs+1), 4);
}
-</programlisting>
- <para>This defines three functions. <literal>reverse_int_array</lit=
eral>
-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 comman=
d:</para>
+ </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>
+ </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>
@@ -6824,15 +9616,15 @@
(setf ,mp nil)))
DISPOSE-HEAP-IVECTOR
</programlisting>
- <para>You don't understand how those functions do what they do. Tha=
t'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 prima=
ry
-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>
+ <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)
@@ -6842,29 +9634,25 @@
;Compiler warnings :
; Undeclared free variable A, in an anonymous lambda form.
; Undeclared free variable AP, in an anonymous lambda form.
-#<A Mac Pointer #x10217C>
+#<A Mac Pointer #x10217C>
=
? a
#(1396 2578 97862649)
=
? ap
-#<A Mac Pointer #x10217C>
+#<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>
+ <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)
@@ -6884,8 +9672,8 @@
? a
#(3 4 5)
</programlisting>
- <para>In addition, the <literal>macptr</literal> allows direct acces=
s to the same
-memory:</para>
+ <para>In addition, the <literal>macptr</literal> allows direct
+ access to the same memory:</para>
<programlisting>
? (setq *byte-length-of-long* 4)
4
@@ -6905,42 +9693,41 @@
? ;; 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 d=
one 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>
+ <para>So far, there is nothing about this object that could not
+ be done much better with standard Lisp. However, the
+ <literal>macptr</literal> can be used to pass this chunk of
+ memory off to a C function. Let's use the C code to reverse the
+ elements in the array:</para>
<programlisting>
? ;; Insert the full path to your copy of libptrtest.dylib
(open-shared-library "/Users/andrewl/openmcl/openmcl/gtk/libptrtest.dylib")
-#<SHLIB /Users/andrewl/openmcl/openmcl/gtk/libptrtest.dylib #x639D1E6>
+#<SHLIB /Users/andrewl/openmcl/openmcl/gtk/libptrtest.dylib #x639D1E6>
=
? a
#(6 4 7)
=
? ap
-#<A Mac Pointer #x10217C>
+#<A Mac Pointer #x10217C>
=
? (external-call "_reverse_int_array" :address ap :unsigned-int (length a)=
:address)
-#<A Mac Pointer #x10217C>
+#<A Mac Pointer #x10217C>
=
? a
#(7 4 6)
=
? ap
-#<A Mac Pointer #x10217C>
+#<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 m=
oving
-on, the memory needs to be deallocated:</para>
+ <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
@@ -6962,62 +9749,59 @@
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>
+ 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 th=
is
-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 yo=
u 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>
+ 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>
+ <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)
@@ -7042,791 +9826,1369 @@
(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 a=
s 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, a=
nd
-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>
+ </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-">
- <para>Acknowledgement
-Much of this chapter was generously contributed by
-Andrew P. LentvorskiJr.</para>
+ <title>Acknowledgement</title>
+ <para>Much of this chapter was generously contributed by
+ Andrew P. Lentvorski Jr.</para>
</sect2>
</sect1>
=
- <sect1 id=3D"The-Foreign-Function-Interface-Dictionary">
- <para>The Foreign-Function-Interface Dictionary</para>
-
- <sect2 id=3D"DEF-FOREIGN-TYPE">
- <para>DEF-FOREIGN-TYPE</para>
- <informalfigure>def-foreign-type</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>DEF-FOREIGN-TYPE —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- def-foreign-type name foreign-type-spec
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>name
- <variablelist>NIL or a keyword; the keyword may containescapin=
g constructs (see ).</variablelist>
- </indexterm><indexterm>foreign-type-spec
- <variablelist>A foreign type specifier, whose syntax is (loose=
ly)defined above.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>If name is non-NIL, defines name to be an alias for the
-foreign type specified by foreign-type-spec. If foreign-type-spec
-is a named structure or union type, additionally defines that
-structure or union type.</para>
- <para>If name is NIL, foreign-type-spec must be a named foreign
-struct or union definition, in which case the foreign structure
-or
-union definition is put in effect.</para>
- <para>Note that there are two separate namespaces for foreign
-type names, one for the names of ordinary types and one for
-the names of structs and unions. Which one
-<literal>name</literal> refers to depends on
-<literal>foreign-type-spec</literal> in the obvious manner.</para>
- </sect2>
-
- <sect2 id=3D"MAKE-RECORD">
- <para>MAKE-RECORD</para>
- <informalfigure>make-record</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>MAKE-RECORD —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- make-record typespec
- &rest initforms =3D> result
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>typespec
- <variablelist>A foreign type specifier, or a keyword which is =
usedas the name of a foreign struct or union.</variablelist>
- </indexterm><indexterm>initforms
- <variablelist>If the type denoted by <literal>typespec</litera=
l>is scalar, a single value appropriate for that type;otherwise, a list of =
alternating field names andvalues appropriate for the types of those fields=
.</variablelist>
- </indexterm><indexterm>result
- <variablelist>A <literal>macptr</literal> which encapsulates t=
he address of anewly-allocated record on the foreign heap.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Expands into code which allocates and initalizes
-an instance of the type
-denoted by <literal>typespec</literal>, on the foreign
-heap. The record is allocated using the C function
-<literal>malloc</literal>, and the user of
-<literal>make-record</literal> must explicitly call
-the C function <literal>free</literal> to deallocate the
-record, when it is no longer needed.</para>
- <para>If <literal>initforms</literal> is provided, its value
-or values are used in the initialization. When the type
-is a scalar, <literal>initforms</literal> is either a single
-value which can be coerced to that type, or no value, in which
-case binary 0 is used. When the type is a <literal>struct</literal>,
-<literal>initforms</literal> is a list, giving field names
-and the values for each. Each field is treated in the same way
-as a scalar is: If a value for it is given, it must be
-coerceable to the field's type; if not, binary 0 is used.</para>
- <para>When the type is an array, <literal>initforms</literal> may
-not be provided, because <literal>make-record</literal>
-cannot initialize its values. <literal>make-record</literal>
-is also unable to initialize fields of a <literal>struct</literal>
-which are themselves
-<literal>struct</literal>s. The user of
-<literal>make-record</literal> should set these values
-by another means.</para>
- <para>A possibly-significant limitation is that it must be possibl=
e to
-find the foreign type at the time the macro is expanded;
-<literal>make-record</literal> signals an error if this is
-not the case.</para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para>It is inconvenient that <literal>make-record</literal> is a
-macro, because this means that <literal>typespec</literal>
-cannot be a variable; it must be an immediate value.</para>
- <para>If it weren't for this requirement,
-<literal>make-record</literal> could be a function. However,
-that would mean that any stand-alone application using it would
-have to include a copy of the interface database
-(see The Interface Database), which is undesireable
-because it's large.</para>
- </sect2>
-
- <sect2 id=3D"RLET">
- <para>RLET</para>
- <informalfigure>rlet</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>RLET —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- rlet (var typespec &rest initforms)*
- &body body
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>var
- <variablelist>A symbol (a lisp variable)</variablelist>
- </indexterm><indexterm>typespec
- <variablelist>A foreign type specifier or foreign record name.=
</variablelist>
- </indexterm><indexterm>initforms
- <variablelist>As described above, for</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Executes <literal>body</literal>
-in an environment in which each var is bound
-to a MACPTR (see ) encapsulating the
-address of a stack-allocated foreign memory block, allocated and
-initialized from typespec and initforms as per
-.
-Returns whatever value(s) <literal>body</literal>
-returns.</para>
- <para>Record fields that aren't explicitly initialized have
-unspecified contents.</para>
- </sect2>
-
- <sect2 id=3D"RLETZ">
- <para>RLETZ</para>
- <informalfigure>rletz</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>RLETZ —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- rletz (var typespec &rest initforms)*
- &body body
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>var
- <variablelist>A symbol (a lisp variable)</variablelist>
- </indexterm><indexterm>typespec
- <variablelist>A foreign type specifier or foreign record name.=
</variablelist>
- </indexterm><indexterm>initforms
- <variablelist>As described above, for ccl:make-record</variabl=
elist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Executes body in an environment in which each var is bound
-to a MACPTR (see ) encapuslating the
-address of a stack-allocated foreign memory block, allocated and
-initialized from typespec and initforms as
-ccl:make-record.</para>
- <para>Returns whatever value(s) body returns.</para>
- <para>Unlike rlet, record fields that aren't explicitly
-initialized are set to binary 0.</para>
- </sect2>
-
- <sect2 id=3D"PREF">
- <para>PREF</para>
- <informalfigure>pref</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>PREF —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- pref ptr accessor-form
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>ptr
- <variablelist>a MACPTR (see ).</variablelist>
- </indexterm><indexterm>accessor-form
- <variablelist>a keyword which names a foreign type or record, =
asdescribed in .</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>References an instance of a foreign type (or a component of
-a foreign type) accessible via ptr.</para>
- <para>Expands into code which references the indicated scalar type
-or component, or returns a pointer to a composite type.</para>
- <para>PREF can be used with SETF.</para>
- <para>RREF is a deprecated alternative to PREF. It accepts a
-:STORAGE keyword and rather loudly ignores it.</para>
- </sect2>
-
- <sect2 id=3D"OPEN-SHARED-LIBRARY">
- <para>OPEN-SHARED-LIBRARY</para>
- <informalfigure>open-shared-library</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>OPEN-SHARED-LIBRARY — Asks the operating system to loa=
d a shared library
-for OpenMCL to use.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- open-shared-library name =3D> library
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>name
- <variablelist>A SIMPLE-STRING which is presumed to be the so-n=
ame ofor a filesystem path to the library.</variablelist>
- </indexterm><indexterm>library
- <variablelist>An object of type SHLIB which describes thelibra=
ry denoted by <literal>name</literal>.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>If the library denoted by <literal>name</literal> can
-be loaded by the
-operating system, returns an object of type SHLIB that describes
-the library; if the library is already open, increments a
-reference count. If the library can't be loaded, signals a
-SIMPLE-ERROR which contains an often-cryptic message from the
-operating system.</para>
- <bridgehead renderas=3D"sect3">Examples</bridgehead>
- <programlisting>
-;;; Try to do something simple.
-? (open-shared-library "libgtk.so")
-> Error: Error opening shared library "libgtk.so": /usr/lib/libgtk.so: und=
efined symbol: gdk_threads_mutex
-> While executing: OPEN-SHARED-LIBRARY
-
-;;; Grovel around, curse, and try to find out where "gdk_threads_mutex"
+ <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"arb30">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"arb25"/>), which is undesireable
+ 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'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'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"arb45"/>.
+ </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'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 "libgtk.so")
+> Error: Error opening shared library "libgtk.so": /usr/lib/li=
bgtk.so: undefined symbol: gdk_threads_mutex
+> While executing: OPEN-SHARED-LIBRARY
+
+;;; Grovel around, curse, and try to find out where "gdk_threads_mutex=
"
;;; might be defined. Then try again:
=
-? (open-shared-library "libgdk.so")
-#<SHLIB libgdk.so #x3046DBB6>
-
-? (open-shared-library "libgtk.so")
-#<SHLIB libgtk.so #x3046DC86>
+? (open-shared-library "libgdk.so")
+#<SHLIB libgdk.so #x3046DBB6>
+
+? (open-shared-library "libgtk.so")
+#<SHLIB libgtk.so #x3046DC86>
=
;;; Reference an external symbol defined in one of those libraries.
=
-? (external "gtk_main")
-#<EXTERNAL-ENTRY-POINT "gtk_main" (#x012C3004) libgtk.so #x3046FE46>
+? (external "gtk_main")
+#<EXTERNAL-ENTRY-POINT "gtk_main" (#x012C3004) libgtk.so #x304=
6FE46>
=
;;; Close those libraries.
=
-? (close-shared-library "libgtk.so")
+? (close-shared-library "libgtk.so")
T
=
-? (close-shared-library "libgdk.so")
+? (close-shared-library "libgdk.so")
T
=
;;; Reference the external symbol again.
=
-? (external "gtk_main")
-#<EXTERNAL-ENTRY-POINT "gtk_main" {unresolved} libgtk.so #x3046FE46>
-</programlisting>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para>It would be helpful to describe what an soname is and give
-examples of one.</para>
- <para>Does the SHLIB still get returned if the library is
-already open?</para>
- </sect2>
-
- <sect2 id=3D"CLOSE-SHARED-LIBRARY">
- <para>CLOSE-SHARED-LIBRARY</para>
- <informalfigure>close-shared-library</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CLOSE-SHARED-LIBRARY — Stops using a shared library, i=
nforming the operating
-system that it can be unloaded if appropriate.</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- close-shared-library library &key
- completely
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>library
- <variablelist>either an object of type SHLIB, or a string whic=
hdesignates one by its so-name.</variablelist>
- </indexterm><indexterm>completely
- <variablelist>a boolean. The default is T.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>If <literal>completely</literal> is T, sets the
-reference count of <literal>library</literal> to 0. Otherwise,
-decrements it by 1. In either case, if the reference count
-becomes 0, <literal>close-shared-library</literal>
-frees all memory resources consumed <literal>library</literal>
-and
-causes any EXTERNAL-ENTRY-POINTs known to be defined by it to
-become unresolved.</para>
- </sect2>
-
- <sect2 id=3D"EXTERNAL">
- <para>EXTERNAL</para>
- <informalfigure>external</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>EXTERNAL — Resolves a reference to an external symbol =
which
-is defined in a shared library.</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- external name =3D> entry
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>name
- <variablelist>a simple-string which names an external symbol.C=
ase-sensitive.</variablelist>
- </indexterm><indexterm>entry
- <variablelist>an object of type EXTERNAL-ENTRY-POINT which mai=
ntainsthe address of the foreign symbol named by<literal>name</literal>.</v=
ariablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>If there is already an EXTERNAL-ENTRY-POINT for
-the symbol named by <literal>name</literal>, finds it and
-returns it. If not, creates one and returns it.</para>
- <para>Tries to resolve the entry point to a memory address,
-and identify the containing library.</para>
- <para>Be aware that under Darwin, external functions which
-are callable from C have underscores prepended to their names,
-as in "_fopen".</para>
- </sect2>
-
- <sect2 id=3D"iFF-CALL">
- <para>%FF-CALL</para>
- <informalfigure>%ff-call</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>%FF-CALL —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- %ff-call entrypoint
- {arg-type-keyword arg}* &optional result-type-keyword
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>entrypoint
- <variablelist>A fixnum or MACPTR</variablelist>
- </indexterm><indexterm>arg-type-keyword
- <variablelist>One of the foreign argument-type keywords, descr=
ibedabove</variablelist>
- </indexterm><indexterm>arg
- <variablelist>A lisp value of type indicated by the correspond=
ingarg-type-keyword</variablelist>
- </indexterm><indexterm>result-type-keyword
- <variablelist>One of the foreign argument-type keywords, descr=
ibedabove</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Calls the foreign function at address entrypoint passing the
-values of each arg as a foreign argument of type indicated by the
-corresponding arg-type-keyword. Returns the foreign function
-result (coerced to a Lisp object of type indicated by
-result-type-keyword), or NIL if result-type-keyword is :VOID or
-NIL</para>
- </sect2>
-
- <sect2 id=3D"FF-CALL">
- <para>FF-CALL</para>
- <informalfigure>ff-call</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>FF-CALL —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- ff-call entrypoint
- {arg-type-specifier arg}* &optional result-type-specifier
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>entrypoint
- <variablelist>A fixnum or MACPTR</variablelist>
- </indexterm><indexterm>arg-type-specifer
- <variablelist>One of the foreign argument-type keywords, descr=
ibedabove, or an equivalent foreigntype specifier (see ).</variablelist>
- </indexterm><indexterm>arg
- <variablelist>A lisp value of type indicated by the correspond=
ingarg-type-specifier</variablelist>
- </indexterm><indexterm>result-type-specifier
- <variablelist>One of the foreign argument-type keywords, descr=
ibedabove, or an equivalent foreigntype specifier (see ).</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Calls the foreign function at address entrypoint passing the
-values of each arg as a foreign argument of type indicated by the
-corresponding arg-type-specifier. Returns the foreign function
-result (coerced to a Lisp object of type indicated by
-result-type-specifier), or NIL if result-type-specifer is :VOID or
-NIL</para>
- </sect2>
-
- <sect2 id=3D"iREFERENCE-EXTERNAL-ENTRY-POINT">
- <para>%REFERENCE-EXTERNAL-ENTRY-POINT</para>
- <informalfigure>%reference-external-entry-point</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>%REFERENCE-EXTERNAL-ENTRY-POINT —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- %reference-external-entry-point eep
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>eep
- <variablelist>An EXTERNAL-ENTRY-POINT, as obtained by the EXTE=
RNALmacro.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Tries to resolve the address of the EXTERNAL-ENTRY-POINT
-eep; returns a fixnum representation of that address if
-successful, else signals an error.</para>
- </sect2>
-
- <sect2 id=3D"EXTERNAL-CALL">
- <para>EXTERNAL-CALL</para>
- <informalfigure>external-call</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>EXTERNAL-CALL —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- external-call name
- {arg-type-specifier arg}* &optional result-type-specifier
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>name
- <variablelist>A lisp string. See external, above.</variablelis=
t>
- </indexterm><indexterm>arg-type-specifer
- <variablelist>One of the foreign argument-type keywords, descr=
ibedabove, or an equivalent foreigntype specifier (see ).</variablelist>
- </indexterm><indexterm>arg
- <variablelist>A lisp value of type indicated by the correspond=
ingarg-type-specifier</variablelist>
- </indexterm><indexterm>result-type-specifier
- <variablelist>One of the foreign argument-type keywords, descr=
ibedabove, or an equivalent foreigntype specifier (see ).</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Calls the foreign function at the address obtained by
-resolving the external-entry-point associated with name, passing
-the values of each arg as a foreign argument of type indicated by
-the corresponding arg-type-specifier. Returns the foreign function
-result (coerced to a Lisp object of type indicated by
-result-type-specifier), or NIL if result-type-specifer is :VOID or
-NIL</para>
- </sect2>
-
- <sect2 id=3D"FOREIGN-SYMBOL-ENTRY">
- <para>FOREIGN-SYMBOL-ENTRY</para>
- <informalfigure>foreign-symbol-entry</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>FOREIGN-SYMBOL-ENTRY —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- foreign-symbol-entry name
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>name
- <variablelist>A lisp string.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Tries to resolve the address of the foreign symbol name. If
-successful, returns a fixnum representation of that address, else
-returns NIL.</para>
- </sect2>
-
- <sect2 id=3D"FOREIGN-SYMBOL-ADDRESS">
- <para>FOREIGN-SYMBOL-ADDRESS</para>
- <informalfigure>foreign-symbol-address</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>FOREIGN-SYMBOL-ADDRESS —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- foreign-symbol-address name
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>name
- <variablelist>A lisp string.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Tries to resolve the address of the foreign symbol name. If
-successful, returns that address encapsulated
-in a MACPTR (see ), else returns
-NIL.</para>
- </sect2>
-
- <sect2 id=3D"DEFCALLBACK">
- <para>DEFCALLBACK</para>
- <informalfigure>defcallback</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>DEFCALLBACK —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- defcallback name
- ({arg-type-specifier var}* &optional result-type-specifier)
- &body body
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>name
- <variablelist>A symbol which can be made into a special variab=
le</variablelist>
- </indexterm><indexterm>arg-type-specifer
- <variablelist>One of the foreign argument-type keywords, descr=
ibedabove, or an equivalent foreigntype specifier (see ).In addition, if th=
e keyword:WITHOUT-INTERRUPTS is specified, the callback will beexecuted wit=
h lisp interrupts disabled if the correspondingvar is non-NIL. If :WITHOUT-=
INTERRUPTS is specified morethan once, the rightmost instance wins.</variab=
lelist>
- </indexterm><indexterm>var
- <variablelist>A symbol (lisp variable), which will be bound to=
avalue of the specified type.</variablelist>
- </indexterm><indexterm>body
- <variablelist>A sequence of lisp forms, which should return a =
valuewhich can be coerced to the specified result-type.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Proclaims <literal>name</literal>
-to be a special variable; sets its value to a
-MACPTR which, when called by foreign code, calls a lisp function
-which expects foreign arguments of the specified types and which
-returns a foreign value of the specified result type. Any argument
-variables which correspond to foreign arguments of type :ADDRESS
-are bound to stack-allocated MACPTRs.</para>
- <para>If <literal>name</literal>
-is already a callback function pointer, its value is
-not changed; instead, it's arranged
-that an
-updated version of the lisp callback function will be called.
-This feature allows for callback functions to be redefined
-incrementally, just like Lisp functions are.</para>
- <para><literal>defcallback</literal>
-returns the callback pointer, e.g., the
-value of <literal>name</literal>.</para>
- </sect2>
-
- <sect2 id=3D"SHARP-UNDERSCORE">
- <para>SHARP-AMPERSAND</para>
- <informalfigure>#_</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>#_ —</para>
- <para>Reader Macro</para>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Reads a symbol from the current input stream, with *PACKAGE*
-bound to the "OS" package and with readtable-case preserved.</para>
- <para>Does a lookup on that symbol
-in the OpenMCL interface database (see ),
-signalling
-an error if no foreign function information can be found for the
-symbol in any
-active interface directory (see ).</para>
- <para>Notes the foreign function information, including the foreign
-function's return type, the number and type of the foreign
-function's required arguments, and an indication of whether or
-not the function accepts additional arguments (via e.g., the
-"varargs" mechanism in C).</para>
- <para>Defines a macroexpansion function on the symbol, which expand
-macro calls involving the symbol into EXTERNAL-CALL forms where
-foreign argument type specifiers for required arguments and the
-return value specifer are provided from the information ind the
-database.</para>
- <para>Returns the symbol.</para>
- <para>The effect of these steps is that it's possible to call
-foreign functions that take fixed numbers of arguments by simply
-providing argument values, as in:</para>
- <programlisting>
-(#_isatty fd)
-(#_read fd buf n)
-</programlisting>
- <para>and to call foreign functions that take variable numbers of
-arguments by specifying the types of non-required args, as in:</para>
- <programlisting>
-(with-cstrs ((format-string "the answer is: %d"))
- (#_printf format-string :int answer))
-</programlisting>
- </sect2>
-
- <sect2 id=3D"SHARP-AMPERSAND">
- <para>SHARP-AMPERSAND</para>
- <informalfigure>SHARP-AMPERSAND</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>#& —</para>
- <para>Reader Macro</para>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>In OpenMCL 1.0 and later, the #& reader macro <tip><para=
>This
-functionality was introduced as #? in 0.14.2, but ANSI CL requires
-that #? be reserved for the user. #? is still supported as an alias
-to #&, but that will change in the next release.</para></tip> can be u=
sed to
-access foreign variables; this functionality depends on the presence
-of "vars.cdb" 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 "OS" package and with readtable-case preserved.</para>
- <para>Use that symbol's pname to access the OpenMCL interface
-database, signalling an error if no appropriate foreign variable
-information can be found with that name in any active interface
-directory.</para>
- <para>Use type information recorded in the database to construct a
-form which can be used to access the foreign variable, and return
-that form.</para>
- <para>Please note that the set of foreign variables declared in he=
ader files
-may or may not match the set of foreign variables exported from
-libraries (we're generally talking about C and Unix here ...). When
-they do match, the form constructed by the #& reader macro manages the
-details of resolving and tracking changes to the foreign variable's
-address.</para>
- <para>Future extensions (via prefix arguments to the reader macro)=
may
-offer additional behavior; it might be convenient (for instance) to be
-able to access the address of a foreign variable without dereferencing
-that address.</para>
- <para>Foreign variables in C code tend to be platform- and
-package-specific (the canonical example - "errno" - is typically
-not a variable when threads are involved. )</para>
- <para>In LinuxPPC,</para>
- <programlisting>
-? #&stderr
-</programlisting>
- <para>returns a pointer to the stdio error stream ("stderr" is a
-macro under OSX/Darwin).</para>
- <para>On both LinuxPPC and DarwinPPC,</para>
- <programlisting>
-? #&sys_errlist
-</programlisting>
- <para>returns a pointer to a C array of C error message strings.</=
para>
- </sect2>
-
- <sect2 id=3D"USE-INTERFACE-DIR">
- <para>USE-INTERFACE-DIR</para>
- <informalfigure>use-interface-dir</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>USE-INTERFACE-DIR —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- use-interface-dir dir-id
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>dir-id
- <variablelist>A keyword whose pname, mapped to lower case, nam=
es asubdirectory of "ccl:headers;" (or"ccl:darwin-headers;")</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Tells OpenMCL to add the interface directory denoted by
-dir-id to the list of interface directories which it consults for
-foreign type and function information. Arranges that that
-directory is searched before any others.</para>
- <para>Note that <literal>use-interface-dir</literal>
-merely adds an entry
-to a search list.
-If the named directory doesn't exist in the file system
-or doesn't
-contain a set of database files, a runtime error may occur
-when OpenMCL
-tries to open some database file in that directory, and it
-will try to
-open such a database file whenever it needs to find any
-foreign type or
-function information. =
-may come in
-handy in that case.</para>
- <bridgehead renderas=3D"sect3">Examples</bridgehead>
- <para>One typically wants interface information to be
-available at compile-time (or, in many cases, at read-time).
-A typical idiom would be:</para>
- <programlisting>
-(eval-when (:compile-toplevel :execute)
- (use-interface-dir :GTK))
-</programlisting>
- <para>Using the :GTK interface directory makes available
-information on
-foreign types, functions, and constants. It's generally
-necessary to
-load foreign libraries before actually calling the
-foreign code, which for GTK can be done like this:</para>
- <programlisting>
-(load-gtk-libraries)
-</programlisting>
- <para>It should now be possible to do things like:</para>
- <programlisting>
-(#_gtk_widget_destroy w)
-</programlisting>
- </sect2>
-
- <sect2 id=3D"UNUSE-INTERFACE-DIR">
- <para>UNUSE-INTERFACE-DIR</para>
- <informalfigure>unuse-interface-dir</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>UNUSE-INTERFACE-DIR —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- unuse-interface-dir dir-id
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>dir-id
- <variablelist>A keyword whose pname, mapped to lower case, nam=
es asubdirectory of "ccl:headers;" (or"ccl:darwin-headers;")</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Tells OpenMCL to remove the interface directory denoted by
-dir-id from the list of interface directories which are
-consulted for
-foreign type and function information. Returns T if the directory
-was on the search list, NIL otherwise.</para>
- </sect2>
-
- <sect2 id=3D"TERMINATE-WHEN-UNREACHABLE">
- <para>TERMINATE-WHEN-UNREACHABLE</para>
- <informalfigure>terminate-when-unreachable</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>TERMINATE-WHEN-UNREACHABLE —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- terminate-when-unreachable object
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>object
- <variablelist>A CLOS object of a class for which there existsa=
method of the generic function<literal>ccl:terminate</literal>.</variablel=
ist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>The "termination" mechanism is a way to have the garbage
-collector run a function right before an object is about to
-become garbage. It is very similar to the "finalization"
-mechanism which Java has. It is not standard Common Lisp,
-although other Lisp implementations have similar features.
-It is useful when there is some sort of special cleanup,
-deallocation, or releasing of resources which needs to happen
-when a certain object is no longer being used.</para>
- <para>When the garbage collector discovers that an object is no
-longer referred to anywhere in the program, it deallocates
-that object, freeing its memory. However, if
-<literal>ccl:terminate-when-unreachable</literal> has been
-called on the object at any time, the garbage collector first
-invokes the generic function <literal>ccl:terminate</literal>,
-passing it the object as a parameter.</para>
- <para>Therefore, to make termination do something useful, you need=
to
-define a method on <literal>ccl:terminate</literal>.</para>
- <para>Because calling
-<literal>ccl:terminate-when-unreachable</literal> only
-affects a single object, rather than all objects of its
-class, you
-may wish to put a call to it in the
-<literal>initialize-instance</literal> method of a
-class. Of course, this is only appropriate if you do in fact
-want to use termination for all objects of a given class.</para>
- <bridgehead renderas=3D"sect3">Example</bridgehead>
- <programlisting>
+? (external "gtk_main")
+#<EXTERNAL-ENTRY-POINT "gtk_main" {unresolved} libgtk.so #x304=
6FE46></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"arb23">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"arb23">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"arb23">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"arb23">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"arb23">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'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 "OS" package and with readtable-case preserved.</p=
ara>
+ =
+ <para>Does a lookup on that symbol
+ in <link linkend=3D"arb25">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"arb29">interface directory</link>.</para>
+
+ <para>Notes the foreign function information, including the foreign
+ function's return type, the number and type of the foreign
+ function's required arguments, and an indication of whether or
+ not the function accepts additional arguments (via e.g., the
+ "varargs" mechanism in C).</para>
+
+ <para>Defines a macroexpansion function on the symbol, which expand
+ macro calls involving the symbol into EXTERNAL-CALL forms where
+ foreign argument type specifiers for required arguments and the
+ return value specifer are provided from the information ind the
+ database.</para>
+
+ <para>Returns the symbol.</para>
+
+ <para>The effect of these steps is that it's possible to call
+ foreign functions that take fixed numbers of arguments by simply
+ providing argument values, as in:</para>
+
+ <programlisting 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 =
4;the answer is: %d"))
+ (#_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
+ "vars.cdb" 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 "OS" package and with readtable-case preserved.</p=
ara>
+ =
+ <para>Use that symbol's pname to access the OpenMCL interface
+ database, signalling an error if no appropriate foreign variable
+ information can be found with that name in any active interface
+ directory.</para>
+
+ <para>Use type information recorded in the database to construct a
+ form which can be used to access the foreign variable, and return
+ that form.</para>
+
+ <para>Please note that the set of foreign variables declared in header =
files
+ may or may not match the set of foreign variables exported from
+ libraries (we're generally talking about C and Unix here ...). When
+ they do match, the form constructed by the #? reader macro manages the
+ details of resolving and tracking changes to the foreign variable's
+ address.</para>
+
+ <para>Future extensions (via prefix arguments to the reader macro) may
+ offer additional behavior; it might be convenient (for instance) to be
+ able to access the address of a foreign variable without dereferencing
+ that address.</para>
+
+ <para>Foreign variables in C code tend to be platform- and
+ packge-specific (the canonical example - "errno" - 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 ("stderr" 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 "ccl:headers;" (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't exist in the file system
+ or doesn't
+ contain a set of database files, a runtime error may occur
+ when OpenMCL
+ tries to open some database file in that directory, and it
+ will try to
+ open such a database file whenever it needs to find any
+ foreign type or
+ function information. <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 "ccl:headers;" (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)))
=
@@ -7835,45 +11197,54 @@
=
(defmethod ccl:terminate ((x resource-wrapper))
(when (resource x)
- (deallocate (resource x))))
-</programlisting>
- <bridgehead renderas=3D"sect3">See Also</bridgehead>
- <para role=3D"continues">Tutorial: Allocating Foreign Data on the =
Lisp Heap</para>
- </sect2>
+ (deallocate (resource x))))</programlisting>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type=3D"inline">
+ <member><xref linkend=3D"arb35"/></member>
+ </simplelist>
+ </refsect1>
+
+ </refentry>
+
</sect1>
</chapter>
=
<chapter id=3D"The-Objective-C-Bridge">
- <para>The Objective-C Bridge
-OS X APIs use a language called "Objective C", which is built on C.
-The Objective-C bridge makes it possible to work with ObjC
-objects and classes from Lisp, and to define classes in Lisp which
-can be used by ObjC.</para>
- <para>The ultimate
-purpose of the ObjC and Cocoa bridges is to make Cocoa as
-easy as possible to use from OpenMCL, in order to support the
-development of GUI applications and IDEs. The eventual goal,
-which is much closer than it used to be, is complete integration of
-Cocoa into CLOS (whatever that means).</para>
+ <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>
+ 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">
- <para>Using Objective-C Classes
-The class of most "standard" CLOS classes is the
-class named STANDARD-CLASS. In the Objective-C object model, each
-class is an instance of a (usually unique) metaclass, which is
-itself an instance of a "base" metaclass (often the
-metaclass of the class named "NSObject".) So, the
-Objective-C class named "NSWindow" and the ObjC class
-"NSArray" are (sole) instances of their distinct
-metaclasses whose names are also "NSWindow" and
-"NSArray", respectively. (In the Objective-C world,
-it's much more common and useful to specialize class behavior
-such as instance allocation.)</para>
+ <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
@@ -7913,23 +11284,23 @@
</sect1>
=
<sect1 id=3D"Instantiating-Objective-C-Objects">
- <para>Instantiating Objective-C Objects
-Making an instance of an ObjC class (whether the class in question
-is predefined or defined by the application) involves calling
-MAKE-INSTANCE with the class and a set of initargs as arguments.
-As with STANDARD-CLASS, making an instance involves initializing
-(with INITIALIZE-INSTANCE) an object allocated with
-ALLOCATE-INSTANCE.</para>
+ <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)
-#<NS-CF-NUMBER 42 (#x85962210)>
+#<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>
+ writing in Objective C:</para>
<programlisting>
[[NSNumber alloc] initWithInt: 42]
-</programlisting>
+ </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
@@ -7940,7 +11311,7 @@
*N*
=
? (setq *n* (ccl::send *n* :init-with-int 42))
-#<NS-CF-NUMBER 42 (#x16D340)>
+#<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
@@ -7966,7 +11337,7 @@
(ccl::send *controller*
:init-with-window-nib-name #@"DataWindow"
:owner *controller*))
-#<NS-WINDOW-CONTROLLER <NSWindowController: 0x1fb520> (#x1FB520)>
+#<NS-WINDOW-CONTROLLER <NSWindowController: 0x1fb520> (#x1FB520)>
</programlisting>
<para>This example calls (make-instance) with no initargs. When you
do this, the object is only allocated, and not initialized. It
@@ -7974,20 +11345,20 @@
</sect1>
=
<sect1 id=3D"Calling-Objective-C-Methods">
- <para>Calling Objective-C Methods
-In Objective-C, methods are called "messages", and there's
-a special syntax to send a message to an object:</para>
+ <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>
+ </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>
+ <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)
@@ -8013,91 +11384,65 @@
method in your subclass.</para>
=
<sect2 id=3D"Type-Coercion-for-ObjC-Method-Calls">
- <para>Type Coercion for ObjC Method Calls
-OpenMCL's FFI handles many common conversions between Lisp
-and foreign data, such as unboxing floating-point args and
-boxing floating-point results. The bridge adds a few more
-automatic conversions:</para>
- <para>NIL is equivalent to (%NULL-PTR) for any message argument th=
at
-requires a pointer.</para>
+ <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>
- <para>To make this last conversion work, the bridge has to engage
-in a bit of hackery. The bridge uses ObjC run-time type
-info. Unfortunately, BOOL is typed as CHAR by ObjC. Thus,
-a method that returns CHAR might actually return only BOOL,
-or it might return any CHAR.</para>
- <para>The bridge currently assumes
-that any method that returns CHAR actually returns BOOL.
-But it provides a facility for defining exceptions to this
-assumption: (DEFINE-RETURNS-BOOLEAN-EXCEPTION "charValue").
-Eventually, the best way to handle issues like this is
-probably to get our method type info directly from the
-header files rather than using ObjC's runtime type system.</para>
- <para>Note that no automatic conversion is currently performed bet=
ween
-Lisp strings and NSStrings. However, there is a convenient
-reader macro for creating constant NSStrings:</para>
- <programlisting>
-(SEND W :SET-TITLE #@"My Window")
-</programlisting>
- <para>Note that #@"Hello" is a full ObjC object, so
-messages can be sent to it: (SEND #@"Hello" 'LENGTH).</para>
- <para>To go in the other direction, use the function
-(ccl::lisp-string-from-nsstring).</para>
- <para>To create variable NSStrings (which you will later
-want to change the
-values of), consider using CCL::NS-LISP-STRING.</para>
+ <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">
- <para>Methods which Return Structures
-Some Cocoa methods return small structures, such as those used
-to represent points, rects, sizes and ranges. When writing in
-Objective C, the compiler hides the implementation details.
-Unfortunately, in Lisp we must be slightly more aware of them.</para>
- <para>Methods which return structures are called in a special way;
-the caller allocates space for the result, and passes a pointer
-to it as an extra argument to the method. This is called a
-Structure Return, or STRET. Don't look at me; I don't name
-these things.</para>
+ <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>
+ 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 .
-We do it like this:</para>
+ </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 :<NSR>ect))
+(rlet ((r :<NSR>ect))
(send/stret r v1 'bounds)
(send v2 :set-bounds r))
</programlisting>
- <para>The rlet allocates the storage (but doesn't initialize it),
-and makes sure that it will be deallocated when we're done.
-It binds the variable r to refer to it.
-The call to <literal>send/stret</literal> is just like
-an ordinary call to
-<literal>send</literal>, except that r is passed as an
-extra, first parameter. The third line, which calls
-<literal>send</literal>, does not need to do anything
-special, because there's nothing complicated about passing
-a structure as a parameter.</para>
- <para>In order to make STRETs easier to use, the bridge provides t=
wo
-conveniences.</para>
+ <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>
+ 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>
+ </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
@@ -8134,7 +11479,8 @@
</sect2>
=
<sect2 id=3D"Variable-Arity-Messages">
- <para>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>
@@ -8162,116 +11508,116 @@
</sect2>
=
<sect2 id=3D"Optimization">
- <para>Optimization
-The bridge works fairly hard to optimize message sends, when
-it has enough information to do so. There are two cases when
-it does. In either, a message send should be nearly as
-efficient as when writing in Objective C.</para>
- <para>The first case is when both the message
-and the receiver's class are known at
-compile-time. In general, the only way the receiver's class
-is known is if you declare it, which you can do with
-either a DECLARE or a THE form. For example:</para>
+ <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>
+ </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>
+ 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>
+ <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>
+ <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">
- <para>Defining Objective-C Classes
-You can define your own foreign classes, which can then be
-passed to foreign functions; the methods which you implement
-in Lisp will be made available to the foreign code as
-callbacks.</para>
- <para>You can also define subclasses of existing classes, implementi=
ng
-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>
+ <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>
+ 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">
- <para>Defining classes with foreign slots
-If a slot specification in an Objective-C class definition
-contains the keyword :FOREIGN-TYPE, the slot will be a "foreign
-slot" (i.e. an ObjC instance variable). Be aware that it is an
-error to redefine an ObjC class so that its foreign slots
-change in any way, and OpenMCL doesn't do anything consistent
-when you try to.</para>
- <para>The value of the :FOREIGN-TYPE initarg should be a foreign t=
ype
-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>
+ <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
@@ -8280,49 +11626,49 @@
(: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>
+ above is redundant: foreign slots are initialized to binary
+ 0.</para>
</sect2>
=
<sect2 id=3D"Defining-classes-with-Lisp-slots">
- <para>Defining classes with Lisp slots
-A slot specification in an ObjC class definition that doesn't
-contain the :FOREIGN-TYPE initarg defines a pretty-much normal lisp
-slot that'll happen to be associated with "an instance of a
-foreign class". For instance:</para>
+ <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>
+ </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>
+ 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">
- <para>Defining Objective-C Methods
-In ObjC, unlike in CLOS, every method belongs to some
-particular class. This is probably not a strange
-concept to you, because C++ and Java do the same thing.
-When you use Lisp to define ObjC methods, it is only
-possible to define methods belonging to ObjC classes which
-have been defined in Lisp.</para>
+ <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>
+ 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>
@@ -8332,32 +11678,29 @@
(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>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>
+ 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>
+ </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>
+ 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)
@@ -8366,14 +11709,13 @@
(setf (aref (data self) i)
(* i multiplier)))
self)
-</programlisting>
+ </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>
+ 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)
@@ -8385,15 +11727,15 @@
(+ (* i multiplier)
addend)))
self)
-</programlisting>
+ </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>
+ "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)
@@ -8402,106 +11744,88 @@
(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 foll=
owing two method definitions are equivalent:</para>
+ <para>This method would be called "takeAction:" in ObjC. The
+ convention for methods that are going to be used as Cocoa
+ actions is that they take one parameter, which is the object
+ responsible for triggering the action. However, this method
+ doesn't actually need to use that parameter, so it explicitly
+ ignores it to avoid a compiler warning. As promised, the method
+ doesn't return any value.</para>
+ <para>There is also an alternate syntax, illustrated here. The
+ following two method definitions are equivalent:</para>
<programlisting>
(define-objc-method ("applicationShouldTerminate:"
"LispApplicationDelegate")
- (:id sender :<BOOL>)
+ (:id sender :<BOOL>)
(declare (ignore sender))
nil)
=
-(define-objc-method ((:<BOOL>
+(define-objc-method ((:<BOOL>
:application-should-terminate sender)
lisp-application-delegate)
(declare (ignore sender))
nil)
</programlisting>
<sect2 id=3D"Method-Redefinition-Constraints">
- <para>Method Redefinition Constraints
-Objective C was not designed, as Lisp was, with runtime
-redefinition in mind. So, there are a few constraints about
-how and when you can replace the definition of an Objective C
-method. Currently, if you break these rules, nothing will
-collapse, but the behaviour will be confusing; so don't.</para>
- <para>Objective C methods can be redefined at runtime, but their
-signatures shouldn't change. That is, the types of the arguments
-and the return type have to stay the same. The reason for this
-is that changing the signature changes the selector which is used
-to call the method.</para>
- <para>When a method has already been defined in one class, and you
-define it in a subclass, shadowing the original method, they
-must both have the same type signature. There is no such
-constraint, though, if the two classes aren't related and the
-methods just happen to have the same name.</para>
+ <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">
- <para>How Objective-C Names are Mapped to Lisp Symbols
-There is a standard set of naming conventions for Cocoa classes,
-messages, etc. As long as they are followed, the bridge is fairly
-good at automaticallly translating between ObjC and Lisp names.</para>
+ <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>
- <colspec>
- <thead cols=3D"1">
- <tbody colwidth=3D"100*"></tbody>
- <row>
- <abstract>
- <entry>(ccl::objc-to-lisp-classname string)</entry>
- =
- </abstract>
- <abstract>
- <entry>(ccl::lisp-to-objc-classname symbol)</entry>
- =
- </abstract>
- <abstract>
- <entry>(ccl::objc-to-lisp-message string)</entry>
- =
- </abstract>
- <abstract>
- <entry>(ccl::lisp-to-objc-message string)</entry>
- =
- </abstract>
- <abstract>
- <entry>(ccl::objc-to-lisp-init string)</entry>
- =
- </abstract>
- <abstract>
- <entry>(ccl::lisp-to-objc-init keyword-list)</entry>
- =
- </abstract>
- </row>
- </thead>
- </colspec>
- <para>Of course, there will always be exceptions to any naming conve=
ntion.
-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>
+ "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>
+ 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 y=
our
-exception. This is useful for an exceptional name that you need
-to use througout your code. Some examples:</para>
+ </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))
@@ -8517,288 +11841,275 @@
<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>
+ <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"Using-OpenMCL-with-Mac-OS-X--the-Darwin-Kernel--and-the-C=
ocoa-GUI-API">
- <para>Using OpenMCL with Mac OS X, the Darwin Kernel, and the Cocoa G=
UI API</para>
-
- <sect1 id=3D"Differences-in-OpenMCL-between-Darwin-and-MacOS-X">
- <para>Differences in OpenMCL between Darwin and MacOS X
-Most of the documentation and whatever experience you may have in using Op=
enMCL under LinuxPPC should apply to using it under Darwin/MacOS X. There a=
re some differences between the platforms, and these differences are someti=
mes exposed in the implementation.</para>
-
- <sect2 id=3D"FASL-file-segregation-">
- <para>FASL file segregation.
-99% of the compiled lisp code in the two implementations is
-identical. Since both implementations target the PowerPC, this
-shouldn't be too surprising.</para>
- <para>The other 1% - code which deals with foreign functions or da=
ta or
-which deals directly with the operating system - is very different but
-superficially similar. The effects of running such code compiled for
-the wrong platform range from harmless to catastrophic.</para>
- <para>During bootstrapping, the 1% proved troublesome enough that =
it seemed
-wise to strictly separate the two implementations.</para>
- <para>FASL files have different file types (.dfsl for Darwin, .pfs=
l for
-LinuxPPC) and contain different identifying information; it's not
-possible to successfully load FASL files compiled for one
-implementation into the other.</para>
- <para>I think that it's wise to maintain this distinction; I spent=
a lot
-less time recompiling the 99% of "non-troublesome" code than I'd been
-spending tracking down bugs caused by the other 1%.</para>
- </sect2>
+ <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">
- <para>File-system case
-Darwin and MacOS X use HFS+ file systems by default; HFS+ file systems
-are case-insensitive. Most of OpenMCL's filesystem and pathname code
-assumes that the underlying filesystem is case-sensitive; this
-assumption extends to functions like EQUAL, which assumes that #p"FIXTHIS"
-and #p"foo" denote different, un-EQUAL filenames. Since Darwin/MacOS X
-can also use UFS and NFS filesystems, the opposite assumption would be
-no more correct than the one that's currently made.</para>
+ <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>has the unfortunate side-effect of trying to overwrite the D=
arwin
-OpenMCL kernel, "dppccl", on a case-insensitive filesystem.</para>
- <para>To work around this, the Darwin OpenMCL kernel expects the d=
efault
-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>
+ </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">
- <para>Line Termination Characters
-MacOSX effectively supports two distinct line-termination
-conventions. Programs in its Darwin substrate follow the Unix
-convention of recognizing #\LineFeed as a line terminator; traditional
-MacOS programs use #\Return for this purpose.</para>
- <para>OpenMCL follows the Unix convention on both Darwin and Linux=
PPC,
-but offers (as of version 0.11) some support for reading and writing
-files that use the MacOS convention as well.</para>
- <para>This support (and anything like it) is by nature heuristic: =
it
-can successfully hide the distinction between newline conventions
-much of the time, but could mistakenly change the meaning of
-otherwise correct programs (typically when files contain both
-#\Return and #\Linefeed characters or when files contain mixtures of
-text and binary data.) Because of this concern, the default settings
-of some of the variables that control newline translation and
-interpretation are somewhat conservative.</para>
- <para>Although the issue of multiple newline conventions primarily
-affects MacOSX users, the functionality described here is available
-under LinuxPPC as well (and may occasionally be useful there.)</para>
- <para>None of this addresses issues related
-to the third newline convention ("CRLF") in widespread use
-(since that convention isn't native to any platform on which
-OpenMCL currently runs). If OpenMCL is ever ported to such a
-platform, that issue might be revisited.</para>
- <para>Note that some MacOS programs (including some versions of
-commercial MCL) may use HFS file type information to recognize TEXT
-and other file types and so may fail to recognize files created with
-OpenMCL or other Darwin applications (regardless of line termination
-issues.)</para>
- <para>Unless otherwise noted, the symbols mentioned in this
-documentation are exported from the CCL package.</para>
+ <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">
- <para>Single-precision trig & transcendental functions
-Despite what Darwin's man pages say, early versions of its math library
-(up to and including OSX 10.2 (Jaguar) don't implement
-single-precision variants of the transcendental and trig functions
-(#_sinf, #_atanf, etc.) OpenMCL works around this by coercing
-single-precision args to double-precision, calling the
-double-precision version of the math library function, and coercing
-the result back to a SINGLE-FLOAT. These steps can introduce rounding
-errors (and potentially overflow conditions) that might not be present
-or as severe if true 32-bit variants were available.</para>
+ <title>Single-precision trig & 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">
- <para>Shared libraries
-Darwin/MacOS X distinguishes between "shared libraries" and "bundles"
-or "extensions"; Linux doesn't. In Darwin, "shared libraries" have the
-file type "dylib" : the expectation is that this class of file is
-linked against when executable files are created and loaded by the OS
-when the executable is launched. The latter class -
-"bundles/extensions" - are expected to be loaded into and unloaded
-from a running application, via a mechanism like the one used by
-OpenMCL's OPEN-SHARED-LIBRARY function.</para>
- <para>OpenMCL wants to treat all shared libs as if they were "bund=
les"; this
-is presumably possible, but none of it's implemented under OpenMCL
-0.10. Ideally, whatever gets implemented will hide the distinction as
-much as possible, but it may not be possible to hide it completely.</para>
+ <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">
- <para>Unix/Posix/Darwin Features
-OpenMCL has several convenience functions which allow you to
-make Posix (portable Unix) calls without having to use the
-foreign-function interface. Each of these corresponds directly
-to a single Posix function call, as it might be made in C. There
-is no attempt to make these calls correspond to Lisp idioms, such as
-<literal>setf</literal>. This means that their behaviour is
-simple and predictable.</para>
+ <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>
+ 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>
+ CCL::GETUID, CCL::SETUID, and CCL::SETGID. To find the home
+ directory of an arbitrary user, as set in the user database
+ (/etc/passwd), there is CCL::GET-USER-HOME-DIR.</para>
+ <para>For process IDs, there is CCL::GETPID.</para>
<para>For the <literal>system()</literal> function, there is
-CCL::OS-COMMAND. Ordinarily, it is better -
-both more efficient and more predictable - to use the features
-described in . However,
-sometimes you may want to specifically ask the shell to invoke a
-command for you.</para>
+ 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">
- <para>Cocoa Programming in OpenMCL
-Cocoa is one of Apple's APIs for GUI programming; for most purposes,
-development is considerably faster with Cocoa than with the
-alternatives. You should have a little familiarity with it, to
-better understand this section.</para>
- <para>A small sample Cocoa program can be invoked by evaluating (REQ=
UIRE
-'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, w=
hich 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>
+ <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">
- <para>The Command Line and the Window System
-OpenMCL is ordinarily a command-line application (it doesn't have a
-connection to the OSX Window server, doesn't have its own menubar or
-dock icon, etc.) By opening some libraries and jumping through some
-hoops, it's able to sort of transform itself into a full-fledged GUI
-application (while retaining its original TTY-based listener.) The
-general idea is that this hybrid environment can be used to test and
-protoype UI ideas and the resulting application can eventually be
-fully transformed into a bundled, double-clickable application. This
-is to some degree possible, but there needs to be a bit more
-infrastructure in place before many people would find it easy.</para>
+ <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>
+ 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">
- <para>Writing (and reading) Cocoa code
-The syntax of the constructs used to define Cocoa classes and methods
-has changed a bit (it was never documented outside of the source code
-and never too well documented at all), largely as the result of
-functionality offered by Randall Beer's bridge; the “standard
-name-mapping conventions” referenced below are described in his
-CocoaBridgeDoc.txt file, as are the constructs used to invoke (“send
-messages to”) Cocoa methods.</para>
+ <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 “standard name-mapping conventions”
+ referenced below are described in his CocoaBridgeDoc.txt file,
+ as are the constructs used to invoke (“send messages
+ to”) Cocoa methods.</para>
<para>All of the symbols described below are currently internal to
the CCL package.</para>
- <colspec>
- <thead cols=3D"1">
- <tbody colwidth=3D"100*"></tbody>
- <row>
- <abstract>
- <entry>CCL::@CLASS</entry>
- =
- </abstract>
- <abstract>
- <entry>CCL::@SELECTOR</entry>
- =
- </abstract>
- <abstract>
- <entry>CCL::DEFINE-OBJC-METHOD</entry>
- =
- </abstract>
- <abstract>
- <entry>CCL::DEFINE-OBJC-CLASS-METHOD</entry>
- =
- </abstract>
- </row>
- </thead>
- </colspec>
+ <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">
- <para>The Application Kit and Multiple Threads
-The Cocoa API is broken into several pieces. The Application Kit,
-affectionately called AppKit, is the one which deals with window
-management, drawing, and handling events. AppKit really wants all
-these things to be done by a "distinguished thread". creation, and
-drawing to take place on a distinguished thread.</para>
- <para>Apple has published some guidelines which discuss these issu=
es 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 explor=
atory
-programming by typing things into a listener or evaluating a “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 maint=
ain a
-current “autorelease pool” (an instance of the NSAutoreleasePo=
ol
-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 “-release” message, which c=
auses
-it to send “-release” messages to all of the objects that've b=
een
-added to it.</para>
- <para>If the current thread doesn't have a current autorelease poo=
l, 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 “New Listener” command in the IDE) is =
given
-a default autorelease pool; there are REPL colon-commands for
-manipulating the current listener's “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 durin=
g 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 “handled” in the dynamic context in which it
-occurs.)</para>
+ <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
+ “defun” 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 “autorelease pool” (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 “-release” message, which causes it
+ to send “-release” 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
+ “New Listener” command in the IDE) is given a
+ default autorelease pool; there are REPL colon-commands for
+ manipulating the current listener's “toplevel
+ auturelease pool”.</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
+ “handled” 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
@@ -8806,23 +12117,24 @@
</sect2>
=
<sect2 id=3D"Acknowledgement--2-">
- <para>Acknowledgement
-The Cocoa bridge was originally developed, and generously contributed
-by, Randal Beer.</para>
+ <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">
- <para>Building an Application Bundle
-You may have noticed that (require "COCOA") takes a long time to load.
-It is possible to avoid this by saving a Lisp heap image which has
-everything already loaded. There is an example file which allows you
-to do this, "ccl/examples/cocoa-application.lisp", by producing a
-double-clickable application which runs your program. First, load
-your own program. Then, do:</para>
+ <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>
+ </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
@@ -8855,512 +12167,980 @@
</sect1>
=
<sect1 id=3D"Recommended-Reading">
- <para>Recommended Reading</para>
- <term><indexterm>Cocoa Documentation
- <variablelist>This is the top page for all of Apple's documentat=
ion onCocoa. If you are unfamiliar with Cocoa, it is a goodplace to start.=
</variablelist>
- </indexterm><indexterm>Foundation Reference for Objective-C
- <variablelist>This is one of the two most important Cocoa refere=
nces; itcovers all of the basics, except for GUI programming. This isa ref=
erence, not a tutorial.</variablelist>
- </indexterm><indexterm>Application Kit Reference for Objective-C
- <variablelist>This is the other; it covers GUI programming with =
Cocoain considerable depth. This is a reference, not a tutorial.</variable=
list>
- </indexterm><indexterm>Apple Developer Documentation
- <variablelist>This is the site which the above two documents are=
found on;go here to find the documentation on any other Apple API.Also go =
here if you need general guidance about OS X, Carbon,Cocoa, Core Foundation=
, or Objective C.</variablelist>
- </indexterm>
- </term>
+ <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">
- <para>Operating-System Dictionary</para>
-
- <sect2 id=3D"CCL--GETENV">
- <para>CCL::GETENV</para>
- <informalfigure>getenv</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::GETENV —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-getenv name =3D> value
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>name
- <variablelist>a string which is the name of an existingenviron=
ment variable;case-sensitive</variablelist>
- </indexterm><indexterm>value
- <variablelist>if there is an environment variable named<litera=
l>name</literal>, its value, as a string; if thereis not, NIL</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Looks up the value of the environment variable named by
-<literal>name</literal>, in the OS environment.</para>
- </sect2>
-
- <sect2 id=3D"CCL--SETENV">
- <para>CCL::SETENV</para>
- <informalfigure>setenv</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::SETENV —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-setenv name value =3D> errno
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>name
- <variablelist>a string which is the name of a new or existinge=
nvironment variable;case-sensitive</variablelist>
- </indexterm><indexterm>value
- <variablelist>a string, to be the new value of theenvironment =
variablenamed by <literal>name</literal></variablelist>
- </indexterm><indexterm>errno
- <variablelist>zero if the function call completes successfully=
;otherwise, a platform-dependent integer which describesthe problem</variab=
lelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Sets the value of the environment variable named by
-<literal>name</literal>, in the OS environment. If there is
-no such environment
-variable, creates it.</para>
- </sect2>
-
- <sect2 id=3D"CCL--CURRENT-DIRECTORY-NAME">
- <para>CCL::CURRENT-DIRECTORY-NAME</para>
- <informalfigure>current-directory-name</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::CURRENT-DIRECTORY-NAME —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-current-directory-name
- =3D> path
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>path
- <variablelist>a string, an absolute pathname in Posix format -=
withdirectory components separated by slashes</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Looks up the current working directory of the OpenMCL proces=
s;
-unless it has been changed, this is the directory OpenMCL was
-started in.</para>
- </sect2>
-
- <sect2 id=3D"CCL--GETUID">
- <para>CCL::GETUID</para>
- <informalfigure>getuid</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::GETUID —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-getuid =3D> uid
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>uid
- <variablelist>a non-negative integer, identifying a specific u=
seraccount as defined in the OS user database</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the ("real") user ID of the current user.</para>
- </sect2>
-
- <sect2 id=3D"CCL--SETUID">
- <para>CCL::SETUID</para>
- <informalfigure>setuid</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::SETUID —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-setuid uid =3D> errno
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>uid
- <variablelist>a non-negative integer, identifying a specific u=
seraccount as defined in the OS user database</variablelist>
- </indexterm><indexterm>errno
- <variablelist>zero if the function call completes successfully=
;otherwise, a platform-dependent integer which describesthe problem</variab=
lelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Attempts to change the current user ID (both "real" and
-"effective"); fails unless
-the OpenMCL process has super-user privileges or the ID
-given is that of the current user.</para>
- </sect2>
-
- <sect2 id=3D"CCL--SETGID">
- <para>CCL::SETGID</para>
- <informalfigure>setgid</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::SETGID —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-setgid gid =3D> errno
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>gid
- <variablelist>a non-negative integer, identifying a specificgr=
oup as defined in the OS user database</variablelist>
- </indexterm><indexterm>errno
- <variablelist>zero if the function call completes successfully=
;otherwise, a platform-dependent integer which describesthe problem</variab=
lelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Attempts to change the current group ID (both "real" and
-"effective"); fails unless
-the OpenMCL process has super-user privileges or the ID
-given is that of a group to which the current user belongs.</para>
- </sect2>
-
- <sect2 id=3D"CCL--GETPID">
- <para>CCL::GETPID</para>
- <informalfigure>getpid</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::GETPID —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-getpid =3D> pid
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>pid
- <variablelist>a non-negative integer, identifying an OS proces=
s</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the ID of the OpenMCL OS process.</para>
- </sect2>
-
- <sect2 id=3D"CCL--GET-USER-HOME-DIR">
- <para>CCL::GET-USER-HOME-DIR</para>
- <informalfigure>get-user-home-dir</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::GET-USER-HOME-DIR —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-get-user-home-dir
- uid =3D> path
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>uid
- <variablelist>a non-negative integer, identifying a specific u=
seraccount as defined in the OS user database</variablelist>
- </indexterm><indexterm>path
- <variablelist>a string, an absolute pathname in Posix format -=
withdirectory components separated by slashes; or NIL</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Looks up and returns the defined home directory of the user
-identified by <literal>uid</literal>. This value comes from the
-OS user database, not from the <literal>$HOME</literal>
-environment variable. Returns NIL if there is no user with
-the ID <literal>uid</literal>.</para>
- </sect2>
-
- <sect2 id=3D"CCL--OS-COMMAND">
- <para>CCL::OS-COMMAND</para>
- <informalfigure>os-command</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::OS-COMMAND —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-os-command command-line
- =3D> exit-code
-</programlisting>
- <bridgehead renderas=3D"sect3">Values</bridgehead>
- <term><indexterm>command-line
- <variablelist>a string, obeying all the whitespace andescaping=
conventions required by the user's default system shell</variablelist>
- </indexterm>
- </term>
- <term><indexterm>exit-code
- <variablelist>a non-negative integer, returned as the exitcode=
of a subprocess; zero indicates success</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Invokes the Posix function <literal>system()</literal>, which
-invokes the user's default system shell (such as
-sh or tcsh) as a new process, and has that shell execute
-<literal>command-line</literal>.</para>
- <para>If the shell was able to find the command specified in
-<literal>command-line</literal>, then <literal>exit-code</literal>
-is the exit code of that command. If not, it is the exit
-code of the shell itself.</para>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para>By convention, an exit code of 0 indicates success. There a=
re
-also other conventions; unfortunately, they are OS-specific, and
-the portable macros to decode their meaning are implemented
-by the system headers as C preprocessor macros. This means
-that there is no good, automated way to make them available
-to Lisp.</para>
- </sect2>
-
- <sect2 id=3D"CCL----CLASS">
- <para>CCL::@CLASS</para>
- <informalfigure>@class</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::@CLASS —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
- at class class-name
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>class-name
- <variablelist>a string which denotes an existing class name, o=
r asymbol which can be mapped to such a string via the standardname-mapping=
conventions for class names</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Used to refer to a known ObjC class by name. (Via the use
-LOAD-TIME-VALUE, the results of a class-name -> class lookup
-are cached.)</para>
- <para><literal>@class</literal> is obsolete as of late 2004, becau=
se
-find-class now works on ObjC classes. It is described here
-only because some old code still uses it.</para>
- </sect2>
-
- <sect2 id=3D"CCL----SELECTOR">
- <para>CCL::@SELECTOR</para>
- <informalfigure>@selector</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::@SELECTOR —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
- at selector string
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>string
- <variablelist>a string constant, used to canonically refer to =
anObjC method selector</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Used to refer to an ObjC method selector (method name). Uses
-LOAD-TIME-VALUE to cache the result of a string -> selector
-lookup.</para>
- </sect2>
-
- <sect2 id=3D"CCL--DEFINE-OBJC-METHOD">
- <para>CCL::DEFINE-OBJC-METHOD</para>
- <informalfigure>define-objc-method</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::DEFINE-OBJC-METHOD —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-define-objc-method
- (selector class-name) &body body
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>selector
- <variablelist>either a string which represents the name of the=
selector or a list which describ+es the method's returntype, selector compo=
nents, and argument types (see below.)If the first form is used, then the f=
irst form in the bodymust be a list which describes the selector's argument=
types and return value type, as per DEFCALLBACK.</variablelist>
- </indexterm><indexterm>class-name
- <variablelist>either a string which names an existing ObjC cla=
ssname or a list symbol which can map to such a string via thestandard name=
-mapping conventions for class names. (Notethat the "canonical" lisp class =
name is such asymbol)</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Defines an ObjC-callable method which implements the
-specified message selector for instances of the existing ObjC
-class class-name.</para>
- </sect2>
-
- <sect2 id=3D"CCL--DEFINE-OBJC-CLASS-METHOD">
- <para>CCL::DEFINE-OBJC-CLASS-METHOD</para>
- <informalfigure>define-objc-class-method</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::DEFINE-OBJC-CLASS-METHOD —</para>
- <para>Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-define-objc-class-method
- (selector class-name) &body body
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <para>As per DEFINE-OBJC-METHOD</para>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Like DEFINE-OBJC-METHOD, only used to define methods on the
-<emphasis>class</emphasis> named by class-name and on its
-subclasses.</para>
- <para>For both DEFINE-OBJC-METHOD and DEFINE-OBJC-CLASS-METHOD, the
-"selector" argument can be a list whose first element is a
-foreign type specifier for the method's return value type and whose
-subsequent elements are either:</para>
- <listitem mark=3D"bullet">
- <variablelist>a non-keyword symbol, which can be mapped to a sel=
ector stringfor a parameterless method according to the standard name-mappi=
ngconventions for method selectors.</variablelist>
- <variablelist>a list of alternating keywords and variable/type s=
pecifiers,where the set of keywords can be mapped to a selector string for =
aparameteriezed method according to the standard name-mappingconventions fo=
r method selectors and each variable/type-specifier iseither a variable nam=
e (denoting a value of type :ID) or a list whoseCAR is a variable name and =
whose CADR is the correspondingargument's foreign type specifier.</variable=
list>
- =
- </listitem>
- </sect2>
-
- <sect2 id=3D"CCL--ALTERNATE-LINE-TERMINATOR-">
- <para>CCL:*ALTERNATE-LINE-TERMINATOR*</para>
- <informalfigure>*alternate-line-terminator*</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL:*ALTERNATE-LINE-TERMINATOR* —</para>
- <para>Variable</para>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>This variable is currently only used by the standard reader =
macro
-function for #\; (single-line comments); that function reads successive
-characters until EOF, a #\NewLine is read, or a character EQL to the
-value of *alternate-line-terminator* is read. In OpenMCL for Darwin, the
-value of this variable is initially #\Return ; in OpenMCL for LinuxPPC,
-it's initially NIL.</para>
- <para>Their default treatment by the #\; reader macro is the prima=
ry way
-in which #\Return and #\Linefeed differ syntactally; by extending the
-#\; reader macro to (conditionally) treat #\Return as a
-comment-terminator, that distinction is eliminated. This seems to make
-LOAD and COMPILE-FILE insensitive to line-termination issues in many
-cases. It could fail in the (hopefully rare) case where a LF-terminated
-(Unix) text file contains embedded #\Return characters, and this
-mechanism isn't adequate to handle cases where newlines are embedded
-in string constants or other tokens (and presumably should be translated
-from an external convention to the external one) : it doesn't change
-what READ-CHAR or READ-LINE "see", and that may be necessary to
-handle some more complicated cases.</para>
- </sect2>
-
- <sect2 id=3D"iEXTERNAL-FORMAT">
- <para>:EXTERNAL-FORMAT</para>
- <informalfigure>:external-format</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>:EXTERNAL-FORMAT —</para>
- <para>Keyword Argument</para>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Per ANSI CL, OpenMCL supports the :EXTERNAL-FORMAT keyword
-argument to the functions OPEN, LOAD, and COMPILE-FILE. This argument is
-intended to provide a standard way of providing implementation-dependent
-information about the format of files opened with an element-type of
-CHARACTER. This argument can meaningfully take on the values :DEFAULT
-(the default), :MACOS, :UNIX, or :INFERRED in OpenMCL.</para>
- <para>When defaulted to or specified as :DEFAULT, the format of th=
e file
-stream is determined by the value of the variable
-CCL:*DEFAULT-EXTERNAL-FORMAT*. See below.</para>
- <para>When specified as :UNIX, all characters are read from and wr=
itten
-to files verbatim.</para>
- <para>When specified as :MACOS, all #\Return characters read from =
the
-file are immediately translated to #\Linefeed (#\Newline); all #\Newline
-(#\Linefeed) characters are written externally as #\Return characters.</pa=
ra>
- <para>When specified as :INFERRED and the file is open for input, =
the
-first bufferful of input data is examined; if a #\Return character
-appears in the buffer before the first #\Linefeed, the file stream's
-external-format is set to :MACOS; otherwise, it is set to :UNIX.</para>
- <para>All other values of :EXTERNAL-FORMAT - and any combinations =
that
-don't make sense, such as trying to infer the format of a
-newly-created output file stream - are treated as if :UNIX was
-specified. As mentioned above, the :EXTERNAL-FORMAT argument doesn't
-apply to binary file streams.</para>
- <para>The translation performed when :MACOS is specified or inferr=
ed has
-a somewhat greater chance of doing the right thing than the
-*alternate-line-terminator* mechanism does; it probably has a somewhat
-greater chance of doing the wrong thing, as well.</para>
- </sect2>
-
- <sect2 id=3D"CCL--DEFAULT-EXTERNAL-FORMAT-">
- <para>CCL:*DEFAULT-EXTERNAL-FORMAT*</para>
- <informalfigure>*default-external-format*</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL:*DEFAULT-EXTERNAL-FORMAT* —</para>
- <para>Variable</para>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>The value of this variable is used when :EXTERNAL-FORMAT is
-unspecified or specified as :DEFAULT. It can meaningfully be given any
-of the values :UNIX, :MACOS, or :INFERRED, each of which is interpreted
-as described above.</para>
- <para>Because there's some risk that unsolicited newline translati=
on
-could have undesirable consequences, the initial value of this variable
-in OpenMCL is :UNIX.</para>
- </sect2>
-
- <sect2 id=3D"CCL--NS-LISP-STRING">
- <para>CCL::NS-LISP-STRING</para>
- <informalfigure>ns-lisp-string</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CCL::NS-LISP-STRING —</para>
- <para>Class</para>
- <bridgehead renderas=3D"sect3">Superclasses</bridgehead>
- <para>NS:NS-STRING</para>
- <bridgehead renderas=3D"sect3">Initargs</bridgehead>
- <term><indexterm>:string
- <variablelist>a Lisp string which is to be the content ofthe n=
ewly-created ns-lisp-string.</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>This class
-implements the interface of an NSString, which means that it can
-be passed to any Cocoa or Core Foundation function which expects
-one.</para>
- <para>The string itself is stored on the Lisp heap, which
-means that its memory management is automatic. However, the
-ns-lisp-string object itself is a foreign
-object (that is, it has an objc metaclass), and resides on the
-foreign heap. Therefore, it is necessary to explicitly free
-it, by sending a dealloc message.</para>
- <bridgehead renderas=3D"sect3">Examples</bridgehead>
- <para>You can create an ns-lisp-string with
-<literal>make-instance</literal>, just like
-any normal Lisp class:</para>
- <programlisting>
-? (defvar *the-string*
+ <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 -> 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 -> 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'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'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't cha=
nge
+ what READ-CHAR or READ-LINE "see", 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=
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'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=
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'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>
-? (ccl::send *the-string* 'dealloc)
-</programlisting>
- <para>You may wish to use an <literal>unwind-protect</literal>
-form to ensure that this happens:</para>
- <programlisting>
-(let (*the-string*)
+ :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 "~&The string is ~D characters long=
.~%"
(ccl::send *the-string* 'length)))
(when *the-string*
- (ccl::send *the-string* 'dealloc))))
-</programlisting>
- <bridgehead renderas=3D"sect3">Notes</bridgehead>
- <para>Currently, ns-lisp-string is defined in
-the file ccl/examples/cocoa-backtrace.lisp, which is a
-rather awkward place. It was probably not originally meant
-as a public utility at all. It would be good if it were
-moved someplace else. Use at your own risk.</para>
- </sect2>
+ (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">
- <para>Understanding and Configuring the Garbage Collector</para>
+ <title>Understanding and Configuring the Garbage Collector</title>
=
<sect1 id=3D"Heap-space-allocation">
- <para>Heap space allocation
-Release 0.10 or later of OpenMCL uses a different memory management
-scheme than previous versions did. Those earlier versions would allocate a
-block of memory (of specified size) at startup and would allocate lisp
-objects within that block. When that block filled with live (non-GCed)
-objects, the lisp would signal a "heap full" condition. The heap
-size imposed a limit on the size of the largest object that could be
-allocated.</para>
- <para>The new strategy involves reserving a very large (2GB on Darwi=
nPPC32,
-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 wa=
y 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.</p=
ara>
- <para>The -R or –heap-reserve command-line option can be use t=
o limit the
-size of the reserved block and therefore bound heap expansion. Running</pa=
ra>
+ <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 –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>
@@ -9369,478 +13149,686 @@
</sect1>
=
<sect1 id=3D"The-Ephemeral-GC">
- <para>The Ephemeral GC
-For many programs, the following observations are true to a very
-large degree:</para>
- <varlistentry numeration=3D"arabic">
- <variablelist>Most heap-allocated objects have very short lifetime=
s ("areephemeral"): they become inaccessible soon after they're created.</v=
ariablelist>
- <variablelist>Most non-ephemeral objects have very long lifetimes:=
it'srarely productive for the GC to consider reclaiming them, sinceit's ra=
rely able to do so. (An object that's survived a largenumber of GCs is like=
ly to survive the next one. That's not alwaystrue of course, but it's a rea=
sonable heuristic.)</variablelist>
- <variablelist>It's relatively rare for an old object to be destruc=
tivelymodified (via SETF) so that it points to a new one, therefore mostref=
erences to newly-created objects can be found in the stacks andregisters of=
active threads. It's not generally necessary to scanthe entire heap to fin=
d references to new objects (or to prove thatsuch references don't exists),=
though it is necessary to keeptrack of the (hopefully exceptional) cases w=
here old objects aremodified to point at new ones.</variablelist>
- </varlistentry>
- <para>"Ephemeral" (or "generational") garbage collectors try to expl=
oit
-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.</par=
a>
- <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>disab=
led</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>
+ <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're created.</=
para>
+ </listitem>
+
+ <listitem>
+ <para>Most non-ephemeral objects have very long lifetimes: it's
+ rarely productive for the GC to consider reclaiming them, since
+ it's rarely able to do so. (An object that's survived a large
+ number of GCs is likely to survive the next one. That's not always
+ true of course, but it's a reasonable heuristic.)</para>
+ </listitem>
+
+ <listitem>
+ <para>It'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's not generally necessary to scan
+ the entire heap to find references to new objects (or to prove that
+ such references don'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're created.</=
para>
+ </listitem>
+
+ <listitem>
+ <para>Most non-ephemeral objects have very long lifetimes: it's
+ rarely productive for the GC to consider reclaiming them, since
+ it's rarely able to do so. (An object that's survived a large
+ number of GCs is likely to survive the next one. That's not always
+ true of course, but it's a reasonable heuristic.)</para>
+ </listitem>
+
+ <listitem>
+ <para>It'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's not generally necessary to scan
+ the entire heap to find references to new objects (or to prove that
+ such references don'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">
- <para>GC Page reclamation policy</para>
- <para>After a full GC finishes, it'll try to ensure that at least
-(LISP-HEAP-GC-THRESHOLD) of virtual memory are available; objects will be
-allocated in this block of memory until it fills up, the GC is triggered,
-and the process repeats itself.</para>
- <para>Many programs reach near stasis in terms of the amount of logi=
cal
-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 r=
ate),
-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>
+ <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">
- <para>"Pure" areas are read-only, paged from image file
-SAVE-APPLICATION identifies code vectors and the pnames of interned
-symbols and copies these objects to a "pure" area of the image
-file it creates. (The "pure" area accounts for most of what the
-ROOM function reports as "static" space.)</para>
- <para>When the resulting image file is loaded, the pure area of the =
file
-is now memory-mapped with read-only access. Code and pure data are paged
-in from the image file as needed (and don't compete for global virtual
-memory resources with other memory areas.)</para>
- <para>Code-vectors and interned symbol pnames are immutable : it is =
an
-error to try to change the contents of such an object. Previously, that
-error would have manifested itself in some random way. In the new scheme,
-it'll manifest itself as an "unhandled exception" error in the
-Lisp kernel. The kernel could probably be made to detect a spurious,
-accidental write to read-only space and signal a lisp error in that case,
-but it doesn't yet do so.</para>
- <para>The image file should be opened and/or mapped in some mode whi=
ch
-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>
+ <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">
- <para>Weak Hash Tables
-In general, a "weak reference" is a reference to an object which
-will not prevent the object from being garbage-collected. For
-example, suppose that you want to keep a list of all the objects
-of a certain type. If you don't take special steps, the fact that
-you have a list of them will mean that the objects are always
-"live", because you can always reference them through the list.
-Therefore, they will never be garbage-collected, and their memory
-will never be reclaimed, even if they are referenced nowhere else
-in the program. You may want this behaviour. If you don't, you
-need weak references.</para>
+ <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>
+ 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">
- <para>Garbage-Collection Dictionary</para>
-
- <sect2 id=3D"LISP-HEAP-GC-THRESHOLD">
- <para>LISP-HEAP-GC-THRESHOLD</para>
- <informalfigure>lisp-heap-gc-threshold</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>LISP-HEAP-GC-THRESHOLD —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-lisp-heap-gc-threshold
-</programlisting>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns the value of the kernel variable that specifies the
-amount of free space to leave in the heap after full GC.</para>
- </sect2>
-
- <sect2 id=3D"SET-LISP-HEAP-GC-THRESHOLD">
- <para>SET-LISP-HEAP-GC-THRESHOLD</para>
- <informalfigure>set-lisp-heap-gc-threshold</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SET-LISP-HEAP-GC-THRESHOLD —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- lisp-heap-gc-threshold new-threshold
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>new-value
- <variablelist>The requested new lisp-heap-gc-threshold.</varia=
blelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Sets the value of the kernel variable that specifies the
-amount of free space to leave in the heap after full GC to
-new-value, which should be a non-negative fixnum. Returns the
-value of that kernel variable (which may be somewhat larger than
-what was specified).</para>
- </sect2>
-
- <sect2 id=3D"USE-LISP-HEAP-GC-THRESHOLD">
- <para>USE-LISP-HEAP-GC-THRESHOLD</para>
- <informalfigure>use-lisp-heap-gc-threshold</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>USE-LISP-HEAP-GC-THRESHOLD —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-
- use-lisp-heap-gc-threshold
-
-</programlisting>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Tries to grow or shrink lisp's heap space, so that the
-free space is (approximately) equal to the current heap threshold.
-Returns NIL</para>
- </sect2>
-
- <sect2 id=3D"EGC">
- <para>EGC</para>
- <informalfigure>egc</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>EGC —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-egc arg
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>arg
- <variablelist>a generalized boolean</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Enables the EGC if arg is non-nil, disables the EGC
-otherwise. Returns the previous enabled status. Although this
-function is thread-safe (in the sense that calls to it are
-serialized), it doesn't make a whole lot of sense to be
-turning the EGC on and off from multiple threads ...</para>
- </sect2>
-
- <sect2 id=3D"EGC-ENABLED-P">
- <para>EGC-ENABLED-P</para>
- <informalfigure>egc-enabled-p</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>EGC-ENABLED-P —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-egc-enabled-p
-</programlisting>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns T if the EGC was enabled at the time of the call,
-NIL otherwise.</para>
- </sect2>
-
- <sect2 id=3D"EGC-ACTIVE-P">
- <para>EGC-ACTIVE-P</para>
- <informalfigure>egc-active-p</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>EGC-ACTIVE-P —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-egc-active-p
-</programlisting>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns T if the EGC was active at the time of the call, NIL
-otherwise. Since this is generally a volatile piece of
-information, it's not clear whether this function serves a
-useful purpose when native threads are involved.</para>
- </sect2>
-
- <sect2 id=3D"EGC-CONFIGURATION">
- <para>EGC-CONFIGURATION</para>
- <informalfigure>egc-configuration</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>EGC-CONFIGURATION —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-egc-configuration
-</programlisting>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns, as multiple values, the sizes in kilobytes of the
-thresholds associated with the youngest ephemeral generation, the
-middle ephemeral generation, and the oldest ephemeral generation</para>
- </sect2>
-
- <sect2 id=3D"CONFIGURE-EGC">
- <para>CONFIGURE-EGC</para>
- <informalfigure>configure-egc</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>CONFIGURE-EGC —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-configure-egc
+ <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'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'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'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
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>generation-0-size
- <variablelist>the requested threshold size of the youngestgene=
ration, in kilobytes</variablelist>
- </indexterm><indexterm>generation-1-size
- <variablelist>the requested threshold size of the middle gener=
ation,in kilobytes</variablelist>
- </indexterm><indexterm>generation-2-size
- <variablelist>the requested threshold size of the oldest gener=
ation,in kilobytes</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>If the EGC is currently disabled, puts the indicated
-threshold sizes in effect and returns T, otherwise, returns NIL.
-(The provided threshold sizes are rounded up to a multiple of
-64Kbytes in OpenMCL 0.14 and later, and to a multiple of 32KBytes in earli=
er
-versions.)</para>
- </sect2>
-
- <sect2 id=3D"GC-RETAIN-PAGES">
- <para>GC-RETAIN-PAGES</para>
- <informalfigure>gc-retain-pages</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>GC-RETAIN-PAGES —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-gc-retain-pages arg
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>arg
- <variablelist>a generalized boolean</variablelist>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Tries to influence the GC to retain/recycle the pages
-allocated between GCs if arg is true, and to release them
-otherwise. This is generally a tradeoff between paging and other
-VM considerations.</para>
- </sect2>
-
- <sect2 id=3D"GC-RETAINING-PAGES">
- <para>GC-RETAINING-PAGES</para>
- <informalfigure>gc-retaining-pages</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>GC-RETAINING-PAGES —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-gc-retaining-pages
-</programlisting>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns T if the GC tries to retain pages between full GCs
-and NIL if it's trying to release them to improve VM paging
-performance.</para>
- </sect2>
+ 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's trying to release them to improve VM paging
+ performance.</para>
+ </refsect1>
+ </refentry>
</sect1>
</chapter>
=
<chapter id=3D"Implementation-Details-of-OpenMCL">
- <para>Implementation Details of OpenMCL
-This chapter describes many aspects of OpenMCL's implementation as of
-(roughly) version 1.1. Details vary a bit between the three archutectures
-(PPC32, PPC64, and X86-64) currently supported and those details change
-over time, so the definitive reference is the source code (especially
-some files in the ccl/compiler/ directory whose names contain the string
-"arch" and some files in the ccl/lisp-kernel/ directory whose namee
-contain the string "constants".) Hopefully, this chapter will make
-it easier for someone who's interested to read and understand the
-contents of those files.</para>
+ <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">
- <para>Threads and exceptions
-OpenMCL's threads are "native" (meaning that they're scheduled and
-controlled by the operating system.) Most of the implications of
-this are discussed elsewhere; this section tries to describe how
-threads look from the lisp kernel's perspective (and especailly
-from the GC's point of view.)</para>
- <para>OpenMCL's runtime system tries to use machine-level exception
-mechanisms (conditional traps when available, illegal instructions,
-memory access protection in some cases) to detect and handle ...
-exceptional situations. These situations include some TYPE-ERRORs
-and PROGRAM-ERRORS (notably wrong-number-of-args errors), and also
-include cases like "not being able to allocate memory without GCing
-or obtaining more memory from the OS." The general idea is that
-it's usually faster to pay (very occasional) exception-processing
-overhead and figure out what's going on in an exception handler than
-it is to maintain enough state and context to handle an exceptional
-case via a lighter-weight mechanism when that exceptional case
-(by definition) rarely occurs.</para>
- <para>Some emulated execution environments (the Rosetta PPC emulator=
on
-x86 versions of OSX) don't provide accurate exception information
-to exception handling functions. OpenMCL can't run in such environments.</=
para>
+ <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">
- <para>The Thread Context Record
-When a lisp thread is first created (or when a thread created by
-foreign code first calls back to lisp), a data structure called
-a Thread Context Record (or TCR) is allocated and initialized. On
-modern versions of Linux and FreeBSD, the allocation actually happens
-via a set of thread-local-storage ABI extensions, so a thread's
-TCR is created when the thread is created and dies when the thread
-dies. (The World's Most Advanced Operating System - as Apple's
-marketing literature refers to Darwin - is not very advanced in this
-regard, and I know of no reason to assume that advances will be made
-in this area anytime soon.)</para>
- <para>A TCR contains a few dozen fields (and is therefore a few hu=
ndred
-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 sa=
ved 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>
+ <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">
- <para>Exception contexts, and exception-handling in general
-Unix-like OSes tend to refer to exceptions as "signals"; the same
-general mechanism ("signal handling") is used to process both
-asynchronous OS-level events (such as the result of the keyboard driver
-noticing that ^C or ^Z has been pressed) and synchronous hardware-level
-events (like trying to execute and illegal instruction or access
-protected memory.) It makes some sense to defer ("block") handling
-of aysnchronous signals so that some critical code sequences complete
-without interruption; since it's generally not possible for a thread
-to proceed after a synchronous exception unless and until its state
-is modified by an exception handler, it makes no sense to talk about
-blocking synchronous signals (though some OSes will let you do so
-and doing so can have mysterious effects.)</para>
- <para>On OSX/Darwin, the POSIX signal handling facilities coexist =
with
-lower-level Mach-based exception handling facilities. Unfortunately,
-the way that this is implemented interacts poorly with debugging
-tools: GDB will generally stop whenever the target program
-encounters a Mach-level exception and offers no way to proceed from
-that point (and let the program's POSIX signal handler try to handle
-the exception); Apple's CrashReporter program has had a similar issue
-and, depending on how it's configured, may bombard the user with
-alert dialogs which falsely claim that an application has crashed
-(when in fact the application in question has routinely handled
-a routine exception.) On Darwin/OSX, OpenMCL uses Mach thread-level
-exception handling facilities which run before GDB or CrashReporter
-get a chance to confuse themeselves; OpenMCL's Mach exception handling
-tries to force the thread which received a synchronous exception to
-invoke a signal handling function ("as if" signal handling worked
-more usefully under Darwin.) Mach exception handlers run in a dedicated
-thread (which basically does nothing but wait for exception messages
-from the lisp kernel, obtain and modify information about the state
-of threads in which exceptions have occurred, and reply to the
-exception messages with an indication that the exception has been
-handled. The reply from a thread-level exception handler keeps the
-exception from being reported to GDB or CrashReporter and avoids
-the problems related to those programs. Since OpenMCL's Mach exception
-handler doesn't claim to handle debugging-related exceptions (from
-breakpoints or single-step operations), it's possible to use GDB to
-debug OpenMCL.</para>
+ <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
@@ -9858,92 +13846,113 @@
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 contex=
t (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 hand=
le
-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' ca=
use
-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>
+ <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">
- <para>Threads, exceptions, and the GC
-OpenMCL's GC is not concurrent: when the GC is invoked in response to an
-exception in a particular thread, all other lisp threads must stop until
-the GC's work is done. The thread that triggered the GC iterates over
-the global TCR list, sending each other thread a distinguished "suspend"
-signal, then iterates over the list again, waiting for a per-thread
-semaphore that indicates that the thread has received the "suspend"
-signal and responded appropriatedly. Once all other threads have
-acknowledged the request to suspend themselves, the GC thread can
-run the GC proper (after doing any necessary .) Once
-the GC's completed its work, the thread that invoked the GC iterates
-over the global TCR list, raising a per-thread "resume" semaphore
-for each other thread.</para>
- <para>The signal handler for the asynchronous "suspend" signal is =
entered
-with all asynchronous signals blocked. It saves its signal-context
-argument in a TCR slot, raises the tcr's "suspend" semaphore, then
-waits on the TCR's "resume" semaphore.</para>
- <para>The GC thread has access to the signal contexts of all TCRs =
(including
-its own) at the time when the thread received an exception or
-acknowledged a request to suspend itself. This information (and
-information about stack areas in the TCR itself) allows the GC to
-identify the "stack locations and register contents" that are elements
-of the GC's root set.</para>
+ <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">
- <para>PC-luseringIt's not quite accurate to say that OpenMCL's com=
piler and runtime
-follow precise stack and register usage conventions at all times; there
-are a few exceptions:</para>
- <listitem mark=3D"bullet">
- <variablelist>On both PPC and x86-64 platforms, consing isn't fu=
lly atomic.It takes at least a few instructions to allocate an object in me=
mory(and slap a header on it if necesssary); if a thread is interrupted int=
he middle of that instruction sequence, the new object may or may nothave b=
een created or fully initialized at the point in time that theinterrupt occ=
urred. (There are actually a few different states ofpartial initialization=
)</variablelist>
- <variablelist>On the PPC, the common act of building a lisp cont=
rol stack frameinvolves allocating a four-word frame and storing three regi=
ster valuesinto that frame. (The fourth word - the back pointer to the pre=
viousframe - is automatically set when the frame is allocated.) The previo=
uscontents of those three words are unknown (there might have been aforeign=
stack frame at the same address a few instructions earlier),so interruptin=
g a thread that's in the process of initializing aPPC control stack frame i=
sn't GC-safe.</variablelist>
- <variablelist>There are similar problems with the initialization=
of temp stackframes on the PPC. (Allocation and initialization doesn't ha=
ppenatomically, and the newly allocated stack memory may have undefinedcont=
ents.)</variablelist>
- <variablelist>'s write barrier has to be implemented atomically =
(i.e.,both an intergenerational store and the update of a correspondingrefe=
rence bit has to happen without interruption, or neither of theseevents can=
happen.)</variablelist>
- <variablelist>There are a few more similar cases.</variablelist>
+ <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>
=
- </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
@@ -9961,287 +13970,621 @@
</sect1>
=
<sect1 id=3D"Register-usage-and-tagging">
- <para>Register usage and tagging</para>
+ <title>Register usage and tagging</title>
=
<sect2 id=3D"Register-usage-and-tagging-overview">
- <para>Register usage and tagging overview
-Regardless of other details of its implementation, a garbage
-collector's job is to partition the set of all heap-allocated
-lisp objects (CONSes, STRINGs, INSTANCEs, etc.) into two subsets.
-The first subset contains all objects that are transitively referenced
-from a small set of "root" objects (the contents of the stacks
-and registers of all active threads at the time the GC occurs
-and the values of some global variables.) The second subset contains
-everything else: those lisp objects that are not transitively
-reachable from the roots are garbage, and the memory occupied
-by garbage objects can be reclaimed (since the GC has just proven
-that it's impossible to reference them.)</para>
- <para>The set of live, reachable lisp objects basically form the n=
odes
-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 a=
rray 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 reliab=
ly, 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 stoc=
k 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 ("conser=
vative") 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.</p=
ara>
- <para>Once we've decided that a given machine word is a node, a d=
escribes 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 ve=
ry 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>
+ <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">
- <para>pc-locatives on the PPC
-On the PPC, there's a third case (besides "node" and "immediate" values).
-As discussed below, a node that denotes a memory-allocated lisp object
-is a biased (tagged) pointer -to- that object; it's not generally possible
-to point -into- some composite (multi-element) object (such a pointer
-would not be a node, and the GC would have no way to update the pointer
-if it were to move the underlying object.)</para>
- <para>Such a pointer ("into" the interior of a heap-allocated obje=
ct) is
-often called a <emphasis>locative</emphasis>; the cases where locatives ar=
e 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 instructi=
ons are
-32 bits wide and all instruction words are allocated on 32-bit boundaries.
-In PPC OpenMCL, a CODE-VECTOR is a specialized type of vector-like object;
-its elements are 32-bit PPC machine instructions. A CODE-VECTOR is
-an attribute of FUNCTION object; a function call involves accessing the
-function's code-vector and jumping to the address of its first instruction=
.</para>
- <para>As each instruction in the code vector sequentially executes=
, the
-hardware program counter (PC) register advances to the address of the
-next instruction (a locative into the code vector); since PPC
-instructions are always 32 bits wide and aligned on 32-bit boundaries,
-the low two bits of the PC are always 0. If the function executes a
-call (simple call instrucions have the mnemonic "bl" on the PPC, which
-stands for "branch and link"), the address of the next instruction (also
-a word-aligned locative into a code-vector) is copied into the special-
-purpose PPC "link register" (lr); a function returns to its caller
-via a "branch to link register" (blr) instruction. Some cases of
-function call and return might also use the PPC's "count register"
-(ctr), and if either the lr or ctr needs to be stored in memory it
-needs to first be copied to a general-purpose registers.</para>
- <para>OpenMCL's GC understands that certain registers contain thes=
e 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>
+ <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">
- <para>Register and stack usage conventions</para>
+ <title>Register and stack usage conventions</title>
=
<sect3 id=3D"Stack-conventions">
- <para>Stack conventions
-On both PPC and X86 platforms, each lisp thread uses 3 stacks; the ways
-in which these stacks are used differs between the PPC and X86.</para>
+ <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>
- <listitem mark=3D"bullet">
- <variablelist>A "control stack".On both platforms, this is "th=
e stack" used by foreign code.On the PPC, it consists of a linked list of f=
rameswhere the first word in each frame points to the first word in theprev=
ious frame (and the outermost frame points to 0.) Some frameson a PPC cont=
rol stack are lisp frames; lisp frames are always 4 wordsin size and contai=
n (in addition to the back pointer to the previousframe) the calling functi=
on (a node), the return address (a "locative"into the calling function's co=
de-vector), and the value to which thevalue-stack pointer (see below) shoul=
d be restored on function exit.On the PPC, the GC has to look at control-st=
ack frames, identifywhich of those frames are lisp frames, and treat the co=
ntents ofthe saved function slot as a node (and handle the return addresslo=
cative specially.)On x86-64, the control stack is used for dynamic-extent a=
llocationof immediate objects. Since the control stack never contains node=
son x86-64, the GC ignores it on that platform.Alignment of the control sta=
ck follows the ABI conventions of theplatform (at least at any point in tim=
e where foreign code could run.)On PPC, the r1 register always points to th=
e top of the current thread'scontrol stack; on x86-64, the RSP register poi=
nts to the top of thecurrent thread's control stack when the thread is runn=
ing foreigncode and the address of the top of the control stack is kept in =
thethread's TCR see when not running foreigncode.The control stack "grows =
down."</variablelist>
- <variablelist>A "value stack".On both platforms, all values on=
the value stack are nodes (including"tagged return addresses" on x86-64.) =
The value stack is always alignedto the native word size; objects are alwa=
ys pushed on the value stackusing atomic instructions ("stwu"/"stdu" on PPC=
, "push" on x86-64), sothe contents of the value stack between its bottom a=
nd 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 addres=
ses 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 li=
sp code, and theVSP value is saved in the TCR when running foreign code.The=
value stack grows down.</variablelist>
- <variablelist>A "temp stack".The temp stack consists of a link=
ed list of frames, each of which pointsto the previous temp stack frame. T=
he number of native machine wordsin each temp stack frame is always even, s=
o 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 ob=
jects contain nodes); on the x86-64, immediatedynamic-extent objects (strin=
gs, foreign pointers, etc.) are allocatedon the control stack and only node=
-containing dynamic-extent objectsare allocated on the temp stack.Data stru=
ctures used to implement CATCH and UNWIND-PROTECT are stored onthe temp sta=
ck on both ppc and x86-64.Temp stack frames are always doublenode aligned a=
nd 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 theremainin=
g 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 alw=
ays 0.The temp stack grows down. It usually takes several instuctions toal=
locate and safely initialize a temp stack frame that's intended tocontain n=
odes, 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 inter=
pret 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) w=
hen running lisp code and saves this register'svalue in the TCR when runnin=
g foreign code. The x86-64 keeps theaddress of the top of each thread's te=
mp stack in the thread's TCR.</variablelist>
- =
- </listitem>
+ <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">
- <para>Register conventions
-If there are a "reasonable" (for some value of "reasonable") number or
-general-purpose registers and the instruction set is "reasonably"
-orthogonal (most instructions that operate on GPRs can operate on any
-GPR), then it's possible to statically partition the GPRs into at least
-two sets: "immediate registers" never contain nodes, and "node registers"
-always contain nodes. (On the PPC, a few registers are members of a
-third set of "PC locatives", and on both platforms some registers may
-have dedicated roles as stack or heap pointers; the latter class is
-treated as immediates by the GC proper but may be used to help determine
-the bounds of stack and heap memory areas.)</para>
- <para>The ultimate definition of register partitioning is hardwi=
red
-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>
+ <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>
- <listitem mark=3D"bullet">
- <variablelist>(only) two "immediate" registers.The RAX and RDX=
registers are used as the implicit operands andresults of some extended-pr=
ecision multiply and divide instructionswhich generally involve non-node va=
lues; since their use in theseinstructions means that they can't be guarant=
eed 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",an=
d RDX is given the symbolic name "imm1"; you may see these namesin disassem=
bled code, usually in operations involving type checking,array indexing, an=
d foreign memory and function access.</variablelist>
- <variablelist>(only) two "dedicated" registers.RSP and RBP hav=
e dedicated functionality dictated by the hardwareand calling conventions. =
(There are a few places where RBP istemporarily used as an extra immediate=
register.)</variablelist>
- <variablelist>12 "node" registers.All other registers (RBX, RC=
X, RSI, RDI, and R8-R15) are asserted tocontain node values at (almost) all=
times; legacy "string" operationsthat implicitly use RSI and/or RDI are no=
t used. Shift and rotateintructions which shift/rotate by a variable numbe=
r of bits arerequired by the architecture to use the low byte of RCX (the t=
raditionalCL 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 i=
t as a node, but since it's not pointing anywherenear the lisp heap it'll s=
oon 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 int=
roducenon-node values into RCX.)</variablelist>
- =
- </listitem>
+ <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>
- <listitem mark=3D"bullet">
- <variablelist>6 "immediate" registersRegisters r3-r8 are given=
the symbolic names imm0-imm5. As a RISCarchitecture with simpler addressi=
ng modes, the PPC probably usesimmediate registers a bit more often than th=
e CISC x86-64 does, butthey're generally used for the same sort of things (=
type checking,array indexing, FFI, etc.)</variablelist>
- <variablelist>9 dedicated registers
- <listitem mark=3D"bullet">
- <variablelist>r0 (symbolic name rzero) always contains the=
value 0 when runninglisp code. Its value is sometimes read as 0 when it's=
used as thebase register in a memory address; keeping the value 0 there is=
sometimes convenient and avoids asymmetry.</variablelist>
- <variablelist>r1 (symbolic name sp) is the control stack p=
ointer, by PPC convention.</variablelist>
- <variablelist>r2 is used to hold the current thread's TCR =
on ppc64 systems; it'snot used on ppc32.</variablelist>
- <variablelist>r9 and r10 (symbolic names allocptr and allo=
cbase) are used to do per-thread memory allocation</variablelist>
- <variablelist>r11 (symbolic name nargs) contains the numbe=
r of function arguments on entry and the number of return values in multipl=
e-value returning constructs. It's not used more generally as either a nod=
e or immediate register because of the way that certain trap instruction en=
codings are interpreted.</variablelist>
- <variablelist>r12 (symbolic name tsp) holds the top of the=
current thread's temp stack.</variablelist>
- <variablelist>r13 is used to hold the TCR on PPC32 sytems;=
it's not used on PPC64.</variablelist>
- <variablelist>r14 (symbolic name loc-pc) is used to copy "=
pc-locative" values between main memory and special-purpose PPC registers (=
LR and CTR) used in function-call and return instructions.</variablelist>
- <variablelist>r15 (symbolic name vsp) addresses the top of=
the current thread's value stack.</variablelist>
- <variablelist>lr and ctr are PPC branch-unit registers use=
d in function call and return instructions; they're always treated as "pc-l=
ocatives", which precludes the use of the ctr in some PPC looping construct=
s.</variablelist>
+
+ <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>
=
- </listitem>
-</variablelist>
- <variablelist>17 "node" registersr15-r31 are always treated as=
node registers</variablelist>
- =
- </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">
- <para>Tagging schemeOpenMCL always allocates lisp objects on doubl=
e-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 p=
latforms (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 <=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 quick=
ly devolve
-into machine-dependencies. We can fairly easily see that we can't
-directly all other primitive lisp object types with only 6 or 14
-available tag values; the details of how types are encoded vary between
-the ppc32, ppc64, and x86-64 implementations, but there are some general
-common principles:</para>
- <listitem mark=3D"bullet">
- <variablelist>CONS cells always contain exactly 2 elements and a=
re 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 impli=
cations - theredoesn't seem to be any advantage to using any particular val=
ue. (A longtime ago - in the case of 68K MCL - the CONS tag and the order =
of CARand CDR in memory were chosen to allow smaller, cheaper addressing mo=
desto be used to "cdr down a list." That's not a factor on ppc or x86-64,b=
ut all versions of OpenMCL still store the CDR of a CONS cell first inmemor=
y. It doesn't matter, but doing it the way that the host systemdid made bo=
ostrapping to a new target system a little easier.)</variablelist>
- <variablelist>Any way you look at it, NIL is a bit ... unusual.N=
IL is both a SYMBOL and a LIST (as well as being a canonical truthvalue and=
probably a few other things.) Its role as a LIST is probablymuch more imp=
ortant to most programs than its role as a SYMBOL is:LISTP has to be true o=
f NIL and primitives like CAR and CDR do LISTPimplicitly when safe and want=
that operation to be fast.There are several possible approaches to this; O=
penMCL uses two of them.On PPC32 and X86-64, NIL is basically a weird CONS =
cell that straddlestwo doublenodes; the tag of NIL is unique and congruent =
modulo 4 (modulo8 on 64-bit) with the tag used for CONS cells. LISTP is th=
ereforetrue of any node whose low 2 (or 3) bits contain the appropriate tag=
value (it's not otherwise necessary to special-case NIL.) SYMBOLaccessors =
(SYMBOL-NAME, SYMBOL-VALUE, SYMBOL-PLIST ..) -do- haveto special-case NIL (=
and access the components of an internal proxysymbol.)On PPC64 (where archi=
tectural restrictions dictate the set of tagsthat can be used to access fix=
ed components of an object), thatapproach wasn't practical. NIL is just a =
distinguished SYMBOL,and it just happens to be the case that its pname slot=
and valueslots are at the same offsets from a tagged pointer as a CONS cel=
lsCDR and CAR would be. NIL's pname is set to NIL (SYMBOL-NAMEchecks for t=
his and returns the string "NIL"), and LISTP (andtherefore safe CAR and CDR=
) have to check for (OR NULL CONSP).At least in the case of CAR and CDR, th=
e fact that the PPC hasmultiple condition-code fields keeps that extra test=
from beingprohibitively expensive.</variablelist>
- <variablelist>Some objects are immediate.(but not FIXNUMs).This =
is true of CHARACTERs and, on 64-bit platforms, SINGLE-FLOATs.It's also tru=
e of some nodes used in the runtime system (specialvalues used to indicate =
unbound variables and slots, for instance.)On 64-bit platforms, SINGLE-FLOA=
Ts have their own unique tag (makingthem a little easier to recognize; on a=
ll platforms, CHARACTERs sharea tag with other immediate objects (unbound m=
arkers) 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 fixnumta=
g) as a leaf.</variablelist>
- <variablelist>There are some advantages to treating everything e=
lse - memory-allocated objects that aren't CONS cells - uniformly.There are=
some disadvantages to that uniform treatment as well, and thetreatment of =
"memory-allocated non-CONS objects" isn't entirely uniformaccross all OpenM=
CL implementations. Let's first pretend that thetreatment is uniform, then=
discuss the ways in which it isn't.The "uniform approach" is to treat all =
memory-allocated non-CONS objectsas if they were vectors; this use of the t=
erm is a little looser thanwhat's implied by the CL VECTOR type. OpenMCL a=
ctually uses the term"uvector" to mean "a memory-allocated lisp object othe=
r 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 F=
UNCTION, and even a DOUBLE-FLOAT.In the PPC implementations (where things a=
re a little more ... uniform),a single tag value is used to denote any uvec=
tor; in order to determinesomething more specific about the type of the obj=
ect in question, it'snecessary to fetch the low byte of the header word fro=
m memory. On thex86-64 platform, certain types of uvectors - SYMBOLs and F=
UNCTIONs -are given their own unique tags. The good news about the x86-64 =
approachis that SYMBOLs and FUNCTIONs can be recognized without referencing=
memory; the slightly bad news is that primitive operations that workon UVEC=
TOR-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 port=
s.)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-co=
unt" information in the rest of the word. (This is wherethe sometimes-limi=
ting 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 i=
tself 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 node=
s or immediates.(A UVECTOR whose elements are nodes is called a GVECTOR; a =
UVECTORwhose elements are immediates is called an IVECTOR. This terminolog=
ycame from Spice Lisp, which was a predecessor of CMUCL.)Even though a uvec=
tor 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 val=
ue of a header wound up in a lisp noderegister and that register wound up g=
etting pushed on a thread's valuestack, the GC might misinterpret that situ=
ation to mean that therewas a stack-allocated UVECTOR on the value stack.)<=
/variablelist>
+ <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 <=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>
=
- </listitem>
+ </itemizedlist>
</sect2>
</sect1>
=
<sect1 id=3D"Heap-Allocation">
- <para>Heap Allocation
-When the OpenMCL kernel first starts up, a large contiguous chunk of the
-process's address space is mapped as "anonymous, no access" memory. ("Larg=
e"
-means different things in different contexts; on LinuxPPC32, it means "abo=
ut
-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. The=
se
-values are both defaults and upper limits; the –heap-reserve argumen=
t can
-be used to try to reserve less than the default.)</para>
- <para>Reserving address space that can't (yet) be read or written to=
doesn't
-cost much; in particular, it doesn't require that correspinding swap
-space or physical memory be available. Marking the address range as being
-"mapped" helps to ensure that other things (random calls to malloc(),
-dynamically loaded shared libraries) won't be allocated in this region
-that lisp has reserved for its own heap growth.</para>
- <para>A small portion (around 1/32 on 32-bit platforms and 1/64 on 6=
4-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 sp=
ace 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.</par=
a>
+ <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">
- <para>Per-thread object allocationEach lisp thread has a private "=
reserved memory segment"; when a thread
-starts up, its reserved memory segment is empty. PPC ports maintain the
-highest unallocated addres and he lowest allocated address in the
-current segment in registers when running lisp code; on x86-664, these
-values are maintained in the current threads's TCR. (An "empty" heap
-segment is one whose high pointer and low pointer are equal.) When
-a thread is not in the midde of allocating something, the low 3 or
-4 bits of the high and low pointers are clear (the pointers are
-doublenode-aligned.)</para>
- <para>A thread tries to allocate an object whose physical size in =
bytes is X
-and whose tag is Y by:</para>
- <varlistentry numeration=3D"arabic">
- <variablelist>decrementing the "high" pointer by (- X Y)</variab=
lelist>
- <variablelist>trapping if the high pointer is less than the low =
pointer</variablelist>
- <variablelist>using the (tagged) high pointer to initialize the =
object, if necessary</variablelist>
- <variablelist>clearing the low bits of the high pointer</variabl=
elist>
- </varlistentry>
- <para>On PPC32, where the size of a CONS cell is 8 bytes and the t=
ag 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>
+ <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
@@ -10250,11 +14593,12 @@
(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 diff=
erent. 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>
+ <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
@@ -10266,53 +14610,63 @@
(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>
+ </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">
- <para>Allocation of reserved heap segmentsAfter lisp image is firs=
t 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 threa=
d 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, t=
he 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.</pa=
ra>
+ <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">
- <para>Heap growthAll OSes on which OpenMCL currently runs use an "=
overcommit" memory
-allocation strategy by default (though some of them provide ways of
-overriding that default.) What this means in general is that the OS
-doesn't necessarily ensure that backing store is available when asked
-to map pages as read-write; it'll often return a success indicator from
-the mapping attempt (mapping the pages as "zero-fill, copy-on-write"),
-and only try to allocate the backing store (swap space and/or physical
-memory) when non-zero contents are written to the pages.</para>
- <para>It -sounds- like it'd be better to have the mmap() call fail
-immediately, but it's actually a complicated issue. (It's possible that
-other applications will stop using some backing store before lisp code
-actually touches the pages that need it, for instance.) It's also
-not guaranteed that lisp code would be able to "cleanly" signal an
-out-of-memory condition if lisp is ... out of memory</para>
+ <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
@@ -10322,410 +14676,539 @@
</sect1>
=
<sect1 id=3D"GC-details">
- <para>GC details
-The GC uses a Mark/Compact algorithm; its execution time is
-essentially a factor of the amount of live data in the heap. (The somewhat
-better-known Mark/Sweep algorithms don't compact the live data but instead
-traverse the garbage to rebuild free-lists; their execution time is
-therefore a factor of the total heap size.)</para>
+ <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 are</par=
a>
- <varlistentry numeration=3D"arabic">
- <variablelist>the markbits bitvector, which contains a bit for eve=
rydoublenode in the dynamic heap (plus a few extra words for alignmentand s=
o that sub-bitvectors can start on word boundaries.)</variablelist>
- <variablelist>the relocation table, which contains a native word f=
or every 32 or 64doublenodes in the dynamic heap, plus an extra word used t=
o keep trackof the end of the heap.</variablelist>
- </varlistentry>
- <para>The total GC space overhead is therefore on the order of 3% (2=
/64 or
-1/32).</para>
+ (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">
- <para>Mark phase
-Each doublenode in the dynamic heap has a corresponding bit in the
-markbits vector. (For any doublenode in the heap, the index of its mark
-bit is determined by subtracing the address of the start of the heap
-from the address of the object and dividing the result by 8 or 16.) The GC
-knows the markbit index of the free pointer, so determining that the
-markbit index of a doubleword address is between the start of the heap
-and the free pointer can be done with a single unsigned
-comparison.</para>
- <para>The markbits of all doublenodes in the dynamic heap are zero=
ed
-before the mark phase begins. An object is <emphasis>marked</emphasis>
-if the markbits of all of its constituent doublewords are set and
-unmarked otherwise; setting an object's markbits involves setting the
-corrsponding markbits of all constituent doublenodes in the
-object.</para>
- <para>The mark phase traverses each root. If the tag of the value =
of
-the root indicates that it's a non-immediate node whose address lies
-in the lisp heap, then:</para>
- <varlistentry numeration=3D"arabic">
- <variablelist>If the object is already marked, do nothing.</vari=
ablelist>
- <variablelist>Set the object's markbit(s).</variablelist>
- <variablelist>If the object is an ivector, do nothing further.</=
variablelist>
- <variablelist>If the object is a cons cell, recursively mark its=
car andcdr.</variablelist>
- <variablelist>Otherwise, the object is a gvector. Recursively ma=
rk itselements.</variablelist>
- </varlistentry>
- <para>Marking an object thus involves ensuring that its mark bits =
are set and
-then recursively marking any pointers contained within the object if the
-object was originally unmarked. If this recursive step was implemented
-in the obvious manner, marking an object would take stack space
-proportional to the length of the pointer chain from some root to that
-object. Rather than storing that pointer chain implicitly on the stack
-(in a series of recursive calls to the mark subroutine), the OpenMCL
-marker uses mixture of recursion and a technique called <emphasis>link
-inversion</emphasis> to store the pointer chain in the objects themselves.
-(Recursion tends to be simpler and faster; if a recursive step notes
-that stack space is becoming limited, the link-inversion technique is
-used.)</para>
+ <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>
- <varlistentry numeration=3D"arabic">
- <variablelist>To support a feature called <emphasis>GCTWA
- <tip>
-<para>I believe that theacronym comes from MACLISP, where it stood for "Ga=
rbage Collection ofTruly Worthless Atoms".</para>
- </tip>
-, </emphasis>the vector which contains the internalsymbols of the current =
package is marked on entry to the mark phasebut the symbols themselves are =
not marked at this time. Near the endof the mark phase, symbols referenced =
from this vector which are nototherwise marked are marked if and only if th=
ey're somehowdistinguishable from newly created symbols (by virtue of their=
havingfunction bindings, value bindings, plists, or other attributes.)</va=
riablelist>
- <variablelist>Pools have their first element set to NIL before a=
ny otherelements are marked.</variablelist>
- <variablelist>All hash tables have certain fields (used to cache=
previousresults) invalidated.</variablelist>
- <variablelist>Weak Hash Tables and other weak objects are put on=
a linkedlist as they're encountered; their contents are only retained ifth=
ere are other (non-weak) references to them.</variablelist>
- </varlistentry>
+ <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>
+ are transitively reachable from the roots are set and all other markbits
+ are clear.</para>
</sect2>
=
<sect2 id=3D"Relocation-phase">
- <para>Relocation phase
-The <emphasis>forwarding address</emphasis> of a doublenode in the
-dynamic heap is (<its current address> - (size_of_doublenode * <the number=
of
-unmarked markbits that precede it>)) or alternately (<the base of
-the heap> + (size_of_doublenode * <the number of marked markbits that prec=
ed
-it>)). Rather than count the number of preceding markbits each time,
-the relocation table is used to precompute an approximation of the
-forwarding addresses for all doublewords. Given this approximate address
-and a pointer into the markbits vector, it's relatively easy to compute
-the exact forwarding address.</para>
- <para>The relocation table contains the forwarding addresses of ea=
ch
-<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>
+ <title>Relocation phase</title>
+ <para>The <emphasis>forwarding address</emphasis> of a
+ doublenode in the dynamic heap is (<its current address> -
+ (size_of_doublenode * <the number of unmarked markbits that
+ precede it>)) or alternately (<the base of the heap> +
+ (size_of_doublenode * <the number of marked markbits that
+ preced it >)). Rather than count the number of preceding
+ markbits each time, the relocation table is used to precompute
+ an approximation of the forwarding addresses for all
+ doublewords. Given this approximate address and a pointer into
+ the markbits vector, it's relatively easy to compute the exact
+ forwarding address.</para>
+ <para>The relocation table contains the forwarding addresses
+ of each <emphasis>pagelet</emphasis>, where a pagelet is 256
+ bytes (or 32 doublenodes). The forwarding address of the first
+ pagelet is the base of the heap. The forwarding address of the
+ second pagelet is the sum of the forwarding address of the
+ first and 8 bytes for each mark bit set in the first 32-bit
+ word in the markbits table. The last entry in the relocation
+ table contains the forwarding address that the freepointer
+ would have, e.g., the new value of the freepointer after
+ compaction.</para>
+ <para>In many programs, old objects rarely become garbage and
+ new objects often do. When building the relocation table, the
+ relocation phase notes the address of the first unmarked
+ object in the dynamic heap. Only the area of the heap between
+ the first unmarked object and the freepointer needs to be
+ compacted; only pointers to this area will need to be
+ forwarded (the forwarding address of all other pointers to the
+ dynamic heap is the address of that pointer.) Often, the
+ first unmarked object is much nearer the free pointer than it
+ is to the base of the heap.</para>
</sect2>
=
<sect2 id=3D"Forwarding-phase">
- <para>Forwarding phase
-The forwarding phase traverses all roots and the
-"old" part of the dynamic heap (the part between the base
-of the heap and the first unmarked object.) All references to objects
-whose address is between the first unmarked object and the free pointer
-are updated to point to the address the object will have after
-compaction by using the relocation table and the markbits vector and
-interpolating.</para>
- <para>The relocation table entry for the pagelet nearest the objec=
t 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, loc=
atives
-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 k=
ey 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>
+ <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">
- <para>Compact phase
-The compact phase compacts the area between the first unmarked
-object and the freepointer so that it contains only marked objects.
-While doing so, it forwards any pointers it finds in the objects it
-copies.</para>
- <para>When the compact phase is finished, so is the GC (more or le=
ss):
-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>
+ <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">
- <para>The ephemeral GC
-In the OpenMCL memory management scheme, the relative age of two
-objects in the dynamic heap can be determined by their addresses: if
-addresses X and Y are both addresses in the dynamic heap, X is younger
-than Y (X was created more recently than Y) if it is nearer to the free
-pointer (and farther from the base of the heap) than Y.</para>
- <para>Ephemeral (or generational) garbage collectors attempt to expl=
oit
-the following assumptions:</para>
- <listitem mark=3D"bullet">
- <variablelist>most newly created objects become garbage soon after=
they'recreated.</variablelist>
- <variablelist>most objects that have already survived several GCs =
are unlikelyto ever become garbage.</variablelist>
- <variablelist>old objects can only point to newer objects as the r=
esult of adestructive modification (e.g., via SETF.)</variablelist>
+ <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>
=
- </listitem>
- <para>By concentrating its efforts on (frequently and quickly) recla=
iming
-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 o=
ne
-<emphasis>generation</emphasis>; generations are sets of objects that are
-related to each other by age: some generation is the youngest, some the
-oldest, and there's an age relationship between any intervening
-generations. Objects are typically assigned to the youngest generation
-when first allocated; any object that has survived some number of GCs in
-its current generation is promoted (or <emphasis>tenured</emphasis>) into
-an older generation.</para>
- <para>When a generation is GCed, the roots consist of the stacks,
-registers, and global variables as always and also of any pointers to
-objects in that generation from other generations. To avoid the need to
-scan those (often large) other generations looking for such
-intergenerational references, the runtime system must note all such
-intergenerational references at the point where they're created (via
-Setf).<tip><para>This is sometimes called "The Write Barrier": all
-assignments which might result in intergenerational references must be
-noted, as if the other generations were write-protected.</para></tip> The =
set of pointers that may contain intergenerational
-references is sometimes called <emphasis>the remembered
-set</emphasis>.</para>
- <para>In OpenMCL's EGC, the heap is organized exactly the same as ot=
herwise;
-"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 give=
n GC
-is "ephemeral",</para>
- <listitem mark=3D"bullet">
- <variablelist>the "base of the heap" used to determine anobject's =
markbit address is the base of the generation beingcollected;</variablelist>
- <variablelist>the markbits vector is actually a pointer into the m=
iddle of theglobal markbits table; preceding entries in this table are used=
tonote doubleword addresses in older generations that (may) containinterge=
nerational references;</variablelist>
- <variablelist>some steps (notably GCTWA and the handling of weak o=
bjects) arenot performed;</variablelist>
- <variablelist>the intergenerational references table is used to fi=
ndadditional roots for the mark and forward phases. If a bit is set inthe i=
ntergenerational references table, that means that thecorresponding doublew=
ord (in some "old" generation, insome "earlier" part of the heap) may have =
had a pointerto an object in a younger generation stored into it.</variable=
list>
- =
- </listitem>
- <para>The intergenerational references table is maintained indirectl=
y:
-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 buff=
er 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 s=
afe 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 spars=
e: 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>
+ </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">
- <para>Fasl files
-The information in this section was current in November 2004.
-Saving and loading of Fasl files is implemented in
-xdump/faslenv.lisp, level-0/nfasload.lisp, and lib/nfcomp.lisp.
-The information here is only an overview, which might help when
-reading the source.</para>
- <para>The OpenMCL Fasl format is forked from the old MCL Fasl format=
; there
-are a few differences, but they are minor. The name "nfasload"
-comes from the fact that this is the so-called "new" Fasl system,
-which was true in 1986 or so. The format has held up well, although
-it would certainly need extensions to deal with 64-bit data, and
-some other modernization might be possible.</para>
- <para>A Fasl file begins with a "file header", which contains version
-information and a count of the following "blocks". There's typically
-only one "block" per Fasl file. The blocks are part of a mechanism
-for
-combining multiple logical files into a single physical file, in order
-to simplify the distribution of precompiled programs. (Nobody seems
-to be doing anything interesting with this feature, at the moment,
-probably because it isn't documented.)</para>
- <para>Each block begins with a header for itself, which just describ=
es 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 t=
able",
-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>
+ <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"Heap-images">
- <para>Heap images
-Needs complete rewrite.</para>
- </sect1>
-
- <sect1 id=3D"Operating-system-dependencies">
- <para>Operating system dependencies</para>
- </sect1>
+
=
<sect1 id=3D"The-Objective-C-Bridge--1-">
- <para>The Objective-C Bridge
-Unlike the rest of this chapter, this section was written in late
-2004.</para>
+ <title>The Objective-C Bridge</title>
=
<sect2 id=3D"How-OpenMCL-Recognizes-Objective-C-Objects">
- <para>How OpenMCL Recognizes Objective-C Objects
-In most cases, pointers to instances of Objective-C classes are
-recognized as such; the recognition is (and probably always will be)
-slightly heuristic. Basically, any pointer that passes basic sanity
-checks and whose first word is a pointer to a known ObjC class is
-considered to be an instance of that class; the Objective-C runtime
-system would reach the same conclusion.</para>
- <para>It's certainly possible that a random pointer to an arbitrary
-memory address could look enough like an ObjC instance to fool the lisp
-runtime system, and it's possible that pointers could have their
-contents change so that something that had either been a true ObjC
-instance (or had looked a lot like one) is changed (possibly by virtue
-of having been deallocated.)</para>
- <para>In the first case, we can improve the heuristics substantial=
ly: 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 managem=
ent 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>
+ <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 id=3D"Recommended-Reading--1-">
- <para>Recommended Reading</para>
- <term><indexterm>The Apple Objective-C Runtime Reference
- <variablelist>This describes the internal data structures and =
programminginterface of Objective C as it is implemented on OS X.</variable=
list>
- </indexterm>
- </term>
+ <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">
- <para>Modifying OpenMCL</para>
+ <title>Modifying OpenMCL</title>
=
<sect1 id=3D"Contributing-Code-Back-to-the-OpenMCL-Project">
- <para>Contributing Code Back to the OpenMCL Project
-This section is a placeholder, added as of August 2004. The
-full text is being written, and will be added as soon as it is
-available.</para>
+ <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">
- <para>Using OpenMCL in "development" and in "user" mode
-As it's distributed, OpenMCL starts up with *PACKAGE* set to the CL-USER
-package and with most predefined functions and methods protected against
-accidental redefinition. The package setting is of course a requirement
-of ANSI CL, while the protection protection is intended to catch certain
-types of programming errors (accidentally redefining a CL or CCL function)
-before those errors have a chance to do much damage.</para>
- <para>These settings may make using OpenMCL to develop OpenMCL a bit=
more
-awkward, since much of that process assumes that the CCL package is
-current (and a primary purpose of that process is to redefine some
-"predefined, builtin functions".) The standard, "routine"
-ways of building OpenMCL from sources (see )
-- COMPILE-CCL, XCOMPILE-CCL, and XLOAD-LEVEL-0 - bind *PACKAGE* to the
-"CCL" package and enable the redefinition of predefined functions;
-the symbols COMPILE-CCL, XCOMPILE-CCL, and XLOAD-LEVEL-0 are additionally
-now exported from the "CCL" package.</para>
- <para>Some other (more ad-hoc) ways of doing development on OpenMCL -
-compiling and/or loading individual files, incrementally redefining
-individual functions - may be awkward unless one reverts to the mode of
-operation which was traditionally offered in OpenMCL. (Some OpenMCL source
-files - especially those that comprise the bootstrapping image sources and
-the first few files in the "cold load" sequence - are compiled and
-loaded in the "CCL" package but don't contain (IN-PACKAGE
-"CCL") forms, since IN-PACKAGE doesn't work until later in the
-cold load sequence.)</para>
- <para>The somewhat bizarre behavior of both SET-USER-ENVIRONMENT and
-SET-DEVELOPMENT-ENVIRONMENT with respect to the special variables they
-affect is intended to allow those constructs to take effect when the
-read-eval-print loop next returns to a top-level '? ' prompt;
-the constructs can meaningfully be used inside LOAD, for instance
-(recall that LOAD binds *PACKAGE*), though using both constructs within
-the same LOAD call would likely be pretty confusing.</para>
- <para>"user" and "development" are otherwise very
-generic terms; here they're intended to enforce the distinction
-between "using" OpenMCL and "developing" it.</para>
- <para>The initial environment from which OpenMCL images are saved is=
one
-where (SET-USER-ENVIRONMENT T) has just been called; in previous
-versions, it was effectively as if (SET-DEVELOPMENT-ENVIRONMENT T) had
-just been called.</para>
- <para>Hopefully, most users of OpenMCL can safely ignore these issues
-most of the time. Note that doing (SET-USER-ENVIRONMENT T) after loading
-one's own code (or 3rd-party code) into OpenMCL would protect that
-code (as well as OpenMCL's) from accidental redefinition; that may
-be useful in some cases.</para>
+ <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">
- <para>Debugging facilities in the lisp kernel
-In a perfect world, something like this couldn't happen:</para>
+ <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)
@@ -10735,7 +15218,7 @@
=
? (foo -1) ;Oops. Too late ...
Unhandled exception 11 at 0x300e90c8, context->regs at #x7ffff6b8
-Continue/Debugger/eXit <enter>?
+Continue/Debugger/eXit <enter>?
</programlisting>
<para>As you may have noticed, it's not a perfect world; it's rare
that the cause (attempting to reference the CDR of -1, and therefore
@@ -10749,8 +15232,8 @@
deliberately:</para>
<programlisting>
? (defun classify (n)
- (cond ((> n 0) "Greater")
- ((< n 0) "Less")
+ (cond ((> n 0) "Greater")
+ ((< n 0) "Less")
(t
;;; Sheesh ! What else could it be ?
(ccl::bug "I give up. How could this happen ?"))))
@@ -10761,40 +15244,44 @@
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 se=
e output
-like:</para>
- <programlisting>(S) Find and describe symbol matching specified name
+ </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 ke=
rnel debugger
-was invoked because of an unhandled exception (such as an illegal memory
-reference) the OS kernel saves the machine state
-("context") in a data structure for us, and in that case some additional
-options can be used to display the contents of the registers at the point
-of the exception. Another function - CCL::DBG - causes a special exception
-to be generated and enters the lisp kernel debugger with a non-null
-"context":</para>
- <programlisting>? (defun classify2 (n)
- (cond ((> n 0) "Greater")
- ((< n 0) "Less")
+ <para>CCL::BUG just does an FF-CALL into the lisp kernel. If
+ the kernel debugger was invoked because of an unhandled
+ exception (such as an illegal memory reference) the OS kernel
+ saves the machine state ("context") in a data structure for us,
+ and in that case some additional options can be used to display
+ the contents of the registers at the point of the
+ exception. Another function - CCL::DBG - causes a special
+ exception to be generated and enters the lisp kernel debugger
+ with a non-null "context":</para>
+ <programlisting>
+? (defun classify2 (n)
+ (cond ((> n 0) "Greater")
+ ((< n 0) "Less")
(t (dbg n))))
CLASSIFY2
=
? (classify2 0)
Lisp Breakpoint
- While executing: #<Function CLASSIFY2 #x08476cfe>
+ While executing: #<Function CLASSIFY2 #x08476cfe>
? for help
[12345] OpenMCL kernel debugger: ?
(G) Set specified GPR to new value
@@ -10816,18 +15303,18 @@
we'd see a dislay like:</para>
<programlisting>rnil =3D 0x01836015
nargs =3D 0
-r16 (fn) =3D #<Function CLASSIFY2 #x30379386>
+r16 (fn) =3D #<Function CLASSIFY2 #x30379386>
r23 (arg_z) =3D 0
r22 (arg_y) =3D 0
r21 (arg_x) =3D 0
-r20 (temp0) =3D #<26-element vector subtag =3D 2F @#x303793ee>
+r20 (temp0) =3D #<26-element vector subtag =3D 2F @#x303793ee>
r19 (temp1/next_method_context) =3D 6393788
-r18 (temp2/nfn) =3D #<Function CLASSIFY2 #x30379386>
+r18 (temp2/nfn) =3D #<Function CLASSIFY2 #x30379386>
r17 (temp3/fname) =3D CLASSIFY2
r31 (save0) =3D 0
r30 (save1) =3D *TERMINAL-IO*
r29 (save2) =3D 0
-r28 (save3) =3D (#<RESTART @#x01867f2e> #<RESTART @#x01867f56>)
+r28 (save3) =3D (#<RESTART @#x01867f2e> #<RESTART @#x01867f56>)
r27 (save4) =3D ()
r26 (save5) =3D ()
r25 (save6) =3D ()
@@ -10846,46 +15333,49 @@
</sect1>
=
<sect1 id=3D"Using-AltiVec-in-OpenMCL-LAP-functions">
- <para>Using AltiVec in OpenMCL LAP functions</para>
+ <title>Using AltiVec in OpenMCL LAP functions</title>
=
<sect2 id=3D"Overview--16-">
- <para>Overview
-It's now possible to use AltiVec instructions in PPC LAP
-(assembler) functions.</para>
- <para>The lisp kernel detects the presence or absence of AltiVec a=
nd
-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 genera=
l.
-Ideally, there would be some document that did.</para>
- <para>This document does explain AltiVec register-usage convention=
s 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 b=
ased on
-work contributed to MCL by Shannon Spires.</para>
+ <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">
- <para>Register usage conventions
-OpenMCL LAP functions that use AltiVec instructions must
-interoperate with each other and with C functions; that suggests that they
-follow C AltiVec register usage conventions. (vr0-vr1 scratch, vr2-vr13
-parameters/return value, vr14-vr19 temporaries, vr20-vr31 callee-save
-non-volatile registers.)</para>
- <para>The EABI (Embedded Application Binary Interface) used in Lin=
uxPPC
-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 whi=
ch
-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>
+ <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>
@@ -10931,441 +15421,263 @@
</sect1>
=
<sect1 id=3D"Development-Mode-Dictionary">
- <para>Development-Mode Dictionary</para>
-
- <sect2 id=3D"iWARN-IF-REDEFINE-KERNEL-">
- <para>*WARN-IF-REDEFINE-KERNEL*</para>
- <informalfigure>*warn-if-redefine-kernel</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>*WARN-IF-REDEFINE-KERNEL* —</para>
- <para>Variable</para>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>When true, attempts to redefine (via DEFUN or DEFMETHOD)
-functions and methods that are marked as being
-"predefined" signal continuable errors.</para>
- <para>Note that these are CERRORs, not warnings, and that
-no lisp functions or methods have been defined in the kernel
-in MCL or OpenMCL since 1987 or so.</para>
- </sect2>
-
- <sect2 id=3D"SET-DEVELOPMENT-ENVIRONMENT">
- <para>SET-DEVELOPMENT-ENVIRONMENT</para>
- <informalfigure>set-development-environment</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SET-DEVELOPMENT-ENVIRONMENT —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-set-development-environment
- &optional
- unmark-builtin-functions
-</programlisting>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Arranges that the outermost special bindings of *PACKAGE*
-and *WARN-IF-REDEFINE-KERNEL* restore values of the "CCL"
-package and NIL to these variables, respectively. If the optional
-argument is true, marks all globally defined functions and methods
-as being "not predefined" (this is a fairly expensive
-operation.)</para>
- </sect2>
-
- <sect2 id=3D"SET-USER-ENVIRONMENT">
- <para>SET-USER-ENVIRONMENT</para>
- <informalfigure>set-user-environment</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>SET-USER-ENVIRONMENT —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-set-user-environment
- &optional mark-builtin-functions
-</programlisting>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Arranges that the outermost special bindings of *PACKAGE*
-and *WARN-IF-REDEFINE-KERNEL* restore values of the
-"CL-USER" package and T to these variables, respectively.
-If the optional argument is true, marks all globally defined
-functions and methods as being "predefined" (this is a
-fairly expensive operation.)</para>
- </sect2>
-
- <sect2 id=3D"iALTIVEC-AVAILABLE-">
- <para>*ALTIVEC-AVAILABLE*</para>
- <informalfigure>*altivec-available*</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>*ALTIVEC-AVAILABLE* —</para>
- <para>Variable</para>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>This variable is intitialized each time an OpenMCL session
-starts based on information provided by the lisp kernel. Its value
-is true if AltiVec is present and false otherwise. This variable
-shouldn't be set by user code.</para>
- </sect2>
-
- <sect2 id=3D"ALTIVEC-AVAILABLE-P">
- <para>ALTIVEC-AVAILABLE-P</para>
- <informalfigure>altivec-available-p</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>ALTIVEC-AVAILABLE-P —</para>
- <para>Function</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-altivec-available-p
-</programlisting>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Returns non-NIL if AltiVec is available.</para>
- </sect2>
-
- <sect2 id=3D"iALTIVEC-LAPMACROS-MAINTAIN-VRSAVE-P-">
- <para>*ALTIVEC-LAPMACROS-MAINTAIN-VRSAVE-P*</para>
- <informalfigure>*altivec-lapmacros-maintain-vrsave-p*</informalfig=
ure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>*ALTIVEC-LAPMACROS-MAINTAIN-VRSAVE-P* —</para>
- <para>Variable</para>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Intended to control the expansion of certain lap macros.
-Initialized to NIL on LinuxPPC; initialized to T on platforms
-(such as MacOS X/Darwin) that require that the VRSAVE SPR contain
-a bitmask of active vector registers at all times.</para>
- </sect2>
-
- <sect2 id=3D"WITH-ALTIVEC-REGISTERS">
- <para>WITH-ALTIVEC-REGISTERS</para>
- <informalfigure>with-altivec-registers</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>WITH-ALTIVEC-REGISTERS —</para>
- <para>LAP Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-with-altivec-registers
- reglist &body body
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>reglist
- <variablelist>A list of vector register names (vr0 .. vr31).</=
variablelist>
- </indexterm><indexterm>body
- <variablelist>A sequence of PPC LAP instructions.</variablelis=
t>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Specifies the set of AltiVec registers used in body. If
-*altivec-lapmacros-maintain-vrsave-p* is true when the macro is
-expanded, generates code to save the VRSAVE SPR and updates VRSAVE
-to incude a bitmask generated from the specified register list.
-Generates code which saves any non-volatile vector registers which
-appear in the register list, executes body, and restores the saved
-non-volatile vector registers (and, if
-*altivec-lapmacros-maintain-vrsave-p* is true, restores VRSAVE as
-well. Uses the IMM0 register (r3) as a temporary.</para>
- </sect2>
-
- <sect2 id=3D"WITH-VECTOR-BUFFER">
- <para>WITH-VECTOR-BUFFER</para>
- <informalfigure>with-vector-buffer</informalfigure>
- <bridgehead renderas=3D"sect3">Name</bridgehead>
- <para>WITH-VECTOR-BUFFER —</para>
- <para>LAP Macro</para>
- <bridgehead renderas=3D"sect3">Synopsis</bridgehead>
- <programlisting>
-with-vector-buffer base n &body body
-</programlisting>
- <bridgehead renderas=3D"sect3">Arguments and Values</bridgehead>
- <term><indexterm>base
- <variablelist>Any available general-purpose register.</variabl=
elist>
- </indexterm><indexterm>n
- <variablelist>An integer between 1 and 254, inclusive. (Should=
typically be much, much closer to 1.) Specifies the size ofthe buffer, in 1=
6-byte units.</variablelist>
- </indexterm><indexterm>body
- <variablelist>A sequence of PPC LAP instructions.</variablelis=
t>
- </indexterm>
- </term>
- <bridgehead renderas=3D"sect3">Description</bridgehead>
- <para>Generates code which allocates a 16-byte aligned buffer
-large enough to contain N vector registers; the GPR base points to
-the lowest address of this buffer. After processing body, the
-buffer will be deallocated. The body should preserve the value of
-base as long as it needs to reference the buffer. It's
-intended that base be used as a base register in stvx and lvx
-instructions within the body.</para>
- </sect2>
+ <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
+ "predefined" signal continuable errors.</para>
+
+ <para>Note that these are CERRORs, not warnings, and that
+ no lisp functions or methods have been defined in the kernel
+ in MCL or OpenMCL since 1987 or so.</para>
+ </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 "CCL"
+ package and NIL to these variables, respectively. If the optional
+ argument is true, marks all globally defined functions and methods
+ as being "not predefined" (this is a fairly expensive
+ operation.)</para>
+ </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
+ "CL-USER" package and T to these variables, respectively.
+ If the optional argument is true, marks all globally defined
+ functions and methods as being "predefined" (this is a
+ fairly expensive operation.)</para>
+ </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> <para>Symbol Index
-<tgroup>
- <secondaryie>
- <indexdiv>#_, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>%ff-call, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>%reference-external-entry-point, see </indexdiv></secondaryi=
e>
- <secondaryie>
- <indexdiv>*alternate-line-terminator*, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>*altivec-available*, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>*altivec-lapmacros-maintain-vrsave-p*, see </indexdiv></seco=
ndaryie>
- <secondaryie>
- <indexdiv>*current-process*, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>*default-external-format*, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>*ticks-per-second*, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>*warn-if-redefine-kernel, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>:external-format, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>:y, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>@class, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>@selector, see </indexdiv></secondaryie></tgroup>
-<tgroup>A
- <secondaryie>
- <indexdiv>accept-connection, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>all-processes, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>altivec-available-p, see </indexdiv></secondaryie></tgroup>
-<tgroup>C
- <secondaryie>
- <indexdiv>close, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>close-shared-library, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>configure-egc, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>current-directory-name, see </indexdiv></secondaryie></tgrou=
p>
-<tgroup>D
- <secondaryie>
- <indexdiv>def-foreign-type, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>defcallback, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>define-objc-class-method, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>define-objc-method, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>dotted-to-ipaddr, see </indexdiv></secondaryie></tgroup>
-<tgroup>E
- <secondaryie>
- <indexdiv>egc, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>egc-active-p, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>egc-configuration, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>egc-enabled-p, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>external, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>external-call, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>external-process-error-stream, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>external-process-id, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>external-process-input-stream, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>external-process-output-stream, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>external-process-status, see </indexdiv></secondaryie></tgro=
up>
-<tgroup>F
- <secondaryie>
- <indexdiv>ff-call, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>foreign-symbol-address, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>foreign-symbol-entry, see </indexdiv></secondaryie></tgroup>
-<tgroup>G
- <secondaryie>
- <indexdiv>gc-retain-pages, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>gc-retaining-pages, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>get-user-home-dir, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>getenv, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>getpid, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>getuid, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>grab-lock, see </indexdiv></secondaryie></tgroup>
-<tgroup>I
- <secondaryie>
- <indexdiv>ipaddr-to-dotted, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>ipaddr-to-hostname, see </indexdiv></secondaryie></tgroup>
-<tgroup>L
- <secondaryie>
- <indexdiv>lisp-heap-gc-threshold, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>local-host, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>local-port, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>lookup-hostname, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>lookup-port, see </indexdiv></secondaryie></tgroup>
-<tgroup>M
- <secondaryie>
- <indexdiv>make-lock, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>make-process, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>make-read-write-lock, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>make-record, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>make-semaphore, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>make-socket, see </indexdiv></secondaryie></tgroup>
-<tgroup>N
- <secondaryie>
- <indexdiv>ns-lisp-string, see </indexdiv></secondaryie></tgroup>
-<tgroup>O
- <secondaryie>
- <indexdiv>open-shared-library, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>os-command, see </indexdiv></secondaryie></tgroup>
-<tgroup>P
- <secondaryie>
- <indexdiv>pref, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-abort, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-allow-schedule, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-enable, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-input-wait, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-interrupt, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-kill, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-output-wait, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-preset, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-reset, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-resume, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-run-function, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-suspend, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-suspend-count, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-wait, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-wait-with-timeout, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>process-whostate, see </indexdiv></secondaryie></tgroup>
-<tgroup>R
- <secondaryie>
- <indexdiv>receive-from, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>release-lock, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>remote-host, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>remote-port, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>request-terminal-input-via-break, see </indexdiv></secondary=
ie>
- <secondaryie>
- <indexdiv>rlet, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>rletz, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>run-program, see </indexdiv></secondaryie></tgroup>
-<tgroup>S
- <secondaryie>
- <indexdiv>send-to, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>set-development-environment, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>set-lisp-heap-gc-threshold, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>set-user-environment, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>setenv, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>setgid, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>setuid, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>SHARP-AMPERSAND, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>shutdown, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>signal-external-process, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>signal-semaphore, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>socket-address-family, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>socket-connect, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>socket-error, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>socket-error-code, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>socket-error-identifier, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>socket-error-situation, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>socket-format, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>socket-os-fd, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>socket-type, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>stream-device, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>stream-read-ivector, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>stream-read-list, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>stream-read-vector, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>stream-write-ivector, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>stream-write-list, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>stream-write-vector, see </indexdiv></secondaryie></tgroup>
-<tgroup>T
- <secondaryie>
- <indexdiv>terminate-when-unreachable, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>timed-wait-on-semaphore, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>try-lock, see </indexdiv></secondaryie></tgroup>
-<tgroup>U
- <secondaryie>
- <indexdiv>unuse-interface-dir, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>use-interface-dir, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>use-lisp-heap-gc-threshold, see </indexdiv></secondaryie></t=
group>
-<tgroup>W
- <secondaryie>
- <indexdiv>wait-on-semaphore, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>with-altivec-registers, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>with-lock-grabbed, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>with-open-socket, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>with-read-lock, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>with-terminal-input, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>with-vector-buffer, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>with-write-lock, see </indexdiv></secondaryie>
- <secondaryie>
- <indexdiv>without-interrupts, see </indexdiv></secondaryie></tgroup></=
para>
+ </chapter>
+ <index><title>Symbol Index</title></index>
</book>
-
More information about the Openmcl-cvs-notifications
mailing list