summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiklas Hambüchen <mail@nh2.me>2020-03-19 19:12:08 +0100
committerMarge Bot <ben+marge-bot@smart-cactus.org>2020-06-04 04:35:24 -0400
commitc05756cdef800f1d8e92114222bcc480bce758b9 (patch)
tree40a22d4e960f503c36cd4f56474200982bb8acd4
parent32a4ae90b50cc56f2955f489ad0cf8c7ff5e131a (diff)
downloadhaskell-c05756cdef800f1d8e92114222bcc480bce758b9.tar.gz
docs: Add more details on InterruptibleFFI.
Details from https://gitlab.haskell.org/ghc/ghc/issues/8684 and https://github.com/takano-akio/filelock/pull/7#discussion_r280332430
-rw-r--r--docs/users_guide/exts/ffi.rst41
1 files changed, 34 insertions, 7 deletions
diff --git a/docs/users_guide/exts/ffi.rst b/docs/users_guide/exts/ffi.rst
index fb0ea38f08..e2937f1ae6 100644
--- a/docs/users_guide/exts/ffi.rst
+++ b/docs/users_guide/exts/ffi.rst
@@ -301,7 +301,8 @@ 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.
+*system* calls which works for most system calls on both Unix and Windows.
+
When the ``InterruptibleFFI`` extension is enabled, a foreign call can
be annotated with ``interruptible`` instead of ``safe`` or ``unsafe``: ::
@@ -325,12 +326,38 @@ Windows systems
``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``.
+Once the system call is successfully interrupted, the surrounding
+code must return control out of the ``foreign import``, back into Haskell code,
+so that the ``throwTo`` Haskell exception can be raised there.
+
+If the foreign code simply retries the system call directly without returning
+back to Haskell, then the intended effect of `interruptible` disappears
+and functions like :base-ref:`System.Timeout.timeout` will not work.
+
+Finally, after the ``interruptible`` foreign call returns into Haskell, the
+Haskell code should allow exceptions to be raised
+(``Control.Exception``'s ``allowInterrupt``, or ``interruptible yield``
+for non-``-threaded``, see https://gitlab.haskell.org/ghc/ghc/issues/8684),
+and implement the ``EINTR``-retrying in Haskell
+(e.g. using e.g. :base-ref:`Foreign.C.Error.throwErrnoIfMinus1Retry`).
+
+Be especially careful when using ``interruptible`` to check that that
+the called foreign function is prepared to deal with the consequences
+of the call being interrupted.
+On Unix it is considered good practice to always check for ``EINTR`` after
+system calls, so you can expect it not to crash (but in that case
+``interruptible`` will not work as intended unless the code then returns
+all the way up to Haskell as described above).
+But on Windows it is not typically common practice to handle
+``ERROR_OPERATION_ABORTED``.
+
+The approach works *only* for foreign code that does I/O (system calls),
+not for CPU-intensive computations that do not do any system calls.
+This is because the only way by which the foreign code can observe
+interruption is by system calls returning interruption error codes.
+To be able to interrupt long-running foreign code doing no system calls,
+the code must likely be changed to explicitly check for intended
+early termination.
.. _ffi-capi: