{- |
Module      :  Numeric.QD.FPU.Unsafe
Copyright   :  (c) Claude Heiland-Allen 2011
License     :  BSD3

Maintainer  :  claude@mathr.co.uk
Stability   :  unstable
Portability :  portable

Unsafe FPU manipulation functions.
-}
module Numeric.QD.FPU.Unsafe
  ( unsafePreservingFPU
  ) where

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

import Numeric.QD.FPU.Raw.Unsafe (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 - this 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