Add a section "Multi-threading and the FFI"
authorSimon Marlow <marlowsd@gmail.com>
Tue, 2 Jun 2009 10:23:52 +0000 (10:23 +0000)
committerSimon Marlow <marlowsd@gmail.com>
Tue, 2 Jun 2009 10:23:52 +0000 (10:23 +0000)
and collect all the information about multi-threaded FFI use into it.

docs/users_guide/ffi-chap.xml
docs/users_guide/phases.xml

index 358c5a8..7e2c547 100644 (file)
@@ -305,50 +305,10 @@ int main(int argc, char *argv[])
           <literal>hs_exit()</literal> to shut down the runtime.</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="glasgow-foreign-headers">
-      <title>Using function headers</title>
+      <title>Using header files</title>
 
       <indexterm><primary>C calls, function headers</primary></indexterm>
 
@@ -456,6 +416,133 @@ int main(int argc, char *argv[])
        </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>
+      </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="../libraries/base/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 <literal>hs_add_root</literal>, and these calls 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>
+        
   </sect1>
 </chapter>
 
index f3a6e33..467f6ad 100644 (file)
@@ -966,23 +966,11 @@ $ cat foo.hspp</screen>
               machine.  See <xref linkend="using-smp" />.</para>
 
               <para>The ability to make a foreign call that does not
-              block all other Haskell threads.</para>
-
-              <para>The ability to invoke foreign exported Haskell
-              functions from multiple OS threads.</para>
+              block all other Haskell threads, and to invoke
+              foreign-exported Haskell functions from multiple OS
+              threads. See <xref linkend="ffi-threads" />.</para>
             </listitem>
           </itemizedlist>
-
-          <para>With <option>-threaded</option>, calls to foreign
-          functions are made using the same OS thread that created the
-          Haskell thread (if it was created by a call to a foreign
-          exported Haskell function), or an arbitrary OS thread
-          otherwise (if the Haskell thread was created by
-          <literal>forkIO</literal>).</para>
-
-          <para>More details on the use of "bound threads" in the
-          threaded runtime can be found in the <ulink
-          url="../libraries/base/Control-Concurrent.html"><literal>Control.Concurrent</literal></ulink> module.</para>
         </listitem>
       </varlistentry>