Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package ghc-async for openSUSE:Factory checked in at 2021-03-10 08:54:31 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/ghc-async (Old) and /work/SRC/openSUSE:Factory/.ghc-async.new.2378 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "ghc-async" Wed Mar 10 08:54:31 2021 rev:24 rq:877615 version:2.2.3 Changes: -------- --- /work/SRC/openSUSE:Factory/ghc-async/ghc-async.changes 2020-12-22 11:34:53.713224277 +0100 +++ /work/SRC/openSUSE:Factory/.ghc-async.new.2378/ghc-async.changes 2021-03-10 08:56:35.974848373 +0100 @@ -1,0 +2,8 @@ +Fri Feb 19 23:02:58 UTC 2021 - [email protected] + +- Update async to version 2.2.3. + ## Changes in 2.2.3: + + - Documentation fixes + +------------------------------------------------------------------- Old: ---- async-2.2.2.tar.gz async.cabal New: ---- async-2.2.3.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ ghc-async.spec ++++++ --- /var/tmp/diff_new_pack.089E3F/_old 2021-03-10 08:56:36.534848951 +0100 +++ /var/tmp/diff_new_pack.089E3F/_new 2021-03-10 08:56:36.538848956 +0100 @@ -1,7 +1,7 @@ # # spec file for package ghc-async # -# Copyright (c) 2020 SUSE LLC +# Copyright (c) 2021 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -19,13 +19,12 @@ %global pkg_name async %bcond_with tests Name: ghc-%{pkg_name} -Version: 2.2.2 +Version: 2.2.3 Release: 0 Summary: Run IO operations asynchronously and wait for their results License: BSD-3-Clause URL: https://hackage.haskell.org/package/%{pkg_name} Source0: https://hackage.haskell.org/package/%{pkg_name}-%{version}/%{pkg_name}-%{version}.tar.gz -Source1: https://hackage.haskell.org/package/%{pkg_name}-%{version}/revision/1.cabal#/%{pkg_name}.cabal BuildRequires: ghc-Cabal-devel BuildRequires: ghc-hashable-devel BuildRequires: ghc-rpm-macros @@ -64,7 +63,6 @@ %prep %autosetup -n %{pkg_name}-%{version} -cp -p %{SOURCE1} %{pkg_name}.cabal %build %ghc_lib_build ++++++ async-2.2.2.tar.gz -> async-2.2.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/async-2.2.2/Control/Concurrent/Async.hs new/async-2.2.3/Control/Concurrent/Async.hs --- old/async-2.2.2/Control/Concurrent/Async.hs 2019-06-06 09:11:39.000000000 +0200 +++ new/async-2.2.3/Control/Concurrent/Async.hs 2021-02-15 09:41:48.000000000 +0100 @@ -24,65 +24,123 @@ -- "Control.Concurrent". The main additional functionality it -- provides is the ability to wait for the return value of a thread, -- but the interface also provides some additional safety and --- robustness over using threads and @MVar@ directly. +-- robustness over using 'forkIO' threads and @MVar@ directly. +-- +-- == High-level API +-- +-- @async@'s high-level API spawns /lexically scoped/ threads, +-- ensuring the following key poperties that make it safer to use +-- than using plain 'forkIO': +-- +-- 1. No exception is swallowed (waiting for results propagates exceptions). +-- 2. No thread is leaked (left running unintentionally). +-- +-- (This is done using the 'Control.Exception.bracket' pattern to work in presence +-- of synchornous and asynchronous exceptions.) +-- +-- __Most practical/production code should only use the high-level API__. -- -- The basic type is @'Async' a@, which represents an asynchronous -- @IO@ action that will return a value of type @a@, or die with an --- exception. An @Async@ corresponds to a thread, and its 'ThreadId' --- can be obtained with 'asyncThreadId', although that should rarely --- be necessary. +-- exception. An 'Async' is a wrapper around a low-level 'forkIO' thread. +-- +-- The fundamental function to spawn threads with the high-level API is +-- 'withAsync'. -- -- For example, to fetch two web pages at the same time, we could do -- this (assuming a suitable @getURL@ function): -- --- > do a1 <- async (getURL url1) --- > a2 <- async (getURL url2) --- > page1 <- wait a1 --- > page2 <- wait a2 --- > ... --- --- where 'async' starts the operation in a separate thread, and --- 'wait' waits for and returns the result. If the operation --- throws an exception, then that exception is re-thrown by --- 'wait'. This is one of the ways in which this library --- provides some additional safety: it is harder to accidentally --- forget about exceptions thrown in child threads. --- --- A slight improvement over the previous example is this: --- --- > withAsync (getURL url1) $ \a1 -> do --- > withAsync (getURL url2) $ \a2 -> do --- > page1 <- wait a1 --- > page2 <- wait a2 --- > ... +-- > withAsync (getURL url1) $ \a1 -> do +-- > withAsync (getURL url2) $ \a2 -> do +-- > page1 <- wait a1 +-- > page2 <- wait a2 +-- > ... +-- +-- where 'withAsync' starts the operation in a separate thread, and +-- 'wait' waits for and returns the result. +-- +-- * If the operation throws an exception, then that exception is re-thrown +-- by 'wait'. This ensures property (1): No exception is swallowed. +-- * If an exception bubbles up through a 'withAsync', then the 'Async' +-- it spawned is 'cancel'ed. This ensures property (2): No thread is leaked. +-- +-- Often we do not care to work manually with 'Async' handles like +-- @a1@ and @a2@. Instead, we want to express high-level objectives like +-- performing two or more tasks concurrently, and waiting for one or all +-- of them to finish. +-- +-- For example, the pattern of performing two IO actions concurrently and +-- waiting for both their results is packaged up in a combinator 'concurrently', +-- so we can further shorten the above example to: +-- +-- > (page1, page2) <- concurrently (getURL url1) (getURL url2) +-- > ... +-- +-- The section __/High-level utilities/__ covers the most +-- common high-level objectives, including: +-- +-- * Waiting for 2 results ('concurrently'). +-- * Waiting for many results ('mapConcurrently' / 'forConcurrently'). +-- * Waiting for the first of 2 results ('race'). +-- * Waiting for arbitrary nestings of "all of /N/" and "the first of /N/" +-- results with the 'Concurrently' newtype and its 'Applicative' and +-- 'Alternative' instances. +-- +-- Click here to scroll to that section: +-- "Control.Concurrent.Async#high-level-utilities". +-- +-- == Low-level API +-- +-- Some use cases require parallelism that is not lexically scoped. +-- +-- For those, the low-level function 'async' can be used as a direct +-- equivalent of 'forkIO': +-- +-- > -- Do NOT use this code in production, it has a flaw (explained below). +-- > do +-- > a1 <- async (getURL url1) +-- > a2 <- async (getURL url2) +-- > page1 <- wait a1 +-- > page2 <- wait a2 +-- > ... +-- +-- In contrast to 'withAsync', this code has a problem. +-- +-- It still fulfills property (1) in that an exception arising from +-- @getUrl@ will be re-thrown by 'wait', but it does not fulfill +-- property (2). +-- Consider the case when the first 'wait' throws an exception; then the +-- second 'wait' will not happen, and the second 'async' may be left +-- running in the background, possibly indefinitely. -- -- 'withAsync' is like 'async', except that the 'Async' is -- automatically killed (using 'uninterruptibleCancel') if the --- enclosing IO operation returns before it has completed. Consider --- the case when the first 'wait' throws an exception; then the second --- 'Async' will be automatically killed rather than being left to run --- in the background, possibly indefinitely. This is the second way --- that the library provides additional safety: using 'withAsync' --- means we can avoid accidentally leaving threads running. +-- enclosing IO operation returns before it has completed. -- Furthermore, 'withAsync' allows a tree of threads to be built, such -- that children are automatically killed if their parents die for any -- reason. -- --- The pattern of performing two IO actions concurrently and waiting --- for their results is packaged up in a combinator 'concurrently', so --- we can further shorten the above example to: +-- If you need to use the low-level API, ensure that you gurantee +-- property (2) by other means, such as 'link'ing asyncs that need +-- to die together, and protecting against asynchronous exceptions +-- using 'Control.Exception.bracket', 'Control.Exception.mask', +-- or other functions from "Control.Exception". -- --- > (page1, page2) <- concurrently (getURL url1) (getURL url2) --- > ... +-- == Miscellaneous -- -- The 'Functor' instance can be used to change the result of an -- 'Async'. For example: -- --- > ghci> a <- async (return 3) --- > ghci> wait a --- > 3 --- > ghci> wait (fmap (+1) a) +-- > ghci> withAsync (return 3) (\a -> wait (fmap (+1) a)) -- > 4 +-- +-- === Resource exhaustion +-- +-- As with all concurrent programming, keep in mind that while +-- Haskell's cooperative ("green") multithreading carries low overhead, +-- spawning too many of them at the same time may lead to resource exhaustion +-- (of memory, file descriptors, or other limited resources), given that the +-- actions running in the threads consume these resources. ----------------------------------------------------------------------------- @@ -90,8 +148,8 @@ -- * Asynchronous actions Async, - -- ** Spawning - async, asyncBound, asyncOn, asyncWithUnmask, asyncOnWithUnmask, + + -- * High-level API -- ** Spawning with automatic 'cancel'ation withAsync, withAsyncBound, withAsyncOn, withAsyncWithUnmask, @@ -101,33 +159,40 @@ wait, poll, waitCatch, asyncThreadId, cancel, uninterruptibleCancel, cancelWith, AsyncCancelled(..), - -- ** STM operations + -- ** #high-level-utilities# High-level utilities + race, race_, + concurrently, concurrently_, + mapConcurrently, forConcurrently, + mapConcurrently_, forConcurrently_, + replicateConcurrently, replicateConcurrently_, + Concurrently(..), + compareAsyncs, + + -- ** Specialised operations + + -- *** STM operations waitSTM, pollSTM, waitCatchSTM, - -- ** Waiting for multiple 'Async's + -- *** Waiting for multiple 'Async's waitAny, waitAnyCatch, waitAnyCancel, waitAnyCatchCancel, waitEither, waitEitherCatch, waitEitherCancel, waitEitherCatchCancel, waitEither_, waitBoth, - -- ** Waiting for multiple 'Async's in STM + -- *** Waiting for multiple 'Async's in STM waitAnySTM, waitAnyCatchSTM, waitEitherSTM, waitEitherCatchSTM, waitEitherSTM_, waitBothSTM, + -- * Low-level API + + -- ** Spawning (low-level API) + async, asyncBound, asyncOn, asyncWithUnmask, asyncOnWithUnmask, + -- ** Linking link, linkOnly, link2, link2Only, ExceptionInLinkedThread(..), - -- * Convenient utilities - race, race_, - concurrently, concurrently_, - mapConcurrently, forConcurrently, - mapConcurrently_, forConcurrently_, - replicateConcurrently, replicateConcurrently_, - Concurrently(..), - compareAsyncs, - ) where import Control.Concurrent.STM @@ -185,11 +250,16 @@ instance Functor Async where fmap f (Async a w) = Async a (fmap (fmap f) w) --- | Compare two Asyncs that may have different types by their ThreadId. +-- | Compare two Asyncs that may have different types by their 'ThreadId'. compareAsyncs :: Async a -> Async b -> Ordering compareAsyncs (Async t1 _) (Async t2 _) = compare t1 t2 -- | Spawn an asynchronous action in a separate thread. +-- +-- Like for 'forkIO', the action may be left running unintentinally +-- (see module-level documentation for details). +-- +-- __Use 'withAsync' style functions wherever you can instead!__ async :: IO a -> IO (Async a) async = inline asyncUsing rawForkIO @@ -516,7 +586,10 @@ -- {-# INLINE waitBoth #-} waitBoth :: Async a -> Async b -> IO (a,b) -waitBoth left right = atomically (waitBothSTM left right) +waitBoth left right = tryAgain $ atomically (waitBothSTM left right) + where + -- See: https://github.com/simonmar/async/issues/14 + tryAgain f = f `catch` \BlockedIndefinitelyOnSTM -> f -- | A version of 'waitBoth' that can be used inside an STM transaction. -- @@ -647,6 +720,11 @@ -- > waitBoth a b concurrently :: IO a -> IO b -> IO (a,b) +-- | 'concurrently', but ignore the result values +-- +-- @since 2.1.1 +concurrently_ :: IO a -> IO b -> IO () + #define USE_ASYNC_VERSIONS 0 #if USE_ASYNC_VERSIONS @@ -656,16 +734,15 @@ withAsync right $ \b -> waitEither a b -race_ left right = - withAsync left $ \a -> - withAsync right $ \b -> - waitEither_ a b +race_ left right = void $ race left right concurrently left right = withAsync left $ \a -> withAsync right $ \b -> waitBoth a b +concurrently_ left right = void $ concurrently left right + #else -- MVar versions of race/concurrently @@ -744,9 +821,19 @@ stop return r +concurrently_ left right = concurrently' left right (collect 0) + where + collect 2 _ = return () + collect i m = do + e <- m + case e of + Left ex -> throwIO ex + Right _ -> collect (i + 1 :: Int) m + + #endif --- | maps an @IO@-performing function over any @Traversable@ data +-- | Maps an 'IO'-performing function over any 'Traversable' data -- type, performing all the @IO@ actions concurrently, and returning -- the original data structure with the arguments replaced by the -- results. @@ -758,6 +845,10 @@ -- -- > pages <- mapConcurrently getURL ["url1", "url2", "url3"] -- +-- Take into account that @async@ will try to immediately spawn a thread +-- for each element of the @Traversable@, so running this on large +-- inputs without care may lead to resource exhaustion (of memory, +-- file descriptors, or other limited resources). mapConcurrently :: Traversable t => (a -> IO b) -> t a -> IO (t b) mapConcurrently f = runConcurrently . traverse (Concurrently . f) @@ -769,29 +860,16 @@ forConcurrently :: Traversable t => t a -> (a -> IO b) -> IO (t b) forConcurrently = flip mapConcurrently --- | `mapConcurrently_` is `mapConcurrently` with the return value discarded, --- just like @mapM_@. +-- | `mapConcurrently_` is `mapConcurrently` with the return value discarded; +-- a concurrent equivalent of 'mapM_'. mapConcurrently_ :: F.Foldable f => (a -> IO b) -> f a -> IO () mapConcurrently_ f = runConcurrently . F.foldMap (Concurrently . void . f) --- | `forConcurrently_` is `forConcurrently` with the return value discarded, --- just like @forM_@. +-- | `forConcurrently_` is `forConcurrently` with the return value discarded; +-- a concurrent equivalent of 'forM_'. forConcurrently_ :: F.Foldable f => f a -> (a -> IO b) -> IO () forConcurrently_ = flip mapConcurrently_ --- | 'concurrently', but ignore the result values --- --- @since 2.1.1 -concurrently_ :: IO a -> IO b -> IO () -concurrently_ left right = concurrently' left right (collect 0) - where - collect 2 _ = return () - collect i m = do - e <- m - case e of - Left ex -> throwIO ex - Right _ -> collect (i + 1 :: Int) m - -- | Perform the action in the given number of threads. -- -- @since 2.1.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/async-2.2.2/async.cabal new/async-2.2.3/async.cabal --- old/async-2.2.2/async.cabal 2019-06-06 09:11:39.000000000 +0200 +++ new/async-2.2.3/async.cabal 2021-02-15 09:41:48.000000000 +0100 @@ -1,5 +1,5 @@ name: async -version: 2.2.2 +version: 2.2.3 -- don't forget to update ./changelog.md! synopsis: Run IO operations asynchronously and wait for their results @@ -34,7 +34,7 @@ cabal-version: >=1.10 homepage: https://github.com/simonmar/async bug-reports: https://github.com/simonmar/async/issues -tested-with: GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2, GHC==7.10.3, GHC==7.8.4, GHC==7.6.3, GHC==7.4.2, GHC==7.2.2, GHC==7.0.4 +tested-with: GHC==8.10.1, GHC==8.8.3, GHC==8.6.5, GHC==8.4.4, GHC==8.2.2, GHC==8.0.2, GHC==7.10.3, GHC==7.8.4, GHC==7.6.3, GHC==7.4.2, GHC==7.2.2, GHC==7.0.4 extra-source-files: changelog.md @@ -50,14 +50,14 @@ if impl(ghc>=7.1) other-extensions: Trustworthy exposed-modules: Control.Concurrent.Async - build-depends: base >= 4.3 && < 4.14, hashable >= 1.1.2.0 && < 1.4, stm >= 2.2 && < 2.6 + build-depends: base >= 4.3 && < 4.16, hashable >= 1.1.2.0 && < 1.4, stm >= 2.2 && < 2.6 test-suite test-async default-language: Haskell2010 type: exitcode-stdio-1.0 hs-source-dirs: test main-is: test-async.hs - build-depends: base >= 4.3 && < 4.14, + build-depends: base >= 4.3 && < 4.15, async, stm, test-framework, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/async-2.2.2/changelog.md new/async-2.2.3/changelog.md --- old/async-2.2.2/changelog.md 2019-06-06 09:11:39.000000000 +0200 +++ new/async-2.2.3/changelog.md 2021-02-15 09:41:48.000000000 +0100 @@ -1,3 +1,7 @@ +## Changes in 2.2.3: + + - Documentation fixes + ## Changes in 2.2.2: - Builds with GHC 8.6.x
