diff options
author | Simon Marlow <simonmar@microsoft.com> | 2007-07-26 09:40:30 +0000 |
---|---|---|
committer | Simon Marlow <simonmar@microsoft.com> | 2007-07-26 09:40:30 +0000 |
commit | ded67816a2baf995081d1772aa7d83c7e51a284b (patch) | |
tree | 753499e916fbaa470c3c6b61584294a5ac9960c9 | |
parent | 8921711ed3b5008f30ce53ba934cf50fb0745d4e (diff) | |
download | haskell-ded67816a2baf995081d1772aa7d83c7e51a284b.tar.gz |
Documentation updates for #1177
We now have a section that describes what hs_exit() does (including
the "wait for foreign calls to return" behaviour), and more
documentation on creating libraries of Haskell code. I also imported
the section "Beware of DllMain()!" from the haskell.org wiki, with
some minor editing.
-rw-r--r-- | docs/users_guide/ffi-chap.xml | 150 | ||||
-rw-r--r-- | docs/users_guide/win32-dlls.xml | 118 |
2 files changed, 214 insertions, 54 deletions
diff --git a/docs/users_guide/ffi-chap.xml b/docs/users_guide/ffi-chap.xml index 82f3899a76..96cbd596e5 100644 --- a/docs/users_guide/ffi-chap.xml +++ b/docs/users_guide/ffi-chap.xml @@ -10,37 +10,25 @@ Foreign function interface (FFI) 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 + </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="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 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="../libraries/base/Control-Concurrent.html"><literal>Foreign</literal></ulink> module.</para> <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> @@ -78,7 +66,6 @@ OK: </programlisting> </para> </sect2> - </sect1> <sect1 id="ffi-ghc"> @@ -137,6 +124,13 @@ extern HsInt foo(HsInt a0);</programlisting> <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> @@ -188,10 +182,10 @@ int main(int argc, char *argv[]) <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 @@ -251,10 +245,8 @@ int main(int argc, char *argv[]) </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 @@ -273,23 +265,87 @@ int main(int argc, char *argv[]) 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> + <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> + HsBool mylib_init(void){ + int argc = ... + char *argv[] = ... + + // 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; + } + + void mylib_end(void){ + hs_exit(); + } +</programlisting> + + <para>The intialisation routine, <literal>mylib_init</literal>, calls + <literal>hs_init()</literal> and <literal>hs_add_root()</literal> as + normal to initialise the Haskell runtime, and the corresponding + deinitialisation funtion <literal>mylib_end()</literal> calls + <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> @@ -299,7 +355,7 @@ int main(int argc, char *argv[]) <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 + flag), 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 @@ -336,10 +392,10 @@ the module being compiled, you should supply all the <option>-#include</opti 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> +configuration, which GHC knows about. So if you are building a package using + Cabal, remember to put all those include files in the package + description (see the <literal>includes</literal> field in the Cabal + documentation).</para> <para> It is also possible, according the FFI specification, to put the diff --git a/docs/users_guide/win32-dlls.xml b/docs/users_guide/win32-dlls.xml index 22a77deef8..f52f189c69 100644 --- a/docs/users_guide/win32-dlls.xml +++ b/docs/users_guide/win32-dlls.xml @@ -210,8 +210,7 @@ make-sessions running under cygwin. <para> <emphasis>Making Haskell libraries into DLLs doesn't work on Windows at the -moment; however, all the machinery is -still there. If you're interested, contact the GHC team. Note that +moment; we hope to re-instate this facility in the future. Note that building an entire Haskell application as a single DLL is still supported: it's just multi-DLL Haskell programs that don't work. The Windows distribution of GHC contains static libraries only.</emphasis></para> @@ -403,13 +402,10 @@ non-static to static linking is simply a question of adding <title>Making DLLs to be called from other languages</title> <para> - If you want to package up Haskell code to be called from other languages, such as Visual Basic or C++, there are some extra things it is useful to -know. The dirty details are in the <emphasis>Foreign Function -Interface</emphasis> definition, but it can be tricky to work out how to -combine this with DLL building, so here's an example: - +know. This is a special case of <xref linkend="ffi-library" />; we'll deal with + the DLL-specific issues that arise below. Here's an example: </para> <itemizedlist> @@ -521,6 +517,114 @@ the Haskell source and build the DLL. </sect2> +<sect2> +<title>Beware of DllMain()!</title> + +<para>The body of a <literal>DllMain()</literal> function is an +extremely dangerous place! This is because the order in which DLLs are +unloaded when a process is terminating is unspecified. This means that +the <literal>DllMain()</literal> for your DLL may be called when other DLLs containing +functions that you call when de-initializing your DLL have already +been unloaded. In other words, you can't put shutdown code inside +<literal>DllMain()</literal>, unless your shutdown code only requires use of certain +functions which are guaranteed to be available (see the Platform SDK +docs for more info).</para> + +<para>In particular, if you are writing a DLL that's statically +linked with Haskell, it is not safe to call +<literal>hs_exit()</literal> from <literal>DllMain()</literal>, since +<literal>hs_exit()</literal> may make use of other DLLs (see also <xref + linkend="hs-exit" />). What's more, if you +wait until program shutdown to execute your deinitialisation code, Windows will have +terminated all the threads in your program except the one calling +<literal>DllMain()</literal>, which can cause even more +problems.</para> + +<para>A solution is to always export <literal>Begin()</literal> and <literal>End()</literal> functions from your +DLL, and call these from the application that uses the DLL, so that +you can be sure that all DLLs needed by any shutdown code in your +End() function are available when it is called.</para> + +<para>The following example is untested but illustrates the idea (please let us + know if you find problems with this example or have a better one). Suppose we have a DLL called Lewis which makes use of 2 +Haskell modules <literal>Bar</literal> and <literal>Zap</literal>, +where <literal>Bar</literal> imports <literal>Zap</literal> and is +therefore the root module in the sense of <xref +linkend="using-own-main" />. Then the main C++ unit for the DLL would +look something like:</para> + +<programlisting> + // Lewis.cpp -- compiled using GCC + #include <Windows.h> + #include "HsFFI.h" + + #define __LEWIS_DLL_EXPORT + #include "Lewis.h" + + #include "Bar_stub.h" // generated by GHC + #include "Zap_stub.h" + + BOOL APIENTRY DllMain( HANDLE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ){ + return TRUE; + } + + extern "C"{ + + LEWIS_API HsBool lewis_Begin(){ + int argc = ... + char *argv[] = ... + + // Initialize Haskell runtime + hs_init(&argc, &argv); + + // Tell Haskell about all root modules + hs_add_root(__stginit_Bar); + + // do any other initialization here and + // return false if there was a problem + return HS_BOOL_TRUE; + } + + LEWIS_API void lewis_End(){ + hs_exit(); + } + + LEWIS_API HsInt lewis_Test(HsInt x){ + // use Haskell functions exported by + // modules Bar and/or Zap + + return ... + } + + } // extern "C" + +and some application which used the functions in the DLL would have a main() function like: + + // MyApp.cpp + #include "stdafx.h" + #include "Lewis.h" + + int main(int argc, char *argv[]){ + if (lewis_Begin()){ + // can now safely call other functions + // exported by Lewis DLL + + } + lewis_End(); + return 0; + } +</programlisting> + +<para><literal>Lewis.h</literal> would have to have some appropriate <literal>#ifndef</literal> to ensure that the +Haskell FFI types were defined for external users of the DLL (who +wouldn't necessarily have GHC installed and therefore wouldn't have +the include files like <literal>HsFFI.h</literal> etc). +</para> +</sect2> + </sect1> </chapter> |