packages feed

typed-process 0.2.2.0 → 0.2.3.0

raw patch · 4 files changed

+87/−20 lines, 4 filesdep ~asyncdep ~basedep ~bytestring

Dependency ranges changed: async, base, bytestring

Files

ChangeLog.md view
@@ -1,3 +1,7 @@+## 0.2.3.0++* Add support for the single-threaded runtime via polling+ ## 0.2.2.0  * Add inherit versions of setter functions
README.md view
@@ -19,6 +19,12 @@ 5. Providing a more composable API, designed to be easy to use for    both simple and complex use cases +__NOTE__ It's highly recommended that you compile any program using this+library with the multi-threaded runtime, usually by adding `ghc-options:+-threaded` to your executable stanza in your cabal or `package.yaml` file. The+single-threaded runtime necessitates some inefficient polling to be used under+the surface.+ ## Synopsis  ```haskell
src/System/Process/Typed.hs view
@@ -6,15 +6,7 @@ {-# LANGUAGE KindSignatures #-} {-# LANGUAGE DeriveFunctor #-} {-# LANGUAGE ScopedTypeVariables #-}-{-|-Please see the README.md file for examples of using this API.--__Applications using this library MUST use @-threaded@__ to link with the-threaded version of the RTS. 'spawnProcess' and the others spawn a Haskell-thread that blocks until the process exits. Without @-threaded@ this will block-/all/ the Haskell threads in your program until the spawned process exits.---}+-- | Please see the README.md file for examples of using this API. module System.Process.Typed     ( -- * Types       ProcessConfig@@ -98,18 +90,21 @@  import qualified Data.ByteString as S import Data.ByteString.Lazy.Internal (defaultChunkSize)-import Control.Exception (assert, evaluate, throwIO, Exception, SomeException, finally, bracket, onException, catch)+import Control.Exception (assert, evaluate, throwIO, Exception, SomeException, finally, bracket, onException, catch, try) import Control.Monad (void) import Control.Monad.IO.Class import qualified System.Process as P import Data.Typeable (Typeable) import System.IO (Handle, hClose)+import System.IO.Error (isPermissionError)+import Control.Concurrent (threadDelay) import Control.Concurrent.Async (async, cancel, waitCatch) import Control.Concurrent.STM (newEmptyTMVarIO, atomically, putTMVar, TMVar, readTMVar, tryReadTMVar, STM, tryPutTMVar, throwSTM, catchSTM) import System.Exit (ExitCode (ExitSuccess)) import qualified Data.ByteString.Lazy as L import qualified Data.ByteString.Lazy.Char8 as L8 import Data.String (IsString (fromString))+import GHC.RTS.Flags (getConcFlags, ctxtSwitchTime)  #if MIN_VERSION_process(1, 4, 0) && !WINDOWS import System.Posix.Types (GroupID, UserID)@@ -624,7 +619,21 @@      pExitCode <- newEmptyTMVarIO     waitingThread <- async $ do-        ec <- P.waitForProcess pHandle+        ec <-+          if multiThreadedRuntime+            then P.waitForProcess pHandle+            else do+              switchTime <- (fromIntegral . (`div` 1000) . ctxtSwitchTime)+                        <$> getConcFlags+              let minDelay = 1+                  maxDelay = max minDelay switchTime+                  loop delay = do+                    threadDelay delay+                    mec <- P.getProcessExitCode pHandle+                    case mec of+                      Nothing -> loop $ min maxDelay (delay * 2)+                      Just ec -> pure ec+              loop minDelay         atomically $ putTMVar pExitCode ec         return ec @@ -645,14 +654,41 @@                 -- Process didn't exit yet, let's terminate it and                 -- then call waitForProcess ourselves                 Left _ -> do-                    P.terminateProcess pHandle-                    ec <- P.waitForProcess pHandle+                    eres <- try $ P.terminateProcess pHandle+                    ec <-+                      case eres of+                        Left e+                          -- On Windows, with the single-threaded runtime, it+                          -- seems that if a process has already exited, the+                          -- call to terminateProcess will fail with a+                          -- permission denied error. To work around this, we+                          -- catch this exception and then immediately+                          -- waitForProcess. There's a chance that there may be+                          -- other reasons for this permission error to appear,+                          -- in which case this code may allow us to wait too+                          -- long for a child process instead of erroring out.+                          -- Recommendation: always use the multi-threaded+                          -- runtime!+                          | isPermissionError e && not multiThreadedRuntime && isWindows ->+                            P.waitForProcess pHandle+                          | otherwise -> throwIO e+                        Right () -> P.waitForProcess pHandle                     success <- atomically $ tryPutTMVar pExitCode ec                     evaluate $ assert success ()      return Process {..}   where     pConfig = clearStreams pConfig'++foreign import ccall unsafe "rtsSupportsBoundThreads"+  multiThreadedRuntime :: Bool++isWindows :: Bool+#if WINDOWS+isWindows = True+#else+isWindows = False+#endif  -- | Close a process and release any resources acquired. This will -- ensure 'P.terminateProcess' is called, wait for the process to
typed-process.cabal view
@@ -1,11 +1,13 @@--- This file has been generated from package.yaml by hpack version 0.21.2.+cabal-version: >= 1.10++-- This file has been generated from package.yaml by hpack version 0.29.0. -- -- see: https://github.com/sol/hpack ----- hash: 11068332a1f3de188a488a22fdb0b1bc49f70ccc1dd04c322123278d6d6124e3+-- hash: 8fd30ba42322fffadc01326bcc1370fa86c650057800ca91d5381d89e91df797  name:           typed-process-version:        0.2.2.0+version:        0.2.3.0 synopsis:       Run external processes, with strong typing of streams description:    Please see the tutorial at <https://haskell-lang.org/library/typed-process> category:       System@@ -16,8 +18,6 @@ license:        MIT license-file:   LICENSE build-type:     Simple-cabal-version:  >= 1.10- extra-source-files:     ChangeLog.md     README.md@@ -35,7 +35,7 @@       src   build-depends:       async-    , base >=4.7 && <5+    , base >=4.8 && <5     , bytestring     , process >=1.2     , stm@@ -55,7 +55,28 @@   ghc-options: -threaded -rtsopts -with-rtsopts=-N   build-depends:       async-    , base >=4.7 && <5+    , base >=4.8 && <5+    , base64-bytestring+    , bytestring+    , hspec+    , process >=1.2+    , stm+    , temporary+    , transformers+    , typed-process+  default-language: Haskell2010++test-suite typed-process-test-single-threaded+  type: exitcode-stdio-1.0+  main-is: Spec.hs+  other-modules:+      System.Process.TypedSpec+      Paths_typed_process+  hs-source-dirs:+      test+  build-depends:+      async+    , base >=4.8 && <5     , base64-bytestring     , bytestring     , hspec