<itemizedlist>
<listitem>
- <para>The routines <literal>hs_init()</literal>,
- <literal>hs_exit()</literal>, and <literal>hs_set_argv()</literal> from
- Chapter 6.1 of the Addendum are not supported yet.</para>
- </listitem>
-
- <listitem>
<para>Syntactic forms and library functions proposed in earlier versions
of the FFI are still supported for backwards compatibility.</para>
</listitem>
resulting code.</para>
<sect2>
- <title>Arrays</title>
-
- <para>The types <literal>ByteArray</literal> and
- <literal>MutableByteArray</literal> may be used as basic foreign types
- (see FFI Addendum, Section 3.2). In C land, they map to
- <literal>(char *)</literal>.</para>
- </sect2>
-
- <sect2>
<title>Unboxed types</title>
<para>The following unboxed types may be used as basic foreign types
invoke <literal>foo()</literal> from C, just <literal>#include
"Foo_stub.h"</literal> and call <literal>foo()</literal>.</para>
- <sect3>
+ <sect3 id="using-own-main">
<title>Using your own <literal>main()</literal></title>
<para>Normally, GHC's runtime system provides a
<programlisting>
#include <stdio.h>
-#include "foo_stub.h"
+#include "HsFFI.h"
-#include "RtsAPI.h"
+#ifdef __GLASGOW_HASKELL__
+#include "foo_stub.h"
+#endif
+#ifdef __GLASGOW_HASKELL__
extern void __stginit_Foo ( void );
+#endif
int main(int argc, char *argv[])
{
int i;
- startupHaskell(argc, argv, __stginit_Foo);
+ hs_init(&argc, &argv);
+#ifdef __GLASGOW_HASKELL__
+ hs_add_root(__stginit_Foo);
+#endif
for (i = 0; i < 5; i++) {
printf("%d\n", foo(2500));
}
- shutdownHaskell();
-
+ hs_exit();
return 0;
}</programlisting>
- <para>The call to <literal>startupHaskell()</literal>
+ <para>We've surrounded the GHC-specific bits with
+ <literal>#ifdef __GLASGOW_HASKELL__</literal>; the rest of the
+ code should be portable across Haskell implementations that
+ support the FFI standard.</para>
+
+ <para>The call to <literal>hs_init()</literal>
initializes GHC's runtime system. Do NOT try to invoke any
Haskell functions before calling
- <literal>startupHaskell()</literal>: strange things will
+ <literal>hs_init()</literal>: strange things will
undoubtedly happen.</para>
<para>We pass <literal>argc</literal> and
- <literal>argv</literal> to <literal>startupHaskell()</literal>
+ <literal>argv</literal> to <literal>hs_init()</literal>
so that it can separate out any arguments for the RTS
(i.e. those arguments between
<literal>+RTS...-RTS</literal>).</para>
- <para>The third argument to <literal>startupHaskell()</literal>
- is used for initializing the Haskell modules in the program.
- It must be the name of the initialization function for the
- "top" module in the program/library - in other words, the
- module which directly or indirectly imports all the other
- Haskell modules in the program. In a standalone Haskell
- program this would be module <literal>Main</literal>, but when
- you are only using the Haskell code as a library it may not
- be. If your library doesn't have such a module, then it is
- straightforward to create one, purely for this initialization
- process. The name of the initialization function for module
+ <para>Next, we call
+ <function>hs_add_root</function><indexterm><primary><function>hs_add_root</function></primary>
+ </indexterm>, a GHC-specific interface which is required to
+ initialise the Haskell modules in the program. The argument
+ to <function>hs_add_root</function> should be the name of the
+ initialization function for the "root" module in your program
+ - in other words, the module which directly or indirectly
+ imports all the other Haskell modules in the program. In a
+ standalone Haskell program the root module is normally
+ <literal>Main</literal>, but when you are using Haskell code
+ from a library it may not be. If your program has multiple
+ root modules, then you can call
+ <function>hs_add_root</function> multiple times, one for each
+ root. The name of the initialization function for module
<replaceable>M</replaceable> is
<literal>__stginit_<replaceable>M</replaceable></literal>, and
it may be declared as an external function symbol as in the
code above.</para>
<para>After we've finished invoking our Haskell functions, we
- can call <literal>shutdownHaskell()</literal>, which
+ can call <literal>hs_exit()</literal>, which
terminates the RTS. It runs any outstanding finalizers and
generates any profiling or stats output that might have been
requested.</para>
- <para>The functions <literal>startupHaskell()</literal> and
- <literal>shutdownHaskell()</literal> may be called only once
- each, and only in that order.</para>
+ <para>There can be multiple calls to
+ <literal>hs_init()</literal>, but each one should be matched
+ by one (and only one) call to
+ <literal>hs_exit()</literal><footnote><para>The outermost
+ <literal>hs_exit()</literal> will actually de-initialise the
+ system. NOTE that currently GHC's runtime cannot reliably
+ re-initialise after this has happened.</para>
+ </footnote>.</para>
<para>NOTE: when linking the final program, it is normally
easiest to do the link using GHC, although this isn't
<option>-#include</option> option in the foreign import
declaration itself:
<programlisting>
- foreign import "#include foo.h f" f :: Int -> IO Int
+ foreign import "foo.h f" f :: Int -> IO Int
</programlisting>
When compiling this module, GHC will generate a C file that includes
the specified <option>-#include</option>. However, GHC
</para>
</sect2>
+
+ <sect2>
+ <title>Memory Allocation</title>
+
+ <para>The FFI libraries provide several ways to allocate memory
+ for use with the FFI, and it isn't always clear which way is the
+ best. This decision may be affected by how efficient a
+ particular kind of allocation is on a given compiler/platform,
+ so this section aims to shed some light on how the different
+ kinds of allocation perform with GHC.</para>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>alloca</literal> and friends</term>
+ <listitem>
+ <para>Useful for short-term allocation when the allocation
+ is intended to scope over a given <literal>IO</literal>
+ compuatation. This kind of allocation is commonly used
+ when marshalling data to and from FFI functions.</para>
+
+ <para>In GHC, <literal>alloca</literal> is implemented
+ using <literal>MutableByteArray#</literal>, so allocation
+ and deallocation are fast: much faster than C's
+ <literal>malloc/free</literal>, but not quite as fast as
+ stack allocation in C. Use <literal>alloca</literal>
+ whenever you can.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>mallocForeignPtr</literal></term>
+ <listitem>
+ <para>Useful for longer-term allocation which requires
+ garbage collection. If you intend to store the pointer to
+ the memory in a foreign data structure, then
+ <literal>mallocForeignPtr</literal> is
+ <emphasis>not</emphasis> a good choice, however.</para>
+
+ <para>In GHC, <literal>mallocForeignPtr</literal> is also
+ implemented using <literal>MutableByteArray#</literal>.
+ Although the memory is pointed to by a
+ <literal>ForeignPtr</literal>, there are no actual
+ finalizers involved (unless you add one with
+ <literal>addForeignPtrFinalizer</literal>), and the
+ deallocation is done using GC, so
+ <literal>mallocForeignPtr</literal> is normally very
+ cheap.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>malloc/free</literal></term>
+ <listitem>
+ <para>If all else fails, then you need to resort to
+ <literal>Foreign.malloc</literal> and
+ <literal>Foreign.free</literal>. These are just wrappers
+ around the C funcitons of the same name, and their
+ efficiency will depend ultimately on the implementations
+ of these functions in your platform's C library. We
+ usually find <literal>malloc</literal> and
+ <literal>free</literal> to be significantly slower than
+ the other forms of allocation above.</para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>Foreign.Marhsal.Pool</literal></term>
+ <listitem>
+ <para>Pools are currently implemented using
+ <literal>malloc/free</literal>, so while they might be a
+ more convenient way to structure your memory allocation
+ than using one of the other forms of allocation, they
+ won't be any more efficient. We do plan to provide an
+ improved-performance implementaiton of Pools in the
+ future, however.</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </sect2>
</sect1>
</Chapter>