packages feed

concurrent-output 1.9.2 → 1.10.0

raw patch · 5 files changed

+43/−94 lines, 5 filesdep ~processPVP ok

version bump matches the API change (PVP)

Dependency ranges changed: process

API changes (from Hackage documentation)

- System.Console.Concurrent: data ConcurrentProcessHandle
- System.Console.Concurrent.Internal: ConcurrentProcessHandle :: ProcessHandle -> ConcurrentProcessHandle
- System.Console.Concurrent.Internal: [processWaiters] :: OutputHandle -> TMVar [Async ()]
- System.Console.Concurrent.Internal: [waitForProcessLock] :: OutputHandle -> TMVar ()
- System.Console.Concurrent.Internal: asyncProcessWaiter :: IO () -> IO ()
- System.Console.Concurrent.Internal: newtype ConcurrentProcessHandle
- System.Console.Concurrent.Internal: toConcurrentProcessHandle :: (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle) -> (Maybe Handle, Maybe Handle, Maybe Handle, ConcurrentProcessHandle)
+ System.Console.Concurrent: type ConcurrentProcessHandle = ProcessHandle
+ System.Console.Concurrent.Internal: type ConcurrentProcessHandle = ProcessHandle
- System.Console.Concurrent: createProcessConcurrent :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ConcurrentProcessHandle)
+ System.Console.Concurrent: createProcessConcurrent :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
- System.Console.Concurrent: createProcessForeground :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ConcurrentProcessHandle)
+ System.Console.Concurrent: createProcessForeground :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
- System.Console.Concurrent.Internal: OutputHandle :: TMVar Lock -> TMVar OutputBuffer -> TMVar OutputBuffer -> TMVar Integer -> TMVar [Async ()] -> TMVar () -> OutputHandle
+ System.Console.Concurrent.Internal: OutputHandle :: TMVar Lock -> TMVar OutputBuffer -> TMVar OutputBuffer -> TMVar Integer -> OutputHandle
- System.Console.Concurrent.Internal: bgProcess :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ConcurrentProcessHandle)
+ System.Console.Concurrent.Internal: bgProcess :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
- System.Console.Concurrent.Internal: createProcessConcurrent :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ConcurrentProcessHandle)
+ System.Console.Concurrent.Internal: createProcessConcurrent :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
- System.Console.Concurrent.Internal: createProcessForeground :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ConcurrentProcessHandle)
+ System.Console.Concurrent.Internal: createProcessForeground :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)
- System.Console.Concurrent.Internal: fgProcess :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ConcurrentProcessHandle)
+ System.Console.Concurrent.Internal: fgProcess :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)

Files

CHANGELOG view
@@ -1,3 +1,15 @@+concurrent-output (1.10.0) unstable; urgency=medium++  * Simplified by removing workaround for waitForProcess race+    condition (https://github.com/haskell/process/issues/46).+  * Depends on process-1.6.0.0 which fixed that race.+  * ConcurrentProcessHandle is now a type alias for ProcessHandle,+    and waitForProcessConcurrent simply calls waitForProcess.+    These are now only provided to avoid breaking backwards+    compatability.++ -- Joey Hess <id@joeyh.name>  Fri, 19 May 2017 11:54:49 -0400+ concurrent-output (1.9.2) unstable; urgency=medium    * Allow process-1.6.0.0.
System/Console/Concurrent.hs view
@@ -20,12 +20,12 @@ 	Outputable(..), 	outputConcurrent, 	errorConcurrent,-	ConcurrentProcessHandle, 	createProcessConcurrent,-	waitForProcessConcurrent, 	createProcessForeground, 	flushConcurrentOutput, 	lockOutput,+	ConcurrentProcessHandle,+	waitForProcessConcurrent, 	-- * Low level access to the output buffer 	OutputBuffer, 	StdHandle(..),
System/Console/Concurrent/Internal.hs view
@@ -40,8 +40,6 @@ 	, outputBuffer :: TMVar OutputBuffer 	, errorBuffer :: TMVar OutputBuffer 	, outputThreads :: TMVar Integer-	, processWaiters :: TMVar [Async ()]-	, waitForProcessLock :: TMVar () 	}  data Lock = Locked@@ -54,8 +52,6 @@ 	<*> newTMVarIO (OutputBuffer []) 	<*> newTMVarIO (OutputBuffer []) 	<*> newTMVarIO 0-	<*> newTMVarIO []-	<*> newEmptyTMVarIO  -- | Holds a lock while performing an action. This allows the action to -- perform its own output to the console, without using functions from this@@ -186,69 +182,13 @@ 	h = toHandle stdh 	bv = bufferFor stdh -newtype ConcurrentProcessHandle = ConcurrentProcessHandle P.ProcessHandle--toConcurrentProcessHandle :: (Maybe Handle, Maybe Handle, Maybe Handle, P.ProcessHandle) -> (Maybe Handle, Maybe Handle, Maybe Handle, ConcurrentProcessHandle)-toConcurrentProcessHandle (i, o, e, h) = (i, o, e, ConcurrentProcessHandle h)+-- | This alias is provided to avoid breaking backwards compatibility.+type ConcurrentProcessHandle = P.ProcessHandle --- | Use this to wait for processes started with --- `createProcessConcurrent` and `createProcessForeground`, and get their--- exit status.------ Note that such processes are actually automatically waited for--- internally, so not calling this explicitly will not result--- in zombie processes. This behavior differs from `P.waitForProcess`+-- | Same as `P.waitForProcess`; provided to avoid breaking backwards+-- compatibility. waitForProcessConcurrent :: ConcurrentProcessHandle -> IO ExitCode-waitForProcessConcurrent (ConcurrentProcessHandle h) = -	bracket lock unlock checkexit-  where-	lck = waitForProcessLock globalOutputHandle-	lock = atomically $ tryPutTMVar lck ()-	unlock True = atomically $ takeTMVar lck-	unlock False = return ()-	checkexit locked = maybe (waitsome locked) return-		=<< P.getProcessExitCode h-	waitsome True = do-		let v = processWaiters globalOutputHandle-		l <- atomically $ readTMVar v-		if null l-			-- Avoid waitAny [] which blocks forever-			then P.waitForProcess h-			else do-				-- Wait for any of the running-				-- processes to exit. It may or may not-				-- be the one corresponding to the-				-- ProcessHandle. If it is,-				-- getProcessExitCode will succeed.-				void $ tryIO $ waitAny l-				checkexit True-	waitsome False = do-		-- Another thread took the lck first. Wait for that thread to-		-- wait for one of the running processes to exit.-		atomically $ do-			putTMVar lck ()-			takeTMVar lck-		checkexit False---- Registers an action that waits for a process to exit,--- adding it to the processWaiters list, and removing it once the action--- completes.-asyncProcessWaiter :: IO () -> IO ()-asyncProcessWaiter waitaction = do-	regdone <- newEmptyTMVarIO-	waiter <- async $ do-		self <- atomically (takeTMVar regdone)-		waitaction `finally` unregister self-	register waiter regdone-  where-	v = processWaiters globalOutputHandle-  	register waiter regdone = atomically $ do-		l <- takeTMVar v-		putTMVar v (waiter:l)-		putTMVar regdone waiter-	unregister waiter = atomically $ do-		l <- takeTMVar v-		putTMVar v (filter (/= waiter) l)+waitForProcessConcurrent = P.waitForProcess  -- | Wrapper around `System.Process.createProcess` that prevents  -- multiple processes that are running concurrently from writing@@ -266,7 +206,11 @@ -- the process is instead run with its stdout and stderr -- redirected to a buffer. The buffered output will be displayed as soon -- as the output lock becomes free.-createProcessConcurrent :: P.CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ConcurrentProcessHandle) +--+-- Note that the the process is waited for by a background thread,+-- so unlike createProcess, neglecting to call waitForProcess will not+-- result in zombie processess.+createProcessConcurrent :: P.CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, P.ProcessHandle)  createProcessConcurrent p 	| willOutput (P.std_out p) || willOutput (P.std_err p) = 		ifM tryTakeOutputLock@@ -275,31 +219,34 @@ 			) 	| otherwise = do 		r@(_, _, _, h) <- P.createProcess p-		asyncProcessWaiter $-			void $ tryIO $ P.waitForProcess h-		return (toConcurrentProcessHandle r)+		_ <- async $ void $ tryIO $ P.waitForProcess h+		return r  -- | Wrapper around `System.Process.createProcess` that makes sure a process -- is run in the foreground, with direct access to stdout and stderr. -- Useful when eg, running an interactive process.-createProcessForeground :: P.CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ConcurrentProcessHandle)+--+-- Note that the the process is waited for by a background thread,+-- so unlike createProcess, neglecting to call waitForProcess will not+-- result in zombie processess.+createProcessForeground :: P.CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, P.ProcessHandle) createProcessForeground p = do 	takeOutputLock 	fgProcess p -fgProcess :: P.CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ConcurrentProcessHandle)+fgProcess :: P.CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, P.ProcessHandle) fgProcess p = do 	r@(_, _, _, h) <- P.createProcess p 		`onException` dropOutputLock 	registerOutputThread 	-- Wait for the process to exit and drop the lock.-	asyncProcessWaiter $ do+	_ <- async $ do 		void $ tryIO $ P.waitForProcess h 		unregisterOutputThread 		dropOutputLock-	return (toConcurrentProcessHandle r)+	return r -bgProcess :: P.CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ConcurrentProcessHandle)+bgProcess :: P.CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, P.ProcessHandle) bgProcess p = do 	let p' = p 		{ P.std_out = rediroutput (P.std_out p)@@ -314,11 +261,13 @@ 		, mungeret (P.std_err p) stderr_h 		, h 		)-	asyncProcessWaiter $ void $ tryIO $ P.waitForProcess h+	-- Wait for the process for symmetry with fgProcess,+	-- which does the same.+	_ <- async $ void $ tryIO $ P.waitForProcess h 	outbuf <- setupOutputBuffer StdOut stdout_h 	errbuf <- setupOutputBuffer StdErr stderr_h 	void $ async $ bufferWriter [outbuf, errbuf]-	return (toConcurrentProcessHandle r)+	return r   where 	rediroutput ss 		| willOutput ss = P.CreatePipe
System/Process/Concurrent.hs view
@@ -9,26 +9,14 @@ module System.Process.Concurrent where  import System.Console.Concurrent-import System.Console.Concurrent.Internal (ConcurrentProcessHandle(..)) import System.Process hiding (createProcess, waitForProcess) import System.IO import System.Exit  -- | Calls `createProcessConcurrent`------ You should use the waitForProcess in this module on the resulting--- ProcessHandle. Using System.Process.waitForProcess instead can have--- mildly unexpected results. createProcess :: CreateProcess -> IO (Maybe Handle, Maybe Handle, Maybe Handle, ProcessHandle)-createProcess p = do-	(i, o, e, ConcurrentProcessHandle h) <- createProcessConcurrent p-	return (i, o, e, h)+createProcess = createProcessConcurrent  -- | Calls `waitForProcessConcurrent`------ You should only use this on a ProcessHandle obtained by calling--- createProcess from this module. Using this with a ProcessHandle--- obtained from System.Process.createProcess etc will have extremely--- unexpected results; it can wait a very long time before returning. waitForProcess :: ProcessHandle -> IO ExitCode-waitForProcess = waitForProcessConcurrent . ConcurrentProcessHandle+waitForProcess = waitForProcessConcurrent
concurrent-output.cabal view
@@ -1,5 +1,5 @@ Name: concurrent-output-Version: 1.9.2+Version: 1.10.0 Cabal-Version: >= 1.8 License: BSD2 Maintainer: Joey Hess <id@joeyh.name>@@ -34,7 +34,7 @@     , text (>= 0.11.0 && < 1.3.0)     , async (>= 2.0 && < 2.2)     , stm (>= 2.0 && < 2.5)-    , process (>= 1.1.0 && < 1.7.0)+    , process (>= 1.6.0 && < 1.7.0)     , directory (>= 1.2.0 && < 1.4.0)     , transformers (>= 0.3.0 && < 0.6.0)     , exceptions (>= 0.6.0 && < 0.9.0)