X-Git-Url: http://git.megacz.com/?a=blobdiff_plain;f=docs%2Fusers_guide%2Fffi-chap.xml;h=97a237876ff69a4d0f865f7faea4b0dedfccc4ff;hb=58339b06aff704834e8553faaa2db00d746b26f3;hp=7e2c547d27cd049c0911e9fbdadc626a7a26c39c;hpb=433558226790dfa88d215cf12a39df44a3ed01fd;p=ghc-hetmet.git diff --git a/docs/users_guide/ffi-chap.xml b/docs/users_guide/ffi-chap.xml index 7e2c547..97a2378 100644 --- a/docs/users_guide/ffi-chap.xml +++ b/docs/users_guide/ffi-chap.xml @@ -6,10 +6,10 @@ Foreign function interface (FFI) - GHC (mostly) conforms to the Haskell 98 Foreign Function Interface - Addendum 1.0, whose definition is available from http://www.haskell.org/. + GHC (mostly) conforms to the Haskell Foreign Function Interface, + whose definition is part of the Haskell Report on http://www.haskell.org/. - To enable FFI support in GHC, give the + FFI support is enabled by default, but can be enabled or disabled explicitly with the flag. GHC implements a number of GHC-specific extensions to the FFI @@ -19,7 +19,7 @@ Foreign function interface (FFI) The FFI libraries are documented in the accompanying library documentation; see for example the - Foreign module. + Foreign module. GHC extensions to the FFI Addendum @@ -63,6 +63,101 @@ OK: + + + Primitive imports + + GHC extends the FFI with an additional calling convention + prim, e.g.: + + foreign import prim "foo" foo :: ByteArray# -> (# Int#, Int# #) + + 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. + + + + + Interruptible foreign calls + + This concerns the interaction of foreign calls + with Control.Concurrent.throwTo. + Normally when the target of a throwTo 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 (SIGINT on Unix) is to raise + the UserInterrupt 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. + + + + 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 interruptible instead + of safe or unsafe: + + +foreign import ccall interruptible + "sleep" :: CUint -> IO CUint + + + interruptble behaves exactly as + safe, except that when + a throwTo 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: + + + + Unix systems + + + The thread making the foreign call is sent + a SIGPIPE signal + using pthread_kill(). This is + usually enough to cause a blocking system call to + return with EINTR (GHC by default + installs an empty signal handler + for SIGPIPE, to override the + default behaviour which is to terminate the process + immediately). + + + + + Windows systems + + + [Vista and later only] The RTS calls the Win32 + function CancelSynchronousIO, + which will cause a blocking I/O operation to return + with the + error ERROR_OPERATION_ABORTED. + + + + + + If the system call is successfully interrupted, it will + return to Haskell whereupon the exception can be raised. Be + especially careful when + using interruptible 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 EINTR always, + but on Windows it is not typically necessary to + handle ERROR_OPERATION_ABORTED. + + @@ -150,18 +245,11 @@ extern HsInt foo(HsInt a0); #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)); @@ -188,26 +276,6 @@ int main(int argc, char *argv[]) (i.e. those arguments between +RTS...-RTS). - Next, we call - hs_add_rooths_add_root - , a GHC-specific interface which is required to - initialise the Haskell modules in the program. The argument - to hs_add_root 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 - Main, 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 - hs_add_root multiple times, one for each - root. The name of the initialization function for module - M is - __stginit_M, 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: - @@ -285,9 +353,6 @@ int main(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; @@ -299,7 +364,7 @@ int main(int argc, char *argv[]) The initialisation routine, mylib_init, calls - hs_init() and hs_add_root() as + hs_init() as normal to initialise the Haskell runtime, and the corresponding deinitialisation function mylib_end() calls hs_exit() to shut down the runtime. @@ -461,6 +526,15 @@ int main(int argc, char *argv[]) threads, but there may be an arbitrary number of foreign calls in progress at any one time, regardless of the +RTS -N value. + + If a call is annotated as interruptible + 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 for more details. @@ -483,7 +557,7 @@ int main(int argc, char *argv[]) threads, which are Haskell threads tied to a particular OS thread. For information on bound threads, see the documentation - for the Control.Concurrent + for the Control.Concurrent module. @@ -495,8 +569,7 @@ int main(int argc, char *argv[]) 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 + calling hs_init(), and this call must complete before invoking any foreign exported functions. @@ -542,13 +615,70 @@ int main(int argc, char *argv[]) shutdownHaskellAndExit() instead). - + + + Floating point and the FFI + + + The standard C99 fenv.h 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. + + + + In Haskell, floating-point operations have pure types, and the + evaluation order is unspecified. So strictly speaking, since + the fenv.h functions let you change the + results of, or observe the effects of floating point + operations, use of fenv.h renders the + behaviour of floating-point operations anywhere in the program + undefined. + + + + Having said that, we can document exactly + what GHC does with respect to the floating point state, so + that if you really need to use fenv.h then + you can do so with full knowledge of the pitfalls: + + + + GHC completely ignores the floating-point + environment, the runtime neither modifies nor reads it. + + + + + 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 + (Control.Concurrent.forkOS), because + a bound thread has its own OS thread, and OS threads do + save and restore the floating-point state. + + + + + It is safe to modify the floating-point unit state + temporarily during a foreign call, because foreign calls + are never pre-empted by GHC. + + + + +