module Numeric.QD.FPU
  ( unsafePreservingFPU
  ) where

import Foreign.Marshal.Alloc (alloca)
import Control.Exception (bracket_)

import Numeric.QD.FPU.Raw (fpu_fix_start, fpu_fix_end)

-- |@'unsafePreservingFPU' f@ executes the computation @f@, ensuring
-- that the FPU control words are set to avoid problems from excess
-- precision.  See the libqd documentation for further details.
-- This function is unsafe in a threaded runtime as Haskell threads can
-- migrate between OS threads, moreover there is no checking for nested
-- calls which results in race conditions.
-- Some steps can be taken to mitigate some of this badness; perhaps
-- using (for example) @'GHC.Conc.forkOnIO'@ might help.

unsafePreservingFPU :: IO a -> IO a
unsafePreservingFPU f = alloca $ \p -> bracket_ (fpu_fix_start p) (fpu_fix_end p) f