diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
--- a/CHANGELOG.markdown
+++ b/CHANGELOG.markdown
@@ -33,3 +33,8 @@
 - re-bump atomic-primops version; should now support 7.10
 - fix missing other-modules for test suite
 - fix getChanContents for GHC 7.10 (see GHC Trac #9965) 
+
+### 0.4.0.0
+
+- `tryReadChan` now returns an `(Element a, IO a)` tuple, where the `snd` is a blocking read action 
+- depend atomic-primops >= 0.8
diff --git a/core-example/Main.hs b/core-example/Main.hs
deleted file mode 100644
--- a/core-example/Main.hs
+++ /dev/null
@@ -1,183 +0,0 @@
-module Main (main) where
-
-import Control.Monad
-import System.Environment
-import Control.Concurrent.MVar
-import Control.Concurrent
-import qualified Control.Concurrent.Chan.Unagi as U
-import qualified Control.Concurrent.Chan.Unagi.Unboxed as UU
-import qualified Control.Concurrent.Chan.Unagi.Bounded as UB
-import qualified Control.Concurrent.Chan.Unagi.NoBlocking as UN
-import qualified Control.Concurrent.Chan.Unagi.NoBlocking.Unboxed as UNU
-
-import qualified Control.Concurrent.Chan as C
-import qualified Control.Concurrent.STM.TQueue as S
-import Control.Concurrent.STM
-
-import Debug.Trace
-
--- This is a copy of the "async 100 writers 100 readers" from chan-benchmarks
- {-
-main = do 
-    (nm:other) <- getArgs
-    let n = 1000000
-        (r,w) = case other of
-                     [rS,wS] -> (read rS, read wS)
-                     _       -> (100,100)
-    putStrLn $ "Running with "++show r++" readers, and "++ show w++" writers."
-    case nm of
-         "unagi" -> runU w r n
-         "chan" -> runC w r n
-         "stm"  -> runS w r n
--}
-
-main = do
-    [n] <- getArgs
-    runU (read n)
-    -- runUU (read n)
-    -- runUB (read n)
-    -- runUN (read n)
-    -- runUNStream (read n)
-    -- runUNUStream (read n)
-runU :: Int -> IO ()
-runU n = do
-  (i,o) <- U.newChan
-  let n1000 = n `quot` 1000
-  replicateM_ 1000 $ do
-    replicateM_ n1000 $ U.writeChan i ()
-    replicateM_ n1000 $ U.readChan o
-{-
-runUU :: Int -> IO ()
-runUU n = do
-  (i,o) <- UU.newChan
-  let n1000 = n `quot` 1000
-  replicateM_ 1000 $ do
-    replicateM_ n1000 $ UU.writeChan i (0::Int)
-    replicateM_ n1000 $ UU.readChan o
-
-runUB :: Int -> IO ()
-runUB n = do
-  let n1000 = n `quot` 1000
-  (i,o) <- UB.newChan n1000
-  replicateM_ 1000 $ do
-    replicateM_ n1000 $ UB.writeChan i (0::Int)
-    replicateM_ n1000 $ UB.readChan o
-
-
-tryReadChanErrUN :: UN.OutChan a -> IO a
-{-# INLINE tryReadChanErrUN #-}
-tryReadChanErrUN oc = UN.tryReadChan oc 
-                    >>= UN.tryRead 
-                    >>= maybe (error "A read we expected to succeed failed!") return
-
-runUN n = do
-  (i,o) <- UN.newChan
-  let n1000 = n `quot` 1000
-  replicateM_ 1000 $ do
-    replicateM_ n1000 $ UN.writeChan i ()
-    replicateM_ n1000 $ tryReadChanErrUN o
-
-runUNStream n = do
-  (i,o) <- UN.newChan
-  [ oStream ] <- UN.streamChan 1 o
-  let n1000 = n `quot` 1000
-  let eat str = do
-          x <- UN.tryReadNext str
-          case x of
-               UN.Pending -> return str
-               UN.Next _ str' -> eat str'
-      writeAndEat iter str = unless (iter <=0) $ do
-          replicateM_ n1000 $ UN.writeChan i ()
-          eat str >>= writeAndEat (iter-1)
-        
-  writeAndEat (1000::Int) oStream
- -}
-tryReadChanErrUNU :: UNU.UnagiPrim a=> UNU.OutChan a -> IO a
-{-# INLINE tryReadChanErrUNU #-}
-tryReadChanErrUNU oc = UNU.tryReadChan oc 
-                    >>= UNU.tryRead 
-                    >>= maybe (error "A read we expected to succeed failed!") return
-
-runUNU n = do
-  (i,o) <- UNU.newChan
-  let n1000 = n `quot` 1000
-  replicateM_ 1000 $ do
-    replicateM_ n1000 $ UNU.writeChan i (0::Int)
-    replicateM_ n1000 $ tryReadChanErrUNU o
-
-runUNUStream n = do
-  (i,o) <- UNU.newChan
-  [ oStream ] <- UNU.streamChan 1 o
-  let n1000 = n `quot` 1000
-  let eat str = do
-          x <- UNU.tryReadNext str
-          case x of
-               UNU.Pending -> return str
-               UNU.Next _ str' -> eat str'
-      writeAndEat iter str = unless (iter <=0) $ do
-          replicateM_ n1000 $ UNU.writeChan i (0::Int)
-          eat str >>= writeAndEat (iter-1)
-        
-  writeAndEat (1000::Int) oStream
-
-{-
-runU :: Int -> Int -> Int -> IO ()
-runU writers readers n = do
-  let nNice = n - rem n (lcm writers readers)
-      perReader = nNice `quot` readers
-      perWriter = (nNice `quot` writers)
-  vs <- replicateM readers newEmptyMVar
-  (i,o) <- U.newChan
-  let doRead = replicateM_ perReader $ theRead
-      theRead = U.readChan o
-      doWrite = replicateM_ perWriter $ theWrite
-      theWrite = U.writeChan i (1 :: Int)
-  mapM_ (\v-> forkIO (traceEventIO "READER START" >> doRead >> putMVar v ())) vs
-
-  wWaits <- replicateM writers newEmptyMVar
-  mapM_ (\v-> forkIO $ (takeMVar v >> traceEventIO "WRITER START" >> doWrite)) wWaits
-  mapM_ (\v-> putMVar v ()) wWaits
-
-  mapM_ takeMVar vs -- await readers
-
--- ------------------------------------------------
--- FOR COMPARISON:
-
-runS :: Int -> Int -> Int -> IO ()
-runS writers readers n = do
-  let nNice = n - rem n (lcm writers readers)
-      perReader = nNice `quot` readers
-      perWriter = (nNice `quot` writers)
-  vs <- replicateM readers newEmptyMVar
-  tq <- S.newTQueueIO
-  let doRead = replicateM_ perReader $ theRead
-      theRead = (atomically . S.readTQueue) tq
-      doWrite = replicateM_ perWriter $ theWrite
-      theWrite = atomically $ S.writeTQueue tq (1 :: Int)
-  mapM_ (\v-> forkIO (traceEventIO "READER START" >> doRead >> putMVar v ())) vs
-
-  wWaits <- replicateM writers newEmptyMVar
-  mapM_ (\v-> forkIO $ (takeMVar v >> traceEventIO "WRITER START" >> doWrite)) wWaits
-  mapM_ (\v-> putMVar v ()) wWaits
-
-  mapM_ takeMVar vs -- await readers
-
-runC :: Int -> Int -> Int -> IO ()
-runC writers readers n = do
-  let nNice = n - rem n (lcm writers readers)
-      perReader = nNice `quot` readers
-      perWriter = (nNice `quot` writers)
-  vs <- replicateM readers newEmptyMVar
-  c <- C.newChan
-  let doRead = replicateM_ perReader $ theRead
-      theRead = C.readChan c
-      doWrite = replicateM_ perWriter $ theWrite
-      theWrite = C.writeChan c (1 :: Int)
-  mapM_ (\v-> forkIO (traceEventIO "READER START" >> doRead >> putMVar v ())) vs
-
-  wWaits <- replicateM writers newEmptyMVar
-  mapM_ (\v-> forkIO $ (takeMVar v >> traceEventIO "WRITER START" >> doWrite)) wWaits
-  mapM_ (\v-> putMVar v ()) wWaits
-
-  mapM_ takeMVar vs -- await readers
--}
diff --git a/src/Control/Concurrent/Chan/Unagi/Bounded/Internal.hs b/src/Control/Concurrent/Chan/Unagi/Bounded/Internal.hs
--- a/src/Control/Concurrent/Chan/Unagi/Bounded/Internal.hs
+++ b/src/Control/Concurrent/Chan/Unagi/Bounded/Internal.hs
@@ -30,6 +30,7 @@
 import Utilities(nextHighestPowerOfTwo)
 import qualified Control.Concurrent.Chan.Unagi.NoBlocking.Types as UT
 
+import Prelude
 
 -- | The write end of a channel created with 'newChan'.
 data InChan a = InChan (IO Int) -- readCounterReader, for tryWriteChan
@@ -143,7 +144,7 @@
     savedEmptyTkt <- readArrayElem firstSeg 0
     stream <- Stream firstSeg <$> newIORef Nothing
     let end = ChanEnd logBounds boundsMn1 segSource 
-                  <$> newCounter (startingCellOffset - 1)
+                  <$> newCounter startingCellOffset
                   <*> newIORef (StreamHead startingCellOffset stream)
     endR@(ChanEnd _ _ _ counterR _) <- end
     endW <- end
@@ -245,11 +246,10 @@
         else writeChanWithBlocking False c a >> return True
 
 
-readChanOnExceptionUnmasked :: (IO a -> IO a) -> OutChan a -> IO a
-{-# INLINE readChanOnExceptionUnmasked #-}
-readChanOnExceptionUnmasked h = \oc-> do
-    (seg,segIx) <- startReadChan oc
-
+-- The core of our 'read' operations, with exception handler:
+readSegIxUnmasked :: (IO a -> IO a) -> (StreamSegment a, Int) -> IO a
+{-# INLINE readSegIxUnmasked #-}
+readSegIxUnmasked h = \(seg,segIx)-> do
     cellTkt <- readArrayElem seg segIx
     case peekTicket cellTkt of
          Written a -> return a
@@ -275,7 +275,7 @@
     (segIx, nextSeg, updateStreamHeadIfNecessary) <- moveToNextCell asReader ce
     let (seg,next) = case nextSeg of
             NextByReader (Stream s n) -> (s,n)
-            _ -> error "moveToNextCell returned a non-reader-installed next segment to readChanOnExceptionUnmasked"
+            _ -> error "moveToNextCell returned a non-reader-installed next segment to readSegIxUnmasked"
     -- try to pre-allocate next segment:
     when (segIx == 0) $ void $
       waitingAdvanceStream asReader next segSource 0
@@ -284,32 +284,35 @@
     return (seg,segIx)
 
 
--- TODO we might want also a blocking `IO a` returned here, or use an opaque
--- Element type supporting blocking, since otherwise calling `tryReadChan` we
--- give up the ability to block on that element. Please open an issue if you
--- need this in the meantime. And also handling of lost elements on async
--- exceptions. And also isActive...
 
--- | Returns immediately with an @'UT.Element' a@ future, which returns one
--- unique element when it becomes available via 'UT.tryRead'.
+-- | Returns immediately with:
 --
+--  - an @'UT.Element' a@ future, which returns one unique element when it
+--  becomes available via 'UT.tryRead'.
+--
+--  - a blocking @IO@ action that returns the element when it becomes available.
+--
 -- /Note re. exceptions/: When an async exception is raised during a @tryReadChan@ 
 -- the message that the read would have returned is likely to be lost, just as
 -- it would be when raised directly after this function returns.
-tryReadChan :: OutChan a -> IO (UT.Element a)
+tryReadChan :: OutChan a -> IO (UT.Element a, IO a)
 {-# INLINE tryReadChan #-}
 tryReadChan oc = do -- no mask necessary
     (seg,segIx) <- startReadChan oc
 
-    return $ UT.Element $ do
+    return ( 
+       UT.Element $ do
         cell <- P.readArray seg segIx
         case cell of
              Written a -> return $ Just a
              Empty -> return Nothing
              Blocking v -> tryReadMVar v
 
+     , readSegIxUnmasked id (seg,segIx)
+     )
 
 
+
 -- | Read an element from the chan, blocking if the chan is empty.
 --
 -- /Note re. exceptions/: When an async exception is raised during a @readChan@ 
@@ -318,7 +321,7 @@
 -- this scenario, you can use 'readChanOnException'.
 readChan :: OutChan a -> IO a
 {-# INLINE readChan #-}
-readChan = readChanOnExceptionUnmasked id
+readChan = \oc-> startReadChan oc >>= readSegIxUnmasked id
 
 -- | Like 'readChan' but allows recovery of the queue element which would have
 -- been read, in the case that an async exception is raised during the read. To
@@ -330,8 +333,10 @@
 -- the passed @IO a@ is the only way to access the element.
 readChanOnException :: OutChan a -> (IO a -> IO ()) -> IO a
 {-# INLINE readChanOnException #-}
-readChanOnException c h = mask_ $ 
-    readChanOnExceptionUnmasked (\io-> io `onException` (h io)) c
+readChanOnException oc h = mask_ (
+    startReadChan oc >>= 
+      readSegIxUnmasked (\io-> io `onException` (h io))
+    )
 
 
 -- increments counter, finds stream segment of corresponding cell (updating the
diff --git a/src/Control/Concurrent/Chan/Unagi/Internal.hs b/src/Control/Concurrent/Chan/Unagi/Internal.hs
--- a/src/Control/Concurrent/Chan/Unagi/Internal.hs
+++ b/src/Control/Concurrent/Chan/Unagi/Internal.hs
@@ -32,6 +32,7 @@
 import qualified Control.Concurrent.Chan.Unagi.NoBlocking.Types as UT
 import Utilities(touchIORef)
 
+import Prelude
 
 -- | The write end of a channel created with 'newChan'.
 data InChan a = InChan !(Ticket (Cell a)) !(ChanEnd (Cell a))
@@ -115,7 +116,7 @@
     savedEmptyTkt <- readArrayElem firstSeg 0
     stream <- Stream firstSeg <$> newIORef NoSegment
     let end = ChanEnd segSource 
-                  <$> newCounter (startingCellOffset - 1)
+                  <$> newCounter startingCellOffset
                   <*> newIORef (StreamHead startingCellOffset stream)
     liftA2 (,) (InChan savedEmptyTkt <$> end) (OutChan <$> end)
 
@@ -177,10 +178,10 @@
 -- from whether cakes are given to well-behaved customers in the order they
 -- came out of the oven, or whether a customer leaving at the wrong moment
 -- might cause the cake shop to burn down...
-readChanOnExceptionUnmasked :: (IO a -> IO a) -> OutChan a -> IO a
-{-# INLINE readChanOnExceptionUnmasked #-}
-readChanOnExceptionUnmasked h = \(OutChan ce)-> do
-    (segIx, (Stream seg _), maybeUpdateStreamHead) <- moveToNextCell ce
+readSegIxUnmasked :: (IO a -> IO a) -> (Int, Stream (Cell a), IO ()) -> IO a
+{-# INLINE readSegIxUnmasked #-}
+readSegIxUnmasked h =
+  \(segIx, (Stream seg _), maybeUpdateStreamHead)-> do
     maybeUpdateStreamHead
     cellTkt <- readArrayElem seg segIx
     case peekTicket cellTkt of
@@ -201,33 +202,36 @@
   where readBlocking v = inline h $ readMVar v 
 
 
--- TODO we might want also a blocking `IO a` returned here, or use an opaque
--- Element type supporting blocking, since otherwise calling `tryReadChan` we
--- give up the ability to block on that element. Please open an issue if you
--- need this in the meantime. And also handling of lost elements on async
--- exceptions. And also isActive...
-
--- | Returns immediately with an @'UT.Element' a@ future, which returns one
--- unique element when it becomes available via 'UT.tryRead'. If you're using
--- this function exclusively you might find the implementation in 
--- "Control.Concurrent.Chan.Unagi.NoBlocking" is faster.
+-- | Returns immediately with:
 --
+--  - an @'UT.Element' a@ future, which returns one unique element when it
+--  becomes available via 'UT.tryRead'.
+--
+--  - a blocking @IO@ action that returns the element when it becomes available.
+--
+-- If you're using this function exclusively you might find the implementation
+-- in "Control.Concurrent.Chan.Unagi.NoBlocking" is faster.
+--
 -- /Note re. exceptions/: When an async exception is raised during a @tryReadChan@ 
 -- the message that the read would have returned is likely to be lost, just as
 -- it would be when raised directly after this function returns.
-tryReadChan :: OutChan a -> IO (UT.Element a)
+tryReadChan :: OutChan a -> IO (UT.Element a, IO a)
 {-# INLINE tryReadChan #-}
 tryReadChan (OutChan ce) = do -- no masking needed
-    (segIx, (Stream seg _), maybeUpdateStreamHead) <- moveToNextCell ce
+    segStuff@(segIx, (Stream seg _), maybeUpdateStreamHead) <- moveToNextCell ce
     maybeUpdateStreamHead
-    return $ UT.Element $ do
-      cell <- P.readArray seg segIx
-      case cell of
-           Written a  -> return $ Just a
-           Empty      -> return Nothing
-           Blocking v -> tryReadMVar v
+    return ( 
+        UT.Element $ do
+          cell <- P.readArray seg segIx
+          case cell of
+               Written a  -> return $ Just a
+               Empty      -> return Nothing
+               Blocking v -> tryReadMVar v
 
+      , readSegIxUnmasked id segStuff 
+      )
 
+
 -- | Read an element from the chan, blocking if the chan is empty.
 --
 -- /Note re. exceptions/: When an async exception is raised during a @readChan@ 
@@ -236,7 +240,7 @@
 -- this scenario, you can use 'readChanOnException'.
 readChan :: OutChan a -> IO a
 {-# INLINE readChan #-}
-readChan = readChanOnExceptionUnmasked id
+readChan = \(OutChan ce)-> moveToNextCell ce >>= readSegIxUnmasked id
 
 -- | Like 'readChan' but allows recovery of the queue element which would have
 -- been read, in the case that an async exception is raised during the read. To
@@ -248,8 +252,9 @@
 -- the passed @IO a@ is the only way to access the element.
 readChanOnException :: OutChan a -> (IO a -> IO ()) -> IO a
 {-# INLINE readChanOnException #-}
-readChanOnException c h = mask_ $ 
-    readChanOnExceptionUnmasked (\io-> io `onException` (h io)) c
+readChanOnException (OutChan ce) h = mask_ ( 
+    moveToNextCell ce >>= 
+      readSegIxUnmasked (\io-> io `onException` (h io)) )
 
 
 ------------ NOTE: ALL CODE BELOW IS RE-USED IN Unagi.NoBlocking --------------
diff --git a/src/Control/Concurrent/Chan/Unagi/NoBlocking/Internal.hs b/src/Control/Concurrent/Chan/Unagi/NoBlocking/Internal.hs
--- a/src/Control/Concurrent/Chan/Unagi/NoBlocking/Internal.hs
+++ b/src/Control/Concurrent/Chan/Unagi/NoBlocking/Internal.hs
@@ -40,7 +40,9 @@
 import Control.Concurrent.Chan.Unagi.Constants
 import qualified Control.Concurrent.Chan.Unagi.NoBlocking.Types as UT
 
+import Prelude
 
+
 -- | The write end of a channel created with 'newChan'.
 data InChan a = InChan !(IORef Bool) -- Used for creating an OutChan in dupChan
                        !(ChanEnd (Cell a))
@@ -69,7 +71,7 @@
     stream <- Stream <$> segSource 
                      <*> newIORef NoSegment
     let end = ChanEnd segSource 
-                  <$> newCounter (startingCellOffset - 1)
+                  <$> newCounter startingCellOffset
                   <*> newIORef (StreamHead startingCellOffset stream)
     inEnd@(ChanEnd _ _ inHeadRef) <- end
     finalizee <- newIORef True
@@ -202,13 +204,13 @@
 --      forkIO $ printStream str3   -- prints: 3,6,9
 --    where 
 --      printStream str = do
---        h <- 'tryReadNext' str
+--        h <- 'UT.tryReadNext' str
 --        case h of
---          'Next' a str' -> print a >> printStream str'
+--          'UT.Next' a str' -> print a >> printStream str'
 --          -- We know that all values were already written, so a Pending tells 
 --          -- us we can exit; in other cases we might call 'yield' and then 
---          -- retry that same @'tryReadNext' str@:
---          'Pending' -> return ()
+--          -- retry that same @'UT.tryReadNext' str@:
+--          'UT.Pending' -> return ()
 -- @
 --
 -- Be aware: if one stream consumer falls behind another (e.g. because it is
@@ -223,8 +225,8 @@
     (StreamHead offsetInitial strInitial) <- readIORef streamHead
     -- Make sure the read above occurs before our readCounter:
     loadLoadBarrier
-    -- Linearizable as the first unread element; N.B. (+1):
-    !ix0 <- (+1) <$> readCounter counter
+    -- Linearizable as the first unread element
+    !ix0 <- readCounter counter
 
     -- Adapted from moveToNextCell, given a stream segment location `str0` and
     -- its offset, `offset0`, this navigates to the UT.Stream segment holding `ix`
diff --git a/src/Control/Concurrent/Chan/Unagi/NoBlocking/Unboxed/Internal.hs b/src/Control/Concurrent/Chan/Unagi/NoBlocking/Unboxed/Internal.hs
--- a/src/Control/Concurrent/Chan/Unagi/NoBlocking/Unboxed/Internal.hs
+++ b/src/Control/Concurrent/Chan/Unagi/NoBlocking/Unboxed/Internal.hs
@@ -37,6 +37,8 @@
 
 import Control.Concurrent.Chan.Unagi.Constants
 
+import Prelude
+
 -- We can re-use much of the Unagi.Unboxed implementation here, and some of
 -- Unagi.NoBlocking (at least our types, which is important):
 import Control.Concurrent.Chan.Unagi.Unboxed.Internal(
@@ -74,7 +76,7 @@
                              <*> undefinedNewIndexedMVar 
                              <*> newIORef NoSegment
     let end = ChanEnd
-                  <$> newCounter (startingCellOffset - 1)
+                  <$> newCounter startingCellOffset
                   <*> newIORef (StreamHead startingCellOffset stream)
     inEnd@(ChanEnd _ inHeadRef) <- end
     finalizee <- newIORef True
@@ -248,13 +250,13 @@
 --      forkIO $ printStream str3   -- prints: 3,6,9
 --    where 
 --      printStream str = do
---        h <- 'tryReadNext' str
+--        h <- 'UT.tryReadNext' str
 --        case h of
---          'Next' a str' -> print a >> printStream str'
+--          'UT.Next' a str' -> print a >> printStream str'
 --          -- We know that all values were already written, so a Pending tells 
 --          -- us we can exit; in other cases we might call 'yield' and then 
---          -- retry that same @'tryReadNext' str@:
---          'Pending' -> return ()
+--          -- retry that same @'UT.tryReadNext' str@:
+--          'UT.Pending' -> return ()
 -- @
 --
 -- Be aware: if one stream consumer falls behind another (e.g. because it is
@@ -269,8 +271,8 @@
     (StreamHead offsetInitial strInitial) <- readIORef streamHead
     -- Make sure the read above occurs before our readCounter:
     loadLoadBarrier
-    -- Linearizable as the first unread element; N.B. (+1):
-    !ix0 <- (+1) <$> readCounter counter
+    -- Linearizable as the first unread element
+    !ix0 <- readCounter counter
 
     -- Adapted from moveToNextCell, given a stream segment location `str0` and
     -- its offset, `offset0`, this navigates to the UT.Stream segment holding `ix`
diff --git a/src/Control/Concurrent/Chan/Unagi/Unboxed/Internal.hs b/src/Control/Concurrent/Chan/Unagi/Unboxed/Internal.hs
--- a/src/Control/Concurrent/Chan/Unagi/Unboxed/Internal.hs
+++ b/src/Control/Concurrent/Chan/Unagi/Unboxed/Internal.hs
@@ -78,6 +78,8 @@
 import Control.Concurrent.Chan.Unagi.Constants
 import qualified Control.Concurrent.Chan.Unagi.NoBlocking.Types as UT
 
+import Prelude
+
 -- | The write end of a channel created with 'newChan'.
 newtype InChan a = InChan (ChanEnd a)
     deriving Typeable
@@ -245,7 +247,7 @@
     (sigArr0,eArr0) <- segSource
     stream <- Stream sigArr0 eArr0 <$> newIndexedMVar <*> newIORef NoSegment
     let end = ChanEnd
-                  <$> newCounter (startingCellOffset - 1)
+                  <$> newCounter startingCellOffset
                   <*> newIORef (StreamHead startingCellOffset stream)
     liftA2 (,) (InChan <$> end) (OutChan <$> end)
 
@@ -285,13 +287,14 @@
   -- [1] casByteArrayInt provides the write barrier we need here to make sure
   -- GHC maintains our ordering such that the element is written before we
   -- signal its availability with the CAS to sigArr that follows. See [2] in
-  -- readChanOnExceptionUnmasked.
+  -- readSegIxUnmasked.
 
 
-readChanOnExceptionUnmasked :: UnagiPrim a=> (IO a -> IO a) -> OutChan a -> IO a
-{-# INLINE readChanOnExceptionUnmasked #-}
-readChanOnExceptionUnmasked h = \(OutChan ce)-> do
-    (segIx, (Stream sigArr eArr mvarIndexed _), maybeUpdateStreamHead) <- moveToNextCell ce
+-- Core of blocking read functions, taking handler and output of moveToNextCell
+readSegIxUnmasked :: UnagiPrim a=> (IO a -> IO a) -> (Int, Stream a, IO ()) -> IO a
+{-# INLINE readSegIxUnmasked #-}
+readSegIxUnmasked h =
+  \(segIx, (Stream sigArr eArr mvarIndexed _), maybeUpdateStreamHead)-> do
     maybeUpdateStreamHead
     let readBlocking = inline h $ readMVarIx mvarIndexed segIx    -- NOTE [1]
         readElem = readElementArray eArr segIx
@@ -305,7 +308,7 @@
                 1 {- Written -} -> readElem
                 -- else in the meantime a dupChan reader read, blocking
                 2 {- Blocking -} -> readBlocking
-                _ -> error "Invalid signal seen in readChanOnExceptionUnmasked!"
+                _ -> error "Invalid signal seen in readSegIxUnmasked!"
     -- If we know writes of this element are atomic, we can determine if the
     -- element has been written, and possibly return it without consulting
     -- sigArr.
@@ -332,19 +335,24 @@
 -- need this in the meantime. And also handling of lost elements on async
 -- exceptions. And also isActive...
 
--- | Returns immediately with an @'UT.Element' a@ future, which returns one
--- unique element when it becomes available via 'UT.tryRead'. If you're using
--- this function exclusively you might find the implementation in 
--- "Control.Concurrent.Chan.Unagi.NoBlocking.Unboxed" is faster.
+-- | Returns immediately with:
 --
+--  - an @'UT.Element' a@ future, which returns one unique element when it
+--  becomes available via 'UT.tryRead'.
+--
+--  - a blocking @IO@ action that returns the element when it becomes available.
+--
+-- If you're using this function exclusively you might find the implementation
+-- in "Control.Concurrent.Chan.Unagi.NoBlocking.Unboxed" is faster.
+--
 -- /Note re. exceptions/: When an async exception is raised during a @tryReadChan@ 
 -- the message that the read would have returned is likely to be lost, just as
 -- it would be when raised directly after this function returns.
-tryReadChan :: UnagiPrim a=> OutChan a -> IO (UT.Element a)
+tryReadChan :: UnagiPrim a=> OutChan a -> IO (UT.Element a, IO a)
 {-# INLINE tryReadChan #-}
 tryReadChan (OutChan ce) = do -- no masking needed
--- NOTE: implementation adapted from readChanOnExceptionUnmasked:
-    (segIx, (Stream sigArr eArr mvarIndexed _), maybeUpdateStreamHead) <- moveToNextCell ce
+-- NOTE: implementation adapted from readSegIxUnmasked:
+    segStuff@(segIx, (Stream sigArr eArr mvarIndexed _), maybeUpdateStreamHead) <- moveToNextCell ce
     maybeUpdateStreamHead
     let readElem = readElementArray eArr segIx
         slowRead = do 
@@ -354,16 +362,20 @@
                 1 {- Written -} -> loadLoadBarrier  >>  Just <$> readElem
                 2 {- Blocking -} -> tryReadMVarIx mvarIndexed segIx
                 _ -> error "Invalid signal seen in tryReadChan!"
-    return $ UT.Element $
-      case atomicUnicorn of
-         Just magic -> do
-            el <- readElem
-            if (el /= magic) 
-              then return $ Just el
-              else slowRead
-         Nothing -> slowRead
+    return ( 
+        UT.Element $
+          case atomicUnicorn of
+             Just magic -> do
+                el <- readElem
+                if (el /= magic) 
+                  then return $ Just el
+                  else slowRead
+             Nothing -> slowRead
 
+      , readSegIxUnmasked id segStuff
+      )
 
+
 -- | Read an element from the chan, blocking if the chan is empty.
 --
 -- /Note re. exceptions/: When an async exception is raised during a @readChan@ 
@@ -372,7 +384,7 @@
 -- this scenario, you can use 'readChanOnException'.
 readChan :: UnagiPrim a=> OutChan a -> IO a
 {-# INLINE readChan #-}
-readChan = readChanOnExceptionUnmasked id
+readChan = \(OutChan ce)-> moveToNextCell ce >>= readSegIxUnmasked id
 
 -- | Like 'readChan' but allows recovery of the queue element which would have
 -- been read, in the case that an async exception is raised during the read. To
@@ -384,8 +396,9 @@
 -- the passed @IO a@ is the only way to access the element.
 readChanOnException :: UnagiPrim a=> OutChan a -> (IO a -> IO ()) -> IO a
 {-# INLINE readChanOnException #-}
-readChanOnException c h = mask_ $ 
-    readChanOnExceptionUnmasked (\io-> io `onException` (h io)) c
+readChanOnException (OutChan ce) h = mask_ $ 
+    moveToNextCell ce >>=
+      readSegIxUnmasked (\io-> io `onException` (h io))
 
 
 
diff --git a/src/Data/Atomics/Counter/Fat.hs b/src/Data/Atomics/Counter/Fat.hs
--- a/src/Data/Atomics/Counter/Fat.hs
+++ b/src/Data/Atomics/Counter/Fat.hs
@@ -11,7 +11,7 @@
 import Data.Primitive.MachDeps(sIZEOF_INT)
 import Control.Monad.Primitive(RealWorld)
 import Data.Primitive.ByteArray
-import Data.Atomics(fetchAddByteArrayInt)
+import Data.Atomics(fetchAddIntArray)
 import Control.Exception(assert)
 
 newtype AtomicCounter = AtomicCounter (MutableByteArray RealWorld)
@@ -34,7 +34,7 @@
 incrCounter :: Int -> AtomicCounter -> IO Int
 {-# INLINE incrCounter #-}
 incrCounter incr (AtomicCounter arr) =
-    fetchAddByteArrayInt arr 0 incr
+    fetchAddIntArray arr 0 incr
 
 readCounter :: AtomicCounter -> IO Int
 {-# INLINE readCounter #-}
diff --git a/src/Utilities.hs b/src/Utilities.hs
--- a/src/Utilities.hs
+++ b/src/Utilities.hs
@@ -20,6 +20,7 @@
 import GHC.IORef(IORef(..))
 import GHC.STRef(STRef(..))
 import GHC.Base(IO(..))
+import Prelude
 
 -- For now: a reverse-ordered assoc list; an IntMap might be better
 newtype IndexedMVar a = IndexedMVar (IORef [(Int, MVar a)])
diff --git a/tests/Atomics.hs b/tests/Atomics.hs
--- a/tests/Atomics.hs
+++ b/tests/Atomics.hs
@@ -37,7 +37,7 @@
     unless (n == 1337) $ error "newCounter magnificently broken"
     n2 <- incrCounter 1 cntr
     n2' <- readCounter cntr
-    unless (n2 == 1338 && n2' == 1338) $ error "incrCounter magnificently broken"
+    unless (n2 == 1337 && n2' == 1338) $ error "incrCounter magnificently broken"
 
 cHUNK_SIZE, maxInt, minInt :: Int
 cHUNK_SIZE = 32 -- MUST REMAIN POWER OF TWO for now
@@ -56,7 +56,7 @@
             in if xmy == x `mod` y
                     then xmy
                     else error "Our bitwise mod isn't working the way we expect in testCounterOverflow"
-    cntr <- newCounter (maxInt - (cHUNK_SIZE `div` 2)) 
+    cntr <- newCounter (maxInt - (cHUNK_SIZE `div` 2) + 1) 
     spanningCntr <- replicateM cHUNK_SIZE (incrCounter 1 cntr)
     -- make sure our test is working
     if all (>0) spanningCntr || all (<0) spanningCntr
@@ -79,12 +79,13 @@
 
     -- (We don't use this property)
     cntr2 <- newCounter maxInt
-    mbnd <- incrCounter 1 cntr2
-    unless (mbnd == minInt) $ 
+    _ <- incrCounter 1 cntr2
+    mnbnd <- readCounter cntr2
+    unless (mnbnd == minInt) $ 
         error $ "Incrementing counter at maxbound didn't yield minBound"
 
     -- (3) test subtraction across boundary: count - newFirstIndex, for window spanning boundary.
-    cntr3 <- newCounter (maxInt - 1)
+    cntr3 <- newCounter maxInt
     let ls = take 30 $ iterate (+1) $ maxInt - 10
     cs <- mapM (\x-> fmap (subtract x) $ incrCounter 1 cntr3) ls
     unless (cs == replicate 30 10) $ 
diff --git a/tests/Deadlocks.hs b/tests/Deadlocks.hs
--- a/tests/Deadlocks.hs
+++ b/tests/Deadlocks.hs
@@ -33,6 +33,18 @@
     -- No real need to checkDeadlocksWriter for tryReadChan.
 
     putStrLn "==================="
+    putStrLn "Testing Unagi (with tryReadChan, blocking):"
+    -- ------
+    putStr $ "    Checking for deadlocks from killed reader, x"++show tries++"... "
+    checkDeadlocksReader unagiTryReadBlockingImpl tries
+    putStrLn "OK"
+    -- ------
+    putStr $ "    Checking for deadlocks from killed writer, x"++show tries++"... "
+    checkDeadlocksWriter unagiTryReadBlockingImpl tries
+    putStrLn "OK"
+
+
+    putStrLn "==================="
     putStrLn "Testing Unagi.NoBlocking:"
     -- ------
     putStr $ "    Checking for deadlocks from killed reader, x"++show tries++"... "
@@ -60,6 +72,17 @@
     putStr $ "    Checking for deadlocks from killed reader, x"++show tries++"... "
     checkDeadlocksReader unboxedUnagiTryReadImpl tries
     putStrLn "OK"
+    
+    putStrLn "==================="
+    putStrLn "Testing Unagi.NoBlocking.Unboxed (with tryReadChan, blocking):"
+    -- ------
+    putStr $ "    Checking for deadlocks from killed reader, x"++show tries++"... "
+    checkDeadlocksReader unboxedUnagiTryReadBlockingImpl tries
+    putStrLn "OK"
+    -- ------
+    putStr $ "    Checking for deadlocks from killed writer, x"++show tries++"... "
+    checkDeadlocksWriter unboxedUnagiTryReadBlockingImpl tries
+    putStrLn "OK"
 
     putStrLn "==================="
     putStrLn "Testing Unagi.Unboxed:"
@@ -85,10 +108,16 @@
     checkDeadlocksReader (unagiBoundedTryReadImpl 50000) tries
     putStrLn "OK"
     -- ------
+    putStr $ "    Checking for deadlocks from killed reader (tryReadChan, blocking), x"++show tries++"... "
+    -- bounds must be > 10000 here (note actual bounds rounded up to power of 2):
+    checkDeadlocksReader (unagiBoundedTryReadBlockingImpl 50000) tries
+    putStrLn "OK"
+    -- ------
     putStr $ "    Checking for deadlocks from killed writer, x"++show tries++"... "
     -- fragile bounds must be large enought to never be reached here:
     checkDeadlocksWriterBounded tries
     putStrLn "OK"
+    -- TODO same test for unagiBoundedTryReadBlockingImpl
 
 
 -- -- Chan002.hs -- --
diff --git a/tests/DupChan.hs b/tests/DupChan.hs
--- a/tests/DupChan.hs
+++ b/tests/DupChan.hs
@@ -33,7 +33,19 @@
     putStr "    Writer/dupChan+Reader... "
     replicateM_ 1000 $ dupChanTest2 unagiTryReadImpl 10000
     putStrLn "OK"
+    
+    putStrLn "==================="
+    putStrLn "Test dupChan Unagi (with tryReadChan, blocking):"
+    -- ------
+    putStr "    Reader/Reader... "
+    replicateM_ 1000 $ dupChanTest1 unagiTryReadBlockingImpl 50000
+    putStrLn "OK"
+    -- ------
+    putStr "    Writer/dupChan+Reader... "
+    replicateM_ 1000 $ dupChanTest2 unagiTryReadBlockingImpl 10000
+    putStrLn "OK"
 
+
     putStrLn "==================="
     putStrLn "Test dupChan Unagi.NoBlocking:"
     -- ------
@@ -79,6 +91,17 @@
     putStrLn "OK"
 
     putStrLn "==================="
+    putStrLn "Test dupChan Unagi.Unboxed (with tryReadChan, blocking):"
+    -- ------
+    putStr "    Reader/Reader... "
+    replicateM_ 1000 $ dupChanTest1 unboxedUnagiTryReadBlockingImpl 50000
+    putStrLn "OK"
+    -- ------
+    putStr "    Writer/dupChan+Reader... "
+    replicateM_ 1000 $ dupChanTest2 unboxedUnagiTryReadBlockingImpl 10000
+    putStrLn "OK"
+
+    putStrLn "==================="
     putStrLn "Test dupChan Unagi.Bounded (and with tryRead)"
     -- NOTE: n must be <= bounds in dupChanTest1:
     forM_ [(4096,4096),(65536,50000),(4,2)] $ \(bounds, n)-> do
@@ -86,11 +109,13 @@
         putStr $ "    Reader/Reader with bounds "++(show bounds)++"... "
         replicateM_ 100 $ dupChanTest1 (unagiBoundedImpl bounds) n
         replicateM_ 100 $ dupChanTest1 (unagiBoundedTryReadImpl bounds) n
+        replicateM_ 100 $ dupChanTest1 (unagiBoundedTryReadBlockingImpl bounds) n
         putStrLn "OK"
     forM_ [2, 1024, 65536] $ \bounds-> do
         putStr $ "    Writer/dupChan+Reader with bounds "++(show bounds)++"... "
         replicateM_ 100 $ dupChanTest2 (unagiBoundedImpl bounds) 10000
         replicateM_ 100 $ dupChanTest2 (unagiBoundedTryReadImpl bounds) 10000
+        replicateM_ 100 $ dupChanTest2 (unagiBoundedTryReadBlockingImpl bounds) 10000
         putStrLn "OK"
 
 -- Check output where dupChan at known point in input stream, with two
diff --git a/tests/Implementations.hs b/tests/Implementations.hs
--- a/tests/Implementations.hs
+++ b/tests/Implementations.hs
@@ -9,17 +9,20 @@
 
 type Implementation inc outc a = (IO (inc a, outc a), inc a -> a -> IO (), outc a -> IO a, inc a -> IO (outc a))
 
-unagiImpl , unagiTryReadImpl :: Implementation U.InChan U.OutChan a
+unagiImpl , unagiTryReadImpl , unagiTryReadBlockingImpl :: Implementation U.InChan U.OutChan a
 unagiImpl =  (U.newChan, U.writeChan, U.readChan, U.dupChan)
 unagiTryReadImpl =  (U.newChan, U.writeChan, u_trying_readChan, U.dupChan)
+unagiTryReadBlockingImpl =  (U.newChan, U.writeChan, u_trying_readChan_blocking, U.dupChan)
 
-unboxedUnagiImpl , unboxedUnagiTryReadImpl:: (UU.UnagiPrim a)=> Implementation UU.InChan UU.OutChan a
+unboxedUnagiImpl , unboxedUnagiTryReadImpl, unboxedUnagiTryReadBlockingImpl :: (UU.UnagiPrim a)=> Implementation UU.InChan UU.OutChan a
 unboxedUnagiImpl = (UU.newChan, UU.writeChan, UU.readChan, UU.dupChan)
 unboxedUnagiTryReadImpl = (UU.newChan, UU.writeChan, uu_trying_readChan, UU.dupChan)
+unboxedUnagiTryReadBlockingImpl = (UU.newChan, UU.writeChan, uu_trying_readChan_blocking, UU.dupChan)
 
-unagiBoundedImpl , unagiBoundedTryReadImpl:: Int -> Implementation UB.InChan UB.OutChan a
+unagiBoundedImpl , unagiBoundedTryReadImpl, unagiBoundedTryReadBlockingImpl :: Int -> Implementation UB.InChan UB.OutChan a
 unagiBoundedImpl n =  (UB.newChan n, UB.writeChan, UB.readChan, UB.dupChan)
 unagiBoundedTryReadImpl n =  (UB.newChan n, UB.writeChan, ub_trying_readChan, UB.dupChan)
+unagiBoundedTryReadBlockingImpl n =  (UB.newChan n, UB.writeChan, ub_trying_readChan_blocking, UB.dupChan)
 
 -- We use our yield "blocking" readChan here, and below:
 unagiNoBlockingImpl :: Implementation UN.InChan UN.OutChan a
@@ -32,18 +35,29 @@
 -- way to do smoke tests of `tryReadChan`:
 uu_trying_readChan :: (UU.UnagiPrim a)=> UU.OutChan a -> IO a
 uu_trying_readChan oc = do
-    e <- UU.tryReadChan oc
+    (e,_) <- UU.tryReadChan oc
     let go = UU.tryRead e >>= maybe (threadDelay 1000 >> go) return
     go
 
 u_trying_readChan :: U.OutChan a -> IO a
 u_trying_readChan oc = do
-    e <- U.tryReadChan oc
+    (e,_) <- U.tryReadChan oc
     let go = U.tryRead e >>= maybe (threadDelay 1000 >> go) return
     go
 
 ub_trying_readChan :: UB.OutChan a -> IO a
 ub_trying_readChan oc = do
-    e <- UB.tryReadChan oc
+    (e,_) <- UB.tryReadChan oc
     let go = UB.tryRead e >>= maybe (threadDelay 1000 >> go) return
     go
+
+-- And we want to test the blocking action of tryReadChan as well:
+uu_trying_readChan_blocking :: (UU.UnagiPrim a)=> UU.OutChan a -> IO a
+uu_trying_readChan_blocking oc = UU.tryReadChan oc >>= snd
+
+u_trying_readChan_blocking :: U.OutChan a -> IO a
+u_trying_readChan_blocking oc = U.tryReadChan oc >>= snd
+
+ub_trying_readChan_blocking :: UB.OutChan a -> IO a
+ub_trying_readChan_blocking oc = UB.tryReadChan oc >>= snd
+
diff --git a/tests/Smoke.hs b/tests/Smoke.hs
--- a/tests/Smoke.hs
+++ b/tests/Smoke.hs
@@ -45,7 +45,15 @@
     putStrLn "OK"
     -- ------
     testContention unagiTryReadImpl 2 2 1000000
-
+    
+    putStrLn "==================="
+    putStrLn "Testing Unagi (with tryReadChan, blocking):"
+    -- ------
+    putStr "    FIFO smoke test... "
+    fifoSmoke unagiTryReadBlockingImpl 1000000
+    putStrLn "OK"
+    -- ------
+    testContention unagiTryReadBlockingImpl 2 2 1000000
 
     putStrLn "==================="
     putStrLn "Testing Unagi.NoBlocking:"
@@ -99,6 +107,31 @@
         testContention (unagiBoundedImpl bounds) 2 2 1000000
         -- because this is slow:
         when (bounds > 100) $ testContention (unagiBoundedTryReadImpl bounds) 2 2 1000000
+
+    putStrLn "==================="
+    putStrLn "Testing Unagi.Unboxed (with tryReadChan, blocking):"
+    -- ------
+    putStr "    FIFO smoke test... "
+    fifoSmoke unboxedUnagiTryReadBlockingImpl 1000000
+    putStrLn "OK"
+    -- ------
+    testContention unboxedUnagiTryReadBlockingImpl 2 2 1000000
+
+
+    forM_ [1, 2, 4, 1024] $ \bounds-> do
+        putStrLn "==================="
+        putStrLn $ "Testing Unagi.Bounded (and with tryReadChan) with bounds "++(show bounds)
+        -- ------
+        putStr "    FIFO smoke test... "
+        fifoSmoke (unagiBoundedImpl bounds) 1000000
+        -- because this is slow:
+        when (bounds > 100) $ fifoSmoke (unagiBoundedTryReadBlockingImpl bounds) 1000000
+        putStrLn "OK"
+        -- ------
+        testContention (unagiBoundedImpl bounds) 2 2 1000000
+        -- because this is slow:
+        when (bounds > 100) $ testContention (unagiBoundedTryReadBlockingImpl bounds) 2 2 1000000
+
 
     ) `onException` (threadDelay 1000000) -- wait for forkCatching logging
 
diff --git a/tests/Unagi.hs b/tests/Unagi.hs
--- a/tests/Unagi.hs
+++ b/tests/Unagi.hs
@@ -163,7 +163,7 @@
          
          oCnt <- readCounter $ (\(UI.OutChan(UI.ChanEnd _ cntr _))-> cntr) o
          iCnt <- readCounter $ (\(UI.InChan _ (UI.ChanEnd _ cntr _))-> cntr) i
-         unless (iCnt == numPreloaded + 1) $ 
+         unless (iCnt == numPreloaded + 2) $ 
             error "The InChan counter doesn't match what we'd expect from numPreloaded!"
 
          case finalRead of
@@ -176,17 +176,17 @@
               --
               -- Rare. Reader was killed after reading all pre-loaded messages
               -- but before starting what would be the blocking read:
-              1 | oCnt == numPreloaded -> putStr "X" >> run n normalRetries (numRace + 1)
+              1 | oCnt == (numPreloaded+1) -> putStr "X" >> run n normalRetries (numRace + 1)
                 | otherwise -> error $ "Having read final 1, "++
-                                       "Expecting a counter value of "++(show numPreloaded)++
+                                       "Expecting a counter value of "++(show $ numPreloaded+1)++
                                        " but got: "++(show oCnt)
               2 -> do when usingReadChanOnException $ do
                         shouldBe1 <- join $ takeMVar saved
                         unless (shouldBe1 == 1) $
                           error "The handler for our readChanOnException should only have returned 1"
-                      unless (oCnt == numPreloaded + 1) $
+                      unless (oCnt == numPreloaded + 2) $
                         error $ "Having read final 2, "++
-                                "Expecting a counter value of "++(show $ numPreloaded+1)++
+                                "Expecting a counter value of "++(show $ numPreloaded+2)++
                                 " but got: "++(show oCnt)
                       putStr "+" >> run n (normalRetries + 1) numRace
 
diff --git a/tests/UnagiBounded.hs b/tests/UnagiBounded.hs
--- a/tests/UnagiBounded.hs
+++ b/tests/UnagiBounded.hs
@@ -14,6 +14,8 @@
 
 import Data.Maybe(isNothing)
 
+import Prelude
+
 unagiBoundedMain :: IO ()
 unagiBoundedMain = do
     putStrLn "==================="
@@ -156,7 +158,7 @@
          
          oCnt <- readCounter $ (\(UI.OutChan(UI.ChanEnd _ _ _ cntr _))-> cntr) o
          iCnt <- readCounter $ (\(UI.InChan _ _ (UI.ChanEnd _ _ _ cntr _))-> cntr) i
-         unless (iCnt == numPreloaded + 1) $ 
+         unless (iCnt == numPreloaded + 2) $ 
             error "The InChan counter doesn't match what we'd expect from numPreloaded!"
 
          case finalRead of
@@ -169,17 +171,17 @@
               --
               -- Rare. Reader was killed after reading all pre-loaded messages
               -- but before starting what would be the blocking read:
-              1 | oCnt == numPreloaded -> putStr "X" >> run n normalRetries (numRace + 1)
+              1 | oCnt == numPreloaded+1 -> putStr "X" >> run n normalRetries (numRace + 1)
                 | otherwise -> error $ "Having read final 1, "++
-                                       "Expecting a counter value of "++(show numPreloaded)++
+                                       "Expecting a counter value of "++(show $ numPreloaded+1)++
                                        " but got: "++(show oCnt)
               2 -> do when usingReadChanOnException $ do
                         shouldBe1 <- join $ takeMVar saved
                         unless (shouldBe1 == 1) $
                           error "The handler for our readChanOnException should only have returned 1"
-                      unless (oCnt == numPreloaded + 1) $
+                      unless (oCnt == numPreloaded + 2) $
                         error $ "Having read final 2, "++
-                                "Expecting a counter value of "++(show $ numPreloaded+1)++
+                                "Expecting a counter value of "++(show $ numPreloaded+2)++
                                 " but got: "++(show oCnt)
                       putStr "+" >> run n (normalRetries + 1) numRace
 
diff --git a/tests/UnagiNoBlocking.hs b/tests/UnagiNoBlocking.hs
--- a/tests/UnagiNoBlocking.hs
+++ b/tests/UnagiNoBlocking.hs
@@ -177,7 +177,7 @@
          
          oCnt <- readCounter $ (\(UI.OutChan _ (UI.ChanEnd _ cntr _))-> cntr) o
          iCnt <- readCounter $ (\(UI.InChan  _ (UI.ChanEnd _ cntr _))-> cntr) i
-         unless (iCnt == numPreloaded + 1) $ 
+         unless (iCnt == numPreloaded + 2) $ 
             error "The InChan counter doesn't match what we'd expect from numPreloaded!"
 
          case finalRead of
@@ -190,13 +190,13 @@
               --
               -- Rare. Reader was killed after reading all pre-loaded messages
               -- but before starting what would be the blocking read:
-              1 | oCnt == numPreloaded -> putStr "X" >> run n normalRetries (numRace + 1)
+              1 | oCnt == numPreloaded+1 -> putStr "X" >> run n normalRetries (numRace + 1)
                 | otherwise -> error $ "Having read final 1, "++
-                                       "Expecting a counter value of "++(show numPreloaded)++
+                                       "Expecting a counter value of "++(show $ numPreloaded+1)++
                                        " but got: "++(show oCnt)
-              2 -> do unless (oCnt == numPreloaded + 1) $
+              2 -> do unless (oCnt == numPreloaded + 2) $
                         error $ "Having read final 2, "++
-                                "Expecting a counter value of "++(show $ numPreloaded+1)++
+                                "Expecting a counter value of "++(show $ numPreloaded+2)++
                                 " but got: "++(show oCnt)
                       putStr "+" >> run n (normalRetries + 1) numRace
 
diff --git a/tests/UnagiNoBlockingUnboxed.hs b/tests/UnagiNoBlockingUnboxed.hs
--- a/tests/UnagiNoBlockingUnboxed.hs
+++ b/tests/UnagiNoBlockingUnboxed.hs
@@ -180,7 +180,7 @@
          
          oCnt <- readCounter $ (\(UI.OutChan _ (UI.ChanEnd cntr _))-> cntr) o
          iCnt <- readCounter $ (\(UI.InChan  _ (UI.ChanEnd cntr _))-> cntr) i
-         unless (iCnt == numPreloaded + 1) $ 
+         unless (iCnt == numPreloaded + 2) $ 
             error "The InChan counter doesn't match what we'd expect from numPreloaded!"
 
          case finalRead of
@@ -193,13 +193,13 @@
               --
               -- Rare. Reader was killed after reading all pre-loaded messages
               -- but before starting what would be the blocking read:
-              1 | oCnt == numPreloaded -> putStr "X" >> run n normalRetries (numRace + 1)
+              1 | oCnt == numPreloaded+1 -> putStr "X" >> run n normalRetries (numRace + 1)
                 | otherwise -> error $ "Having read final 1, "++
-                                       "Expecting a counter value of "++(show numPreloaded)++
+                                       "Expecting a counter value of "++(show $ numPreloaded+1)++
                                        " but got: "++(show oCnt)
-              2 -> do unless (oCnt == numPreloaded + 1) $
+              2 -> do unless (oCnt == numPreloaded + 2) $
                         error $ "Having read final 2, "++
-                                "Expecting a counter value of "++(show $ numPreloaded+1)++
+                                "Expecting a counter value of "++(show $ numPreloaded+2)++
                                 " but got: "++(show oCnt)
                       putStr "+" >> run n (normalRetries + 1) numRace
 
diff --git a/tests/UnagiUnboxed.hs b/tests/UnagiUnboxed.hs
--- a/tests/UnagiUnboxed.hs
+++ b/tests/UnagiUnboxed.hs
@@ -273,7 +273,7 @@
          
          oCnt <- readCounter $ (\(UI.OutChan(UI.ChanEnd cntr _))-> cntr) o
          iCnt <- readCounter $ (\(UI.InChan (UI.ChanEnd cntr _))-> cntr) i
-         unless (iCnt == numPreloaded + 1) $ 
+         unless (iCnt == numPreloaded + 2) $ 
             error "The InChan counter doesn't match what we'd expect from numPreloaded!"
 
          case finalRead of
@@ -286,17 +286,17 @@
               --
               -- Rare. Reader was killed after reading all pre-loaded messages
               -- but before starting what would be the blocking read:
-              1 | oCnt == numPreloaded -> putStr "X" >> run n normalRetries (numRace + 1)
+              1 | oCnt == numPreloaded+1 -> putStr "X" >> run n normalRetries (numRace + 1)
                 | otherwise -> error $ "Having read final 1, "++
-                                       "Expecting a counter value of "++(show numPreloaded)++
+                                       "Expecting a counter value of "++(show $ numPreloaded+1)++
                                        " but got: "++(show oCnt)
               2 -> do when usingReadChanOnException $ do
                         shouldBe1 <- join $ takeMVar saved
                         unless (shouldBe1 == 1) $
                           error "The handler for our readChanOnException should only have returned 1"
-                      unless (oCnt == numPreloaded + 1) $
+                      unless (oCnt == numPreloaded + 2) $
                         error $ "Having read final 2, "++
-                                "Expecting a counter value of "++(show $ numPreloaded+1)++
+                                "Expecting a counter value of "++(show $ numPreloaded+2)++
                                 " but got: "++(show oCnt)
                       putStr "+" >> run n (normalRetries + 1) numRace
 
diff --git a/unagi-chan.cabal b/unagi-chan.cabal
--- a/unagi-chan.cabal
+++ b/unagi-chan.cabal
@@ -1,5 +1,5 @@
 name:                unagi-chan
-version:             0.3.0.2
+version:             0.4.0.0
 
 synopsis:            Fast concurrent queues with a Chan-like API, and more
 
@@ -80,7 +80,7 @@
 
   ghc-options:        -Wall -funbox-strict-fields
   build-depends:       base < 5
-                     , atomic-primops >= 0.6.0.5 && <= 0.7
+                     , atomic-primops >= 0.8
                      , primitive>=0.5.3
                      , ghc-prim
   default-language:    Haskell2010
@@ -146,7 +146,7 @@
     , UnagiNoBlockingUnboxed
   build-depends:       base
                      , primitive>=0.5.3
-                     , atomic-primops >= 0.6.0.5 && <= 0.7
+                     , atomic-primops >= 0.8
                      , containers
                      , ghc-prim
   default-language:    Haskell2010
@@ -204,33 +204,33 @@
   build-depends: async
 
 
-flag dev
-  default: False
-  manual: True
+-- flag dev
+--   default: False
+--   manual: True
 
 -- for profiling, checking out core, etc
-executable dev-example
-  -- for n in `find dist/build/dev-example/dev-example-tmp -name '*dump-simpl'`; do cp $n "core-example/$(basename $n).$(git rev-parse --abbrev-ref HEAD)"; done
-  if !flag(dev)
-    buildable: False
-  else
-    build-depends:       
-        base
-      , stm
-      , unagi-chan
-
-  ghc-options: -ddump-to-file -ddump-simpl -dsuppress-module-prefixes -dsuppress-uniques -ddump-core-stats -ddump-inlinings
-  ghc-options: -O2  -rtsopts  
-  
-  -- Either do threaded for eventlogging and simple timing...
-  --ghc-options: -threaded -with-rtsopts=-N2
-  --ghc-options: -eventlog
-  -- ...or do non-threaded runtime
-  ghc-prof-options: -fprof-auto
-  --Relevant profiling RTS settings:  -xt
-  -- TODO also check out +RTS -A10m, and look at output of -sstderr
-
-  hs-source-dirs: core-example
-  main-is: Main.hs
-  default-language:    Haskell2010
-
+-- executable dev-example
+--  -- for n in `find dist/build/dev-example/dev-example-tmp -name '*dump-simpl'`; do cp $n "core-example/$(basename $n).$(git rev-parse --abbrev-ref HEAD)"; done
+--  if !flag(dev)
+--    buildable: False
+--  else
+--    build-depends:       
+--        base
+--      , stm
+--      , unagi-chan
+--
+--  ghc-options: -ddump-to-file -ddump-simpl -dsuppress-module-prefixes -dsuppress-uniques -ddump-core-stats -ddump-inlinings
+--  ghc-options: -O2  -rtsopts  
+--  
+--  -- Either do threaded for eventlogging and simple timing...
+--  ghc-options: -threaded -eventlog
+--  -- and run e.g. with +RTS -N -l
+--
+--  -- ...or do non-threaded runtime
+--  --ghc-prof-options: -fprof-auto
+--  --Relevant profiling RTS settings:  -xt
+--  -- TODO also check out +RTS -A10m, and look at output of -sstderr
+--
+--  hs-source-dirs: core-example
+--  main-is: Main.hs
+--  default-language:    Haskell2010
