Commit 794c3863 authored by Petr Pudlak's avatar Petr Pudlak
Browse files

When forking a job, close all unnecessary file descriptors



This is a bit problematic as there is no portable way how to list all
open file descriptors, and we can't track them all, because they're also
opened by third party libraries such as inotify. Therefore we use
/proc/self/fd and /dev/fd, which should work for all Linux flavors and
most *BSD as well. If both are missing, we don't do anything and just
log a warning.
Signed-off-by: default avatarPetr Pudlak <pudlak@google.com>
Reviewed-by: default avatarKlaus Aehlig <aehlig@google.com>
parent f40023d4
...@@ -55,11 +55,15 @@ import Control.Concurrent ...@@ -55,11 +55,15 @@ import Control.Concurrent
import Control.Exception.Lifted (finally) import Control.Exception.Lifted (finally)
import Control.Monad import Control.Monad
import Control.Monad.Error import Control.Monad.Error
import Data.Functor
import qualified Data.Map as M import qualified Data.Map as M
import Data.Maybe (listToMaybe, mapMaybe)
import System.Directory (getDirectoryContents)
import System.Environment import System.Environment
import System.IO.Error (tryIOError)
import System.Posix.Process import System.Posix.Process
import System.Posix.IO import System.Posix.IO
import System.Posix.Types (ProcessID) import System.Posix.Types (Fd, ProcessID)
import System.Time import System.Time
import Text.Printf import Text.Printf
...@@ -79,6 +83,22 @@ connectConfig = ConnectConfig { recvTmo = 30 ...@@ -79,6 +83,22 @@ connectConfig = ConnectConfig { recvTmo = 30
, sendTmo = 30 , sendTmo = 30
} }
-- Returns the list of all open file descriptors of the current process.
listOpenFds :: (Error e) => ResultT e IO [Fd]
listOpenFds = liftM filterReadable
$ liftIO (getDirectoryContents "/proc/self/fd") `orElse`
liftIO (getDirectoryContents "/dev/fd") `orElse`
([] <$ logInfo "Listing open file descriptors isn't\
\ supported by the system,\
\ not cleaning them up!")
-- FIXME: If we can't get the list of file descriptors,
-- try to determine the maximum value and just return
-- the full range.
-- See http://stackoverflow.com/a/918469/1333025
where
filterReadable :: (Read a) => [String] -> [a]
filterReadable = mapMaybe (fmap fst . listToMaybe . reads)
-- Code that is executed in a @fork@-ed process and that the replaces iteself -- Code that is executed in a @fork@-ed process and that the replaces iteself
-- with the actual job process -- with the actual job process
runJobProcess :: JobId -> Client -> IO () runJobProcess :: JobId -> Client -> IO ()
...@@ -112,6 +132,10 @@ runJobProcess jid s = withErrorLogAt CRITICAL (show jid) $ ...@@ -112,6 +132,10 @@ runJobProcess jid s = withErrorLogAt CRITICAL (show jid) $
closeFd clFdR closeFd clFdR
closeFd clFdW closeFd clFdW
fds <- (filter (> 2) . filter (/= fd)) <$> toErrorBase listOpenFds
logDebug $ "Closing every superfluous file descriptor: " ++ show fds
mapM_ (tryIOError . closeFd) fds
-- the master process will send the job id and the livelock file name -- the master process will send the job id and the livelock file name
-- using the same protocol to the job process -- using the same protocol to the job process
-- we pass the job id as the first argument to the process; -- we pass the job id as the first argument to the process;
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment