#include "foo_stub.h"
#endif
-#ifdef __GLASGOW_HASKELL__
-extern void __stginit_Foo ( void );
-#endif
-
int main(int argc, char *argv[])
{
int i;
hs_init(&argc, &argv);
-#ifdef __GLASGOW_HASKELL__
- hs_add_root(__stginit_Foo);
-#endif
for (i = 0; i < 5; i++) {
printf("%d\n", foo(2500));
(i.e. those arguments between
<literal>+RTS...-RTS</literal>).</para>
- <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. Note that the symbol name should be transformed
- according to the Z-encoding:</para>
-
<informaltable>
<tgroup cols="2" align="left" colsep="1" rowsep="1">
<thead>
// Initialize Haskell runtime
hs_init(&argc, &argv);
- // Tell Haskell about all root modules
- hs_add_root(__stginit_Foo);
-
// do any other initialization here and
// return false if there was a problem
return HS_BOOL_TRUE;
</programlisting>
<para>The initialisation routine, <literal>mylib_init</literal>, calls
- <literal>hs_init()</literal> and <literal>hs_add_root()</literal> as
+ <literal>hs_init()</literal> as
normal to initialise the Haskell runtime, and the corresponding
deinitialisation function <literal>mylib_end()</literal> calls
<literal>hs_exit()</literal> to shut down the runtime.</para>
invoke <literal>foreign export</literal>ed functions from
multiple OS threads concurrently. The runtime system must
be initialised as usual by
- calling <literal>hs_init()</literal>
- and <literal>hs_add_root</literal>, and these calls must
+ calling <literal>hs_init()</literal>, and this call must
complete before invoking any <literal>foreign
export</literal>ed functions.</para>
</sect3>
<literal>shutdownHaskellAndExit()</literal> instead).</para>
</sect3>
</sect2>
-
+
+ <sect2 id="ffi-floating-point">
+ <title>Floating point and the FFI</title>
+
+ <para>
+ The standard C99 <literal>fenv.h</literal> header
+ provides operations for inspecting and modifying the state of
+ the floating point unit. In particular, the rounding mode
+ used by floating point operations can be changed, and the
+ exception flags can be tested.
+ </para>
+
+ <para>
+ In Haskell, floating-point operations have pure types, and the
+ evaluation order is unspecified. So strictly speaking, since
+ the <literal>fenv.h</literal> functions let you change the
+ results of, or observe the effects of floating point
+ operations, use of <literal>fenv.h</literal> renders the
+ behaviour of floating-point operations anywhere in the program
+ undefined.
+ </para>
+
+ <para>
+ Having said that, we <emphasis>can</emphasis> document exactly
+ what GHC does with respect to the floating point state, so
+ that if you really need to use <literal>fenv.h</literal> then
+ you can do so with full knowledge of the pitfalls:
+ <itemizedlist>
+ <listitem>
+ <para>
+ GHC completely ignores the floating-point
+ environment, the runtime neither modifies nor reads it.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ The floating-point environment is not saved over a
+ normal thread context-switch. So if you modify the
+ floating-point state in one thread, those changes may be
+ visible in other threads. Furthermore, testing the
+ exception state is not reliable, because a context
+ switch may change it. If you need to modify or test the
+ floating point state and use threads, then you must use
+ bound threads
+ (<literal>Control.Concurrent.forkOS</literal>), because
+ a bound thread has its own OS thread, and OS threads do
+ save and restore the floating-point state.
+ </para>
+ </listitem>
+ <listitem>
+ <para>
+ It is safe to modify the floating-point unit state
+ temporarily during a foreign call, because foreign calls
+ are never pre-empted by GHC.
+ </para>
+ </listitem>
+ </itemizedlist>
+ </para>
+ </sect2>
</sect1>
</chapter>