From 433558226790dfa88d215cf12a39df44a3ed01fd Mon Sep 17 00:00:00 2001 From: Simon Marlow Date: Tue, 2 Jun 2009 10:23:52 +0000 Subject: [PATCH] Add a section "Multi-threading and the FFI" and collect all the information about multi-threaded FFI use into it. --- docs/users_guide/ffi-chap.xml | 169 +++++++++++++++++++++++++++++++---------- docs/users_guide/phases.xml | 18 +---- 2 files changed, 131 insertions(+), 56 deletions(-) diff --git a/docs/users_guide/ffi-chap.xml b/docs/users_guide/ffi-chap.xml index 358c5a8..7e2c547 100644 --- a/docs/users_guide/ffi-chap.xml +++ b/docs/users_guide/ffi-chap.xml @@ -305,50 +305,10 @@ int main(int argc, char *argv[]) hs_exit() to shut down the runtime. - - On the use of <literal>hs_exit()</literal> - - hs_exit() normally causes the termination of - any running Haskell threads in the system, and when - hs_exit() 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. - - 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 Windows DLL, - hs_exit() is normally called before unloading the - DLL). So hs_exit() must wait - until all outstanding foreign calls return before it can return - itself. - - The upshot of this is that if you have Haskell threads that are - blocked in foreign calls, then hs_exit() 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 hs_exit(). 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. - - 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 - hs_exit(), then call - shutdownHaskellAndExit() instead). - - Using function headers + Using header files C calls, function headers @@ -456,6 +416,133 @@ int main(int argc, char *argv[]) + + + Multi-threading and the FFI + + In order to use the FFI in a multi-threaded setting, you must + use the option + (see ). + + + Foreign imports and multi-threading + + When you call a foreign imported + function that is annotated as safe (the + default), and the program was linked + using , then the call will run + concurrently with other running Haskell threads. If the + program was linked without , + then the other Haskell threads will be blocked until the + call returns. + + 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 safe and + use . Some library functions + make such calls internally; their documentation should + indicate when this is the case. + + If you are making foreign calls from multiple Haskell + threads and using , 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 + ). + + Note that foreign calls made by different Haskell + threads may execute in parallel, even + when the +RTS -N flag is not being used + (). The +RTS + -N 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 +RTS -N value. + + + + The relationship between Haskell threads and OS + threads + + 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. + + 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 bound + threads, which are Haskell threads tied to a + particular OS thread. For information on bound threads, see + the documentation + for the Control.Concurrent + module. + + + + Foreign exports and multi-threading + + When the program is linked + with , then you may + invoke foreign exported functions from + multiple OS threads concurrently. The runtime system must + be initialised as usual by + calling hs_init() + and hs_add_root, and these calls must + complete before invoking any foreign + exported functions. + + + + On the use of <literal>hs_exit()</literal> + + hs_exit() normally causes the termination of + any running Haskell threads in the system, and when + hs_exit() 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. + + 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 Windows DLL, + hs_exit() is normally called before unloading the + DLL). So hs_exit() must wait + until all outstanding foreign calls return before it can return + itself. + + The upshot of this is that if you have Haskell threads that are + blocked in foreign calls, then hs_exit() 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 hs_exit(). 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. + + 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 + hs_exit(), then call + shutdownHaskellAndExit() instead). + + + diff --git a/docs/users_guide/phases.xml b/docs/users_guide/phases.xml index f3a6e33..467f6ad 100644 --- a/docs/users_guide/phases.xml +++ b/docs/users_guide/phases.xml @@ -966,23 +966,11 @@ $ cat foo.hspp machine. See . The ability to make a foreign call that does not - block all other Haskell threads. - - The ability to invoke foreign exported Haskell - functions from multiple OS threads. + block all other Haskell threads, and to invoke + foreign-exported Haskell functions from multiple OS + threads. See . - - With , 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 - forkIO). - - More details on the use of "bound threads" in the - threaded runtime can be found in the Control.Concurrent module. -- 1.7.10.4