2013-06-20 21:10:16 -04:00
|
|
|
{- Running a long or expensive batch operation niced.
|
|
|
|
-
|
2020-06-03 12:59:09 -04:00
|
|
|
- Copyright 2013-2020 Joey Hess <id@joeyh.name>
|
2013-06-20 21:10:16 -04:00
|
|
|
-
|
2014-05-10 11:01:27 -03:00
|
|
|
- License: BSD-2-clause
|
2013-06-20 21:10:16 -04:00
|
|
|
-}
|
|
|
|
|
|
|
|
{-# LANGUAGE CPP #-}
|
|
|
|
|
2019-11-21 15:38:06 -04:00
|
|
|
module Utility.Batch (
|
|
|
|
batch,
|
|
|
|
BatchCommandMaker,
|
2020-12-07 12:50:48 -04:00
|
|
|
nonBatchCommandMaker,
|
2019-11-21 15:38:06 -04:00
|
|
|
getBatchCommandMaker,
|
|
|
|
toBatchCommand,
|
|
|
|
batchCommand,
|
|
|
|
batchCommandEnv,
|
|
|
|
) where
|
2013-06-20 21:10:16 -04:00
|
|
|
|
2013-10-11 16:03:18 -04:00
|
|
|
import Common
|
|
|
|
|
2018-10-13 01:36:06 -04:00
|
|
|
#if defined(linux_HOST_OS)
|
2013-06-20 21:10:16 -04:00
|
|
|
import Control.Concurrent.Async
|
|
|
|
import System.Posix.Process
|
|
|
|
#endif
|
|
|
|
|
|
|
|
{- Runs an operation, at batch priority.
|
|
|
|
-
|
|
|
|
- This is done by running it in a bound thread, which on Linux can be set
|
|
|
|
- to have a different nice level than the rest of the program. Note that
|
|
|
|
- due to running in a bound thread, some operations may be more expensive
|
|
|
|
- to perform. Also note that if the action calls forkIO or forkOS itself,
|
|
|
|
- that will make a new thread that does not have the batch priority.
|
|
|
|
-
|
|
|
|
- POSIX threads do not support separate nice levels, so on other operating
|
|
|
|
- systems, the action is simply ran.
|
|
|
|
-}
|
|
|
|
batch :: IO a -> IO a
|
2018-10-13 01:36:06 -04:00
|
|
|
#if defined(linux_HOST_OS)
|
2013-06-20 21:10:16 -04:00
|
|
|
batch a = wait =<< batchthread
|
|
|
|
where
|
2014-10-09 14:53:13 -04:00
|
|
|
batchthread = asyncBound $ do
|
2013-06-20 21:10:16 -04:00
|
|
|
setProcessPriority 0 maxNice
|
|
|
|
a
|
2020-11-23 14:00:17 -04:00
|
|
|
maxNice = 19
|
2013-06-20 21:10:16 -04:00
|
|
|
#else
|
|
|
|
batch a = a
|
|
|
|
#endif
|
|
|
|
|
2013-12-01 14:53:15 -04:00
|
|
|
{- Makes a command be run by whichever of nice, ionice, and nocache
|
|
|
|
- are available in the path. -}
|
2013-12-01 15:37:51 -04:00
|
|
|
type BatchCommandMaker = (String, [CommandParam]) -> (String, [CommandParam])
|
|
|
|
|
2020-12-07 12:50:48 -04:00
|
|
|
nonBatchCommandMaker :: BatchCommandMaker
|
|
|
|
nonBatchCommandMaker = id
|
|
|
|
|
2013-12-01 15:37:51 -04:00
|
|
|
getBatchCommandMaker :: IO BatchCommandMaker
|
|
|
|
getBatchCommandMaker = do
|
2013-10-22 14:39:45 -04:00
|
|
|
#ifndef mingw32_HOST_OS
|
2021-02-02 19:01:45 -04:00
|
|
|
nicers <- filterM (inSearchPath . fst)
|
2013-12-01 14:53:15 -04:00
|
|
|
[ ("nice", [])
|
|
|
|
, ("ionice", ["-c3"])
|
|
|
|
, ("nocache", [])
|
|
|
|
]
|
2013-12-01 15:37:51 -04:00
|
|
|
return $ \(command, params) ->
|
|
|
|
case nicers of
|
|
|
|
[] -> (command, params)
|
|
|
|
(first:rest) -> (fst first, map Param (snd first ++ concatMap (\p -> fst p : snd p) rest ++ [command]) ++ params)
|
2013-10-22 14:39:45 -04:00
|
|
|
#else
|
2013-12-01 15:37:51 -04:00
|
|
|
return id
|
2013-10-22 14:39:45 -04:00
|
|
|
#endif
|
2013-12-01 15:37:51 -04:00
|
|
|
|
|
|
|
toBatchCommand :: (String, [CommandParam]) -> IO (String, [CommandParam])
|
|
|
|
toBatchCommand v = do
|
|
|
|
batchmaker <- getBatchCommandMaker
|
|
|
|
return $ batchmaker v
|
2013-10-22 14:39:45 -04:00
|
|
|
|
|
|
|
{- Runs a command in a way that's suitable for batch jobs that can be
|
2020-06-03 12:59:09 -04:00
|
|
|
- interrupted. -}
|
2013-10-11 16:03:18 -04:00
|
|
|
batchCommand :: String -> [CommandParam] -> IO Bool
|
2013-10-14 15:05:10 -04:00
|
|
|
batchCommand command params = batchCommandEnv command params Nothing
|
|
|
|
|
|
|
|
batchCommandEnv :: String -> [CommandParam] -> Maybe [(String, String)] -> IO Bool
|
|
|
|
batchCommandEnv command params environ = do
|
2013-12-01 15:37:51 -04:00
|
|
|
batchmaker <- getBatchCommandMaker
|
|
|
|
let (command', params') = batchmaker (command, params)
|
2020-06-03 12:59:09 -04:00
|
|
|
boolSystemEnv command' params' environ
|