Foreign function interface (FFI)
</title>
- <para>GHC (mostly) conforms to the Haskell 98 Foreign Function Interface
- Addendum 1.0, whose definition is available from <ulink url="http://haskell.org/"><literal>http://haskell.org/</literal></ulink>.</para>
-
- <para>To enable FFI support in GHC, give the <option>-fffi</option><indexterm><primary><option>-fffi</option></primary>
- </indexterm>flag, or
-the <option>-fglasgow-exts</option><indexterm><primary><option>-fglasgow-exts</option></primary>
- </indexterm> flag which implies <option>-fffi</option>
-.</para>
-
- <para>The FFI support in GHC diverges from the Addendum in the following ways:</para>
-
- <itemizedlist>
- <listitem>
- <para>Syntactic forms and library functions proposed in earlier versions
- of the FFI are still supported for backwards compatibility.</para>
- </listitem>
-
- <listitem>
- <para>GHC implements a number of GHC-specific extensions to the FFI
- Addendum. These extensions are described in <xref linkend="sec-ffi-ghcexts" />, but please note that programs using
- these features are not portable. Hence, these features should be
- avoided where possible.</para>
- </listitem>
- </itemizedlist>
+ <para>GHC (mostly) conforms to the Haskell Foreign Function Interface,
+ whose definition is part of the Haskell Report on <ulink url="http://www.haskell.org/"><literal>http://www.haskell.org/</literal></ulink>.</para>
+
+ <para>FFI support is enabled by default, but can be enabled or disabled explicitly with the <option>-XForeignFunctionInterface</option><indexterm><primary><option>-XForeignFunctionInterface</option></primary>
+ </indexterm> flag.</para>
+
+ <para>GHC implements a number of GHC-specific extensions to the FFI
+ Addendum. These extensions are described in <xref linkend="ffi-ghcexts" />, but please note that programs using
+ these features are not portable. Hence, these features should be
+ avoided where possible.</para>
<para>The FFI libraries are documented in the accompanying library
- documentation; see for example the <literal>Foreign</literal>
- module.</para>
+ documentation; see for example the
+ <ulink url="&libraryBaseLocation;/Control-Concurrent.html"><literal>Foreign</literal></ulink> module.</para>
- <sect1 id="sec-ffi-ghcexts">
+ <sect1 id="ffi-ghcexts">
<title>GHC extensions to the FFI Addendum</title>
<para>The FFI features that are described in this section are specific to
- GHC. Avoid them where possible to not compromise the portability of the
- resulting code.</para>
+ GHC. Your code will not be portable to other compilers if you use them.</para>
<sect2>
<title>Unboxed types</title>
and <literal>ByteArray#</literal>.</para>
</sect2>
+ <sect2 id="ffi-newtype-io">
+ <title>Newtype wrapping of the IO monad</title>
+ <para>The FFI spec requires the IO monad to appear in various places,
+ but it can sometimes be convenient to wrap the IO monad in a
+ <literal>newtype</literal>, thus:
+<programlisting>
+ newtype MyIO a = MIO (IO a)
+</programlisting>
+ (A reason for doing so might be to prevent the programmer from
+ calling arbitrary IO procedures in some part of the program.)
+</para>
+<para>The Haskell FFI already specifies that arguments and results of
+foreign imports and exports will be automatically unwrapped if they are
+newtypes (Section 3.2 of the FFI addendum). GHC extends the FFI by automatically unwrapping any newtypes that
+wrap the IO monad itself.
+More precisely, wherever the FFI specification requires an IO type, GHC will
+accept any newtype-wrapping of an IO type. For example, these declarations are
+OK:
+<programlisting>
+ foreign import foo :: Int -> MyIO Int
+ foreign import "dynamic" baz :: (Int -> MyIO Int) -> CInt -> MyIO Int
+</programlisting>
+</para>
+ </sect2>
+
+ <sect2 id="ffi-prim">
+ <title>Primitive imports</title>
+ <para>
+ GHC extends the FFI with an additional calling convention
+ <literal>prim</literal>, e.g.:
+<programlisting>
+ foreign import prim "foo" foo :: ByteArray# -> (# Int#, Int# #)
+</programlisting>
+ This is used to import functions written in Cmm code that follow an
+ internal GHC calling convention. This feature is not intended for
+ use outside of the core libraries that come with GHC. For more
+ details see the GHC developer wiki.
+ </para>
+ </sect2>
+
+ <sect2 id="ffi-interruptible">
+ <title>Interruptible foreign calls</title>
+ <para>
+ This concerns the interaction of foreign calls
+ with <literal>Control.Concurrent.throwTo</literal>.
+ Normally when the target of a <literal>throwTo</literal> is
+ involved in a foreign call, the exception is not raised
+ until the call returns, and in the meantime the caller is
+ blocked. This can result in unresponsiveness, which is
+ particularly undesirable in the case of user interrupt
+ (e.g. Control-C). The default behaviour when a Control-C
+ signal is received (<literal>SIGINT</literal> on Unix) is to raise
+ the <literal>UserInterrupt</literal> exception in the main
+ thread; if the main thread is blocked in a foreign call at
+ the time, then the program will not respond to the user
+ interrupt.
+ </para>
+
+ <para>
+ The problem is that it is not possible in general to
+ interrupt a foreign call safely. However, GHC does provide
+ a way to interrupt blocking system calls which works for
+ most system calls on both Unix and Windows. A foreign call
+ can be annotated with <literal>interruptible</literal> instead
+ of <literal>safe</literal> or <literal>unsafe</literal>:
+
+<programlisting>
+foreign import ccall interruptible
+ "sleep" :: CUint -> IO CUint
+</programlisting>
+
+ <literal>interruptble</literal> behaves exactly as
+ <literal>safe</literal>, except that when
+ a <literal>throwTo</literal> is directed at a thread in an
+ interruptible foreign call, an OS-specific mechanism will be
+ used to attempt to cause the foreign call to return:
+
+ <variablelist>
+ <varlistentry>
+ <term>Unix systems</term>
+ <listitem>
+ <para>
+ The thread making the foreign call is sent
+ a <literal>SIGPIPE</literal> signal
+ using <literal>pthread_kill()</literal>. This is
+ usually enough to cause a blocking system call to
+ return with <literal>EINTR</literal> (GHC by default
+ installs an empty signal handler
+ for <literal>SIGPIPE</literal>, to override the
+ default behaviour which is to terminate the process
+ immediately).
+ </para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Windows systems</term>
+ <listitem>
+ <para>
+ [Vista and later only] The RTS calls the Win32
+ function <literal>CancelSynchronousIO</literal>,
+ which will cause a blocking I/O operation to return
+ with the
+ error <literal>ERROR_OPERATION_ABORTED</literal>.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ If the system call is successfully interrupted, it will
+ return to Haskell whereupon the exception can be raised. Be
+ especially careful when
+ using <literal>interruptible</literal> that the caller of
+ the foreign function is prepared to deal with the
+ consequences of the call being interrupted; on Unix it is
+ good practice to check for <literal>EINTR</literal> always,
+ but on Windows it is not typically necessary to
+ handle <literal>ERROR_OPERATION_ABORTED</literal>.
+ </para>
+ </sect2>
</sect1>
- <sect1 id="sec-ffi-ghc">
+ <sect1 id="ffi-ghc">
<title>Using the FFI with GHC</title>
<para>The following sections also give some hints and tips on the
<option>-stubdir</option> option; see <xref linkend="options-output"
/>.</para>
+ <para>When linking the program, remember to include
+ <filename>M_stub.o</filename> in the final link command line, or
+ you'll get link errors for the missing function(s) (this isn't
+ necessary when building your program with <literal>ghc
+ ––make</literal>, as GHC will automatically link in the
+ correct bits).</para>
+
<sect3 id="using-own-main">
<title>Using your own <literal>main()</literal></title>
#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));
<para>The call to <literal>hs_init()</literal>
initializes GHC's runtime system. Do NOT try to invoke any
Haskell functions before calling
- <literal>hs_init()</literal>: strange things will
+ <literal>hs_init()</literal>: bad things will
undoubtedly happen.</para>
- <para>We pass <literal>argc</literal> and
+ <para>We pass references to <literal>argc</literal> and
<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>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>
+ <informaltable>
+ <tgroup cols="2" align="left" colsep="1" rowsep="1">
+ <thead>
+ <row>
+ <entry>Character</entry>
+ <entry>Replacement</entry>
+ </row>
+ </thead>
+ <tbody>
+ <row>
+ <entry><literal>.</literal></entry>
+ <entry><literal>zd</literal></entry>
+ </row>
+ <row>
+ <entry><literal>_</literal></entry>
+ <entry><literal>zu</literal></entry>
+ </row>
+ <row>
+ <entry><literal>`</literal></entry>
+ <entry><literal>zq</literal></entry>
+ </row>
+ <row>
+ <entry><literal>Z</literal></entry>
+ <entry><literal>ZZ</literal></entry>
+ </row>
+ <row>
+ <entry><literal>z</literal></entry>
+ <entry><literal>zz</literal></entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </informaltable>
<para>After we've finished invoking our Haskell functions, we
- 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>
+ can call <literal>hs_exit()</literal>, which terminates the
+ RTS.</para>
<para>There can be multiple calls to
<literal>hs_init()</literal>, but each one should be matched
<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>
+ re-initialise after this has happened,
+ see <xref linkend="ffi-divergence" />.</para>
</footnote>.</para>
<para>NOTE: when linking the final program, it is normally
to the <literal>Main</literal> Haskell module.</para>
</sect3>
- <sect3 id="foreign-export-dynamic-ghc">
- <title>Using <literal>foreign import ccall "wrapper"</literal> with GHC</title>
+ <sect3 id="ffi-library">
+ <title>Making a Haskell library that can be called from foreign
+ code</title>
- <indexterm><primary><literal>foreign import
- ccall "wrapper"</literal></primary><secondary>with GHC</secondary>
- </indexterm>
+ <para>The scenario here is much like in <xref linkend="using-own-main"
+ />, except that the aim is not to link a complete program, but to
+ make a library from Haskell code that can be deployed in the same
+ way that you would deploy a library of C code.</para>
- <para>When <literal>foreign import ccall "wrapper"</literal> is used
- in a Haskell module, The C stub file <filename>M_stub.c</filename>
- generated by GHC contains small helper functions used by the code
- generated for the imported wrapper, so it must be linked in to the
- final program. When linking the program, remember to include
- <filename>M_stub.o</filename> in the final link command line, or
- you'll get link errors for the missing function(s) (this isn't
- necessary when building your program with <literal>ghc
- ––make</literal>, as GHC will automatically link in the
- correct bits).</para>
- </sect3>
- </sect2>
-
- <sect2 id="glasgow-foreign-headers">
- <title>Using function headers</title>
-
- <indexterm><primary>C calls, function headers</primary></indexterm>
-
- <para>When generating C (using the <option>-fvia-C</option>
- directive), one can assist the C compiler in detecting type
- errors by using the <option>-#include</option> directive
- (<xref linkend="options-C-compiler"/>) to provide
- <filename>.h</filename> files containing function
- headers.</para>
-
- <para>For example,</para>
+ <para>The main requirement here is that the runtime needs to be
+ initialized before any Haskell code can be called, so your library
+ should provide initialisation and deinitialisation entry points,
+ implemented in C or C++. For example:</para>
<programlisting>
-#include "HsFFI.h"
+ HsBool mylib_init(void){
+ int argc = ...
+ char *argv[] = ...
-void initialiseEFS (HsInt size);
-HsInt terminateEFS (void);
-HsForeignObj emptyEFS(void);
-HsForeignObj updateEFS (HsForeignObj a, HsInt i, HsInt x);
-HsInt lookupEFS (HsForeignObj a, HsInt i);
-</programlisting>
+ // Initialize Haskell runtime
+ hs_init(&argc, &argv);
- <para>The types <literal>HsInt</literal>,
- <literal>HsForeignObj</literal> etc. are described in the H98 FFI
- Addendum.</para>
-
- <para>Note that this approach is only
- <emphasis>essential</emphasis> for returning
- <literal>float</literal>s (or if <literal>sizeof(int) !=
- sizeof(int *)</literal> on your architecture) but is a Good
- Thing for anyone who cares about writing solid code. You're
- crazy not to do it.</para>
-
-<para>
-What if you are importing a module from another package, and
-a cross-module inlining exposes a foreign call that needs a supporting
-<option>-#include</option>? If the imported module is from the same package as
-the module being compiled, you should supply all the <option>-#include</option>
-that you supplied when compiling the imported module. If the imported module comes
-from another package, you won't necessarily know what the appropriate
-<option>-#include</option> options are; but they should be in the package
-configuration, which GHC knows about. So if you are building a package, remember
-to put all those <option>-#include</option> options into the package configuration.
-See the <literal>c_includes</literal> field in <xref linkend="package-management"/>.
-</para>
+ // do any other initialization here and
+ // return false if there was a problem
+ return HS_BOOL_TRUE;
+ }
-<para>
-It is also possible, according the FFI specification, to put the
-<option>-#include</option> option in the foreign import
-declaration itself:
-<programlisting>
- foreign import "foo.h f" f :: Int -> IO Int
+ void mylib_end(void){
+ hs_exit();
+ }
</programlisting>
-When compiling this module, GHC will generate a C file that includes
-the specified <option>-#include</option>. However, GHC
-<emphasis>disables</emphasis> cross-module inlining for such foreign
-calls, because it doesn't transport the <option>-#include</option>
-information across module boundaries. (There is no fundamental reason for this;
-it was just tiresome to implement. The wrapper, which unboxes the arguments
-etc, is still inlined across modules.) So if you want the foreign call itself
-to be inlined across modules, use the command-line and package-configuration
-<option>-#include</option> mechanism.
-</para>
- <sect3 id="finding-header-files">
- <title>Finding Header files</title>
-
- <para>Header files named by the <option>-#include</option>
- option or in a <literal>foreign import</literal> declaration
- are searched for using the C compiler's usual search path.
- You can add directories to this search path using the
- <option>-I</option> option (see <xref
- linkend="c-pre-processor"/>).</para>
-
- <para>Note: header files are ignored unless compiling via C.
- If you had been compiling your code using the native code
- generator (the default) and suddenly switch to compiling via
- C, then you can get unexpected errors about missing include
- files. Compiling via C is enabled automatically when certain
- options are given (eg. <option>-O</option> and
- <option>-prof</option> both enable
- <option>-fvia-C</option>).</para>
+ <para>The initialisation routine, <literal>mylib_init</literal>, calls
+ <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>
</sect3>
</sect2>
+
+ <sect2 id="glasgow-foreign-headers">
+ <title>Using header files</title>
+
+ <indexterm><primary>C calls, function headers</primary></indexterm>
+
+ <para>C functions are normally declared using prototypes in a C
+ header file. Earlier versions of GHC (6.8.3 and
+ earlier) <literal>#include</literal>d the header file in
+ the C source file generated from the Haskell code, and the C
+ compiler could therefore check that the C function being
+ called via the FFI was being called at the right type.</para>
+
+ <para>GHC no longer includes external header files when
+ compiling via C, so this checking is not performed. The
+ change was made for compatibility with the native code backend
+ (<literal>-fasm</literal>) and to comply strictly with the FFI
+ specification, which requires that FFI calls are not subject
+ to macro expansion and other CPP conversions that may be
+ applied when using C header files. This approach also
+ simplifies the inlining of foreign calls across module and
+ package boundaries: there's no need for the header file to be
+ available when compiling an inlined version of a foreign call,
+ so the compiler is free to inline foreign calls in any
+ context.</para>
+
+ <para>The <literal>-#include</literal> option is now
+ deprecated, and the <literal>include-files</literal> field
+ in a Cabal package specification is ignored.</para>
+
+ </sect2>
<sect2>
<title>Memory Allocation</title>
</varlistentry>
</variablelist>
</sect2>
+
+ <sect2 id="ffi-threads">
+ <title>Multi-threading and the FFI</title>
+
+ <para>In order to use the FFI in a multi-threaded setting, you must
+ use the <option>-threaded</option> option
+ (see <xref linkend="options-linker" />).</para>
+
+ <sect3>
+ <title>Foreign imports and multi-threading</title>
+
+ <para>When you call a <literal>foreign import</literal>ed
+ function that is annotated as <literal>safe</literal> (the
+ default), and the program was linked
+ using <option>-threaded</option>, then the call will run
+ concurrently with other running Haskell threads. If the
+ program was linked without <option>-threaded</option>,
+ then the other Haskell threads will be blocked until the
+ call returns.</para>
+
+ <para>This means that if you need to make a foreign call to
+ a function that takes a long time or blocks indefinitely,
+ then you should mark it <literal>safe</literal> and
+ use <option>-threaded</option>. Some library functions
+ make such calls internally; their documentation should
+ indicate when this is the case.</para>
+
+ <para>If you are making foreign calls from multiple Haskell
+ threads and using <option>-threaded</option>, make sure that
+ the foreign code you are calling is thread-safe. In
+ particularly, some GUI libraries are not thread-safe and
+ require that the caller only invokes GUI methods from a
+ single thread. If this is the case, you may need to
+ restrict your GUI operations to a single Haskell thread,
+ and possibly also use a bound thread (see
+ <xref linkend="haskell-threads-and-os-threads" />).</para>
+
+ <para>Note that foreign calls made by different Haskell
+ threads may execute in <emphasis>parallel</emphasis>, even
+ when the <literal>+RTS -N</literal> flag is not being used
+ (<xref linkend="parallel-options" />). The <literal>+RTS
+ -N</literal> flag controls parallel execution of Haskell
+ threads, but there may be an arbitrary number of foreign
+ calls in progress at any one time, regardless of
+ the <literal>+RTS -N</literal> value.</para>
+
+ <para>If a call is annotated as <literal>interruptible</literal>
+ and the program was multithreaded, the call may be
+ interrupted in the event that the Haskell thread receives an
+ exception. The mechanism by which the interrupt occurs
+ is platform dependent, but is intended to cause blocking
+ system calls to return immediately with an interrupted error
+ code. The underlying operating system thread is not to be
+ destroyed. See <xref linkend="ffi-interruptible"/> for more details.</para>
+ </sect3>
+
+ <sect3 id="haskell-threads-and-os-threads">
+ <title>The relationship between Haskell threads and OS
+ threads</title>
+
+ <para>Normally there is no fixed relationship between Haskell
+ threads and OS threads. This means that when you make a
+ foreign call, that call may take place in an unspecified OS
+ thread. Furthermore, there is no guarantee that multiple
+ calls made by one Haskell thread will be made by the same OS
+ thread.</para>
+
+ <para>This usually isn't a problem, and it allows the GHC
+ runtime system to make efficient use of OS thread resources.
+ However, there are cases where it is useful to have more
+ control over which OS thread is used, for example when
+ calling foreign code that makes use of thread-local state.
+ For cases like this, we provide <emphasis>bound
+ threads</emphasis>, which are Haskell threads tied to a
+ particular OS thread. For information on bound threads, see
+ the documentation
+ for the <ulink url="&libraryBaseLocation;/Control-Concurrent.html"><literal>Control.Concurrent</literal></ulink>
+ module.</para>
+ </sect3>
+
+ <sect3>
+ <title>Foreign exports and multi-threading</title>
+
+ <para>When the program is linked
+ with <option>-threaded</option>, then you may
+ 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 this call must
+ complete before invoking any <literal>foreign
+ export</literal>ed functions.</para>
+ </sect3>
+
+ <sect3 id="hs-exit">
+ <title>On the use of <literal>hs_exit()</literal></title>
+
+ <para><literal>hs_exit()</literal> normally causes the termination of
+ any running Haskell threads in the system, and when
+ <literal>hs_exit()</literal> returns, there will be no more Haskell
+ threads running. The runtime will then shut down the system in an
+ orderly way, generating profiling
+ output and statistics if necessary, and freeing all the memory it
+ owns.</para>
+
+ <para>It isn't always possible to terminate a Haskell thread forcibly:
+ for example, the thread might be currently executing a foreign call,
+ and we have no way to force the foreign call to complete. What's
+ more, the runtime must
+ assume that in the worst case the Haskell code and runtime are about
+ to be removed from memory (e.g. if this is a <link linkend="win32-dlls">Windows DLL</link>,
+ <literal>hs_exit()</literal> is normally called before unloading the
+ DLL). So <literal>hs_exit()</literal> <emphasis>must</emphasis> wait
+ until all outstanding foreign calls return before it can return
+ itself.</para>
+
+ <para>The upshot of this is that if you have Haskell threads that are
+ blocked in foreign calls, then <literal>hs_exit()</literal> may hang
+ (or possibly busy-wait) until the calls return. Therefore it's a
+ good idea to make sure you don't have any such threads in the system
+ when calling <literal>hs_exit()</literal>. This includes any threads
+ doing I/O, because I/O may (or may not, depending on the
+ type of I/O and the platform) be implemented using blocking foreign
+ calls.</para>
+
+ <para>The GHC runtime treats program exit as a special case, to avoid
+ the need to wait for blocked threads when a standalone
+ executable exits. Since the program and all its threads are about to
+ terminate at the same time that the code is removed from memory, it
+ isn't necessary to ensure that the threads have exited first.
+ (Unofficially, if you want to use this fast and loose version of
+ <literal>hs_exit()</literal>, then call
+ <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>
<!-- Emacs stuff:
;;; Local Variables: ***
- ;;; mode: xml ***
;;; sgml-parent-document: ("users_guide.xml" "book" "chapter") ***
;;; End: ***
-->