Commit 5cbf9934 authored by Andreas Klebinger's avatar Andreas Klebinger Committed by Marge Bot

Update "GHC differences to the FFI Chapter" in user guide.

The old entry had a heavy focus on how things had been. Which is
not what I generally look for in a user guide.

I also added a small section on behaviour of nested safe ffi calls.

[skip-ci]
parent 4e8a71c1
Pipeline #16889 skipped
...@@ -37,31 +37,51 @@ Guaranteed call safety ...@@ -37,31 +37,51 @@ Guaranteed call safety
~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~
The Haskell 2010 Report specifies that ``safe`` FFI calls must allow foreign The Haskell 2010 Report specifies that ``safe`` FFI calls must allow foreign
calls to safely call into Haskell code. In practice, this means that the calls to safely call into Haskell code. In practice, this means that called
garbage collector must be able to run while these calls are in progress, functions also have to assume heap-allocated Haskell values may move around
moving heap-allocated Haskell values around arbitrarily. arbitrarily in order to allow for GC.
This greatly constrains library authors since it implies that it is not safe to This greatly constrains library authors since it implies that it is not safe to
pass any heap object reference to a ``safe`` foreign function call. For pass any heap object reference to a ``safe`` foreign function call. For
instance, it is often desirable to pass an :ref:`unpinned <pinned-byte-arrays>` instance, it is often desirable to pass :ref:`unpinned <pinned-byte-arrays>`
``ByteArray#``\s directly to native code to avoid making an otherwise-unnecessary ``ByteArray#``\s directly to native code to avoid making an otherwise-unnecessary
copy. However, this can only be done safely if the array is guaranteed not to be copy. However, this can not be done safely for ``safe`` calls since the array might
moved by the garbage collector in the middle of the call. be moved by the garbage collector in the middle of the call.
The Chapter does *not* require implementations to refrain from doing the The Chapter *does* allow for implementations to move objects around during
same for ``unsafe`` calls, so strictly Haskell 2010-conforming programs ``unsafe`` calls as well. So strictly Haskell 2010-conforming programs
cannot pass heap-allocated references to ``unsafe`` FFI calls either. cannot pass heap-allocated references to ``unsafe`` FFI calls either.
GHC, since version 8.4, **guarantees** that garbage collection will never occur
during an ``unsafe`` call, even in the bytecode interpreter, and further guarantees
that ``unsafe`` calls will be performed in the calling thread. Making it safe to
pass heap-allocated objects to unsafe functions.
In previous releases, GHC would take advantage of the freedom afforded by the In previous releases, GHC would take advantage of the freedom afforded by the
Chapter by performing ``safe`` foreign calls in place of ``unsafe`` calls in Chapter by performing ``safe`` foreign calls in place of ``unsafe`` calls in
the bytecode interpreter. This meant that some packages which worked when the bytecode interpreter. This meant that some packages which worked when
compiled would fail under GHCi (e.g. :ghc-ticket:`13730`). compiled would fail under GHCi (e.g. :ghc-ticket:`13730`). But this is no
longer the case in recent releases.
Interactions between ``safe`` calls and bound threads
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
A ``safe`` call calling into haskell is run on a bound thread by
the RTS. This means any nesting of ``safe`` calls will be executed on
the same operating system thread. *Sequential* ``safe`` calls however
do not enjoy this luxury and may be run on arbitrary OS threads.
However, since version 8.4 this is no longer the case: GHC **guarantees** that This behaviour is considered an implementation detail and code relying on
garbage collection will never occur during an ``unsafe`` call, even in the thread local state should instead use one of the interfaces provided
bytecode interpreter, and further guarantees that ``unsafe`` calls will be in :base-ref:`Control.Concurrent.` to make this explicit.
performed in the calling thread.
For information on what bound threads are,
see the documentation for the :base-ref:`Control.Concurrent.`.
For more details on the implementation see the Paper:
"Extending the Haskell Foreign Function Interface with Concurrency".
Last known to be accessible `here
<https://www.microsoft.com/en-us/research/wp-content/uploads/2004/09/conc-ffi.pdf>`_.
.. _ffi-ghcexts: .. _ffi-ghcexts:
...@@ -100,7 +120,7 @@ restrictions: ...@@ -100,7 +120,7 @@ restrictions:
of heap objects record writes for the purpose of garbage collection. of heap objects record writes for the purpose of garbage collection.
An array of heap objects is passed to a foreign C function, the An array of heap objects is passed to a foreign C function, the
runtime does not record any writes. Consequently, it is not safe to runtime does not record any writes. Consequently, it is not safe to
write to an array of heap objects in a foreign function. write to an array of heap objects in a foreign function.
Since the runtime has no facilities for tracking mutation of a Since the runtime has no facilities for tracking mutation of a
``MutableByteArray#``, these can be safely mutated in any foreign ``MutableByteArray#``, these can be safely mutated in any foreign
function. function.
...@@ -169,7 +189,7 @@ In other situations, the C function may need knowledge of the RTS ...@@ -169,7 +189,7 @@ In other situations, the C function may need knowledge of the RTS
closure types. The following example sums the first element of closure types. The following example sums the first element of
each ``ByteArray#`` (interpreting the bytes as an array of ``CInt``) each ``ByteArray#`` (interpreting the bytes as an array of ``CInt``)
element of an ``ArrayArray##`` [3]_:: element of an ``ArrayArray##`` [3]_::
// C source, must include the RTS to make the struct StgArrBytes // C source, must include the RTS to make the struct StgArrBytes
// available along with its fields: ptrs and payload. // available along with its fields: ptrs and payload.
#include "Rts.h" #include "Rts.h"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment