diff --git a/CHANGELOG.rst b/CHANGELOG.rst
--- a/CHANGELOG.rst
+++ b/CHANGELOG.rst
@@ -7,6 +7,33 @@
 .. _PVP: https://pvp.haskell.org/
 
 
+1.5.0.0 - No More 7.10 (2018-03-28)
+-----------------------------------
+
+* Git: :tag:`concurrency-1.5.0.0`
+* Hackage: :hackage:`concurrency-1.5.0.0`
+
+Added
+~~~~~
+
+* (:issue:`132`) ``forkOSWithUnmask`` in ``MonadConc``
+
+Changed
+~~~~~~~
+
+* (:issue:`132`) ``Control.Monad.Conc.Class.fork``, ``forkOn``,
+  ``forkOS``, and ``forkOSN`` are top-level definitions.
+
+Miscellaneous
+~~~~~~~~~~~~~
+
+* GHC 7.10 support is dropped.  Dependency lower bounds are:
+
+    * :hackage:`base`: 4.9
+    * :hackage:`array`: 0.5.1
+    * :hackage:`transformers`: 0.5
+
+
 1.4.0.2 (2018-03-11)
 --------------------
 
diff --git a/Control/Concurrent/Classy/Async.hs b/Control/Concurrent/Classy/Async.hs
--- a/Control/Concurrent/Classy/Async.hs
+++ b/Control/Concurrent/Classy/Async.hs
@@ -1,4 +1,3 @@
-{-# LANGUAGE CPP #-}
 {-# LANGUAGE RankNTypes #-}
 
 -- |
@@ -7,7 +6,7 @@
 -- License     : MIT
 -- Maintainer  : Michael Walker <mike@barrucadu.co.uk>
 -- Stability   : stable
--- Portability : CPP, RankNTypes
+-- Portability : RankNTypes
 --
 -- This module is a version of the
 -- <https://hackage.haskell.org/package/async async> package. It
@@ -103,10 +102,7 @@
 import           Control.Monad.Conc.Class
 import           Control.Monad.STM.Class
 import           Data.Foldable                       (foldMap)
-
-#if MIN_VERSION_base(4,9,0)
 import           Data.Semigroup                      (Semigroup(..))
-#endif
 
 -----------------------------------------------------------------------------------------
 -- Asynchronous and Concurrent Actions
@@ -171,13 +167,9 @@
   Concurrently as <|> Concurrently bs =
     Concurrently $ either id id <$> race as bs
 
-#if MIN_VERSION_base(4,9,0)
--- | Only defined for base >= 4.9.0.0
---
--- @since 1.1.2.0
+-- | @since 1.1.2.0
 instance (MonadConc m, Semigroup a) => Semigroup (Concurrently m a) where
   (<>) = liftA2 (<>)
-#endif
 
 -- | @since 1.1.2.0
 instance (MonadConc m, Monoid a) => Monoid (Concurrently m a) where
diff --git a/Control/Concurrent/Classy/STM/TArray.hs b/Control/Concurrent/Classy/STM/TArray.hs
--- a/Control/Concurrent/Classy/STM/TArray.hs
+++ b/Control/Concurrent/Classy/STM/TArray.hs
@@ -37,9 +37,8 @@
 instance MonadSTM stm => MArray (TArray stm) e stm where
   getBounds (TArray a) = pure (bounds a)
 
-  newArray b e = do
-    a <- rep (rangeSize b) (newTVar e)
-    pure $ TArray (listArray b a)
+  newArray b e =
+    TArray . listArray b <$> rep (rangeSize b) (newTVar e)
 
   newArray_ b = newArray b arrEleBottom
 
diff --git a/Control/Monad/Conc/Class.hs b/Control/Monad/Conc/Class.hs
--- a/Control/Monad/Conc/Class.hs
+++ b/Control/Monad/Conc/Class.hs
@@ -31,8 +31,11 @@
   ( MonadConc(..)
 
   -- * Threads
-  , spawn
+  , fork
+  , forkOn
+  , forkOS
   , forkFinally
+  , spawn
   , killThread
 
   -- ** Bound threads
@@ -59,6 +62,7 @@
   -- ** Named Threads
   , forkN
   , forkOnN
+  , forkOSN
 
   -- * Exceptions
   , throw
@@ -146,8 +150,8 @@
 -- Do not be put off by the use of @UndecidableInstances@, it is safe
 -- here.
 --
--- @since 1.4.0.0
-class ( Applicative m, Monad m
+-- @since 1.5.0.0
+class ( Monad m
       , MonadCatch m, MonadThrow m, MonadMask m
       , MonadSTM (STM m)
       , Ord (ThreadId m), Show (ThreadId m)) => MonadConc m  where
@@ -155,7 +159,7 @@
   {-# MINIMAL
         (forkWithUnmask | forkWithUnmaskN)
       , (forkOnWithUnmask | forkOnWithUnmaskN)
-      , (forkOS | forkOSN)
+      , (forkOSWithUnmask | forkOSWithUnmaskN)
       , isCurrentThreadBound
       , getNumCapabilities
       , setNumCapabilities
@@ -211,15 +215,6 @@
   -- @since 1.0.0.0
   type ThreadId m :: *
 
-  -- | Fork a computation to happen concurrently. Communication may
-  -- happen over @MVar@s.
-  --
-  -- > fork ma = forkWithUnmask (const ma)
-  --
-  -- @since 1.0.0.0
-  fork :: m () -> m (ThreadId m)
-  fork ma = forkWithUnmask (const ma)
-
   -- | Like 'fork', but the child thread is passed a function that can
   -- be used to unmask asynchronous exceptions. This function should
   -- not be used within a 'mask' or 'uninterruptibleMask'.
@@ -239,18 +234,6 @@
   forkWithUnmaskN :: String -> ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)
   forkWithUnmaskN _ = forkWithUnmask
 
-  -- | Fork a computation to happen on a specific processor. The
-  -- specified int is the /capability number/, typically capabilities
-  -- correspond to physical processors or cores but this is
-  -- implementation dependent. The int is interpreted modulo to the
-  -- total number of capabilities as returned by 'getNumCapabilities'.
-  --
-  -- > forkOn c ma = forkOnWithUnmask c (const ma)
-  --
-  -- @since 1.0.0.0
-  forkOn :: Int -> m () -> m (ThreadId m)
-  forkOn c ma = forkOnWithUnmask c (const ma)
-
   -- | Like 'forkWithUnmask', but the child thread is pinned to the
   -- given CPU, as with 'forkOn'.
   --
@@ -269,24 +252,24 @@
   forkOnWithUnmaskN :: String -> Int -> ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)
   forkOnWithUnmaskN _ = forkOnWithUnmask
 
-  -- | Fork a computation to happen in a /bound thread/, which is
-  -- necessary if you need to call foreign (non-Haskell) libraries
-  -- that make use of thread-local state, such as OpenGL.
+  -- | Like 'forkOS', but the child thread is passed a function that
+  -- can be used to unmask asynchronous exceptions. This function
+  -- should not be used within a 'mask' or 'uninterruptibleMask'.
   --
-  -- > forkOS = forkOSN ""
+  -- > forkOSWithUnmask = forkOSWithUnmaskN ""
   --
-  -- @since 1.3.0.0
-  forkOS :: m () -> m (ThreadId m)
-  forkOS = forkOSN ""
+  -- @since 1.5.0.0
+  forkOSWithUnmask :: ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)
+  forkOSWithUnmask = forkOSWithUnmaskN ""
 
-  -- | Like 'forkOS', but the thread is given a name which may be used
-  -- to present more useful debugging information.
+  -- | Like 'forkOSWithUnmask', but the thread is given a name which
+  -- may be used to present more useful debugging information.
   --
-  -- > forkOSN _ = forkOS
+  -- > forkOSWithUnmaskN _ = forkOSWithUnmask
   --
-  -- @since 1.3.0.0
-  forkOSN :: String -> m () -> m (ThreadId m)
-  forkOSN _ = forkOS
+  -- @since 1.5.0.0
+  forkOSWithUnmaskN :: String -> ((forall a. m a -> m a) -> m ()) -> m (ThreadId m)
+  forkOSWithUnmaskN _ = forkOSWithUnmask
 
   -- | Returns 'True' if the calling thread is bound, that is, if it
   -- is safe to use foreign libraries that rely on thread-local state
@@ -500,16 +483,31 @@
 
 -- Threads
 
--- | Create a concurrent computation for the provided action, and
--- return a @MVar@ which can be used to query the result.
+-- | Fork a computation to happen concurrently. Communication may
+-- happen over @MVar@s.
 --
--- @since 1.0.0.0
-spawn :: MonadConc m => m a -> m (MVar m a)
-spawn ma = do
-  cvar <- newEmptyMVar
-  _ <- fork $ ma >>= putMVar cvar
-  pure cvar
+-- @since 1.5.0.0
+fork :: MonadConc m => m () -> m (ThreadId m)
+fork ma = forkWithUnmask (const ma)
 
+-- | Fork a computation to happen on a specific processor. The
+-- specified int is the /capability number/, typically capabilities
+-- correspond to physical processors or cores but this is
+-- implementation dependent. The int is interpreted modulo to the
+-- total number of capabilities as returned by 'getNumCapabilities'.
+--
+-- @since 1.5.0.0
+forkOn :: MonadConc m => Int -> m () -> m (ThreadId m)
+forkOn c ma = forkOnWithUnmask c (const ma)
+
+-- | Fork a computation to happen in a /bound thread/, which is
+-- necessary if you need to call foreign (non-Haskell) libraries
+-- that make use of thread-local state, such as OpenGL.
+--
+-- @since 1.5.0.0
+forkOS :: MonadConc m => m () -> m (ThreadId m)
+forkOS ma = forkOSWithUnmask (const ma)
+
 -- | Fork a thread and call the supplied function when the thread is
 -- about to terminate, with an exception or a returned value. The
 -- function is called with asynchronous exceptions masked.
@@ -523,6 +521,16 @@
   mask $ \restore ->
     fork $ Ca.try (restore action) >>= and_then
 
+-- | Create a concurrent computation for the provided action, and
+-- return a @MVar@ which can be used to query the result.
+--
+-- @since 1.0.0.0
+spawn :: MonadConc m => m a -> m (MVar m a)
+spawn ma = do
+  cvar <- newEmptyMVar
+  _ <- fork $ ma >>= putMVar cvar
+  pure cvar
+
 -- | Raise the 'ThreadKilled' exception in the target thread. Note
 -- that if the thread is prepared to catch this exception, it won't
 -- actually kill it.
@@ -545,6 +553,13 @@
 forkOnN :: MonadConc m => String -> Int -> m () -> m (ThreadId m)
 forkOnN name i ma = forkOnWithUnmaskN name i (const ma)
 
+-- | Like 'forkOS', but the thread is given a name which may be used
+-- to present more useful debugging information.
+--
+-- @since 1.5.0.0
+forkOSN :: MonadConc m => String -> m () -> m (ThreadId m)
+forkOSN name ma = forkOSWithUnmaskN name (const ma)
+
 -- | Run the computation passed as the first argument.  If the calling
 -- thread is not /bound/, a bound thread is created temporarily.
 -- @runInBoundThread@ doesn't finish until the inner computation
@@ -695,16 +710,9 @@
   type Ticket   IO = IO.Ticket
   type ThreadId IO = IO.ThreadId
 
-  fork   = IO.forkIO
-  forkOn = IO.forkOn
-  forkOS = IO.forkOS
-
   forkWithUnmask   = IO.forkIOWithUnmask
   forkOnWithUnmask = IO.forkOnWithUnmask
-
-  forkOSN n ma = forkOS $ do
-    labelMe n
-    ma
+  forkOSWithUnmask = IO.forkOSWithUnmask
 
   forkWithUnmaskN n ma = forkWithUnmask $ \umask -> do
     labelMe n
@@ -714,6 +722,10 @@
     labelMe n
     ma umask
 
+  forkOSWithUnmaskN n ma = forkOSWithUnmask $ \umask -> do
+    labelMe n
+    ma umask
+
   isCurrentThreadBound = IO.isCurrentThreadBound
 
   getNumCapabilities = IO.getNumCapabilities
@@ -778,17 +790,12 @@
   type Ticket   (IsConc m) = Ticket   m
   type ThreadId (IsConc m) = ThreadId m
 
-
-  fork     ma = toIsConc (fork     $ unIsConc ma)
-  forkOn i ma = toIsConc (forkOn i $ unIsConc ma)
-
-  forkOS    ma = toIsConc (forkOS    $ unIsConc ma)
-  forkOSN n ma = toIsConc (forkOSN n $ unIsConc ma)
-
   forkWithUnmask        ma = toIsConc (forkWithUnmask        (\umask -> unIsConc $ ma (\mx -> toIsConc (umask $ unIsConc mx))))
   forkWithUnmaskN   n   ma = toIsConc (forkWithUnmaskN   n   (\umask -> unIsConc $ ma (\mx -> toIsConc (umask $ unIsConc mx))))
   forkOnWithUnmask    i ma = toIsConc (forkOnWithUnmask    i (\umask -> unIsConc $ ma (\mx -> toIsConc (umask $ unIsConc mx))))
   forkOnWithUnmaskN n i ma = toIsConc (forkOnWithUnmaskN n i (\umask -> unIsConc $ ma (\mx -> toIsConc (umask $ unIsConc mx))))
+  forkOSWithUnmask      ma = toIsConc (forkOSWithUnmask      (\umask -> unIsConc $ ma (\mx -> toIsConc (umask $ unIsConc mx))))
+  forkOSWithUnmaskN n   ma = toIsConc (forkOSWithUnmaskN n   (\umask -> unIsConc $ ma (\mx -> toIsConc (umask $ unIsConc mx))))
 
   isCurrentThreadBound = toIsConc isCurrentThreadBound
 
@@ -831,16 +838,12 @@
   type Ticket   (T m) = Ticket m                               ; \
   type ThreadId (T m) = ThreadId m                             ; \
                                                                  \
-  fork   = liftedF F fork                                      ; \
-  forkOn = liftedF F . forkOn                                  ; \
-  forkOS = liftedF F forkOS                                    ; \
-                                                                 \
-  forkOSN = liftedF F . forkOSN                                ; \
-                                                                 \
   forkWithUnmask        = liftedFork F forkWithUnmask          ; \
   forkWithUnmaskN   n   = liftedFork F (forkWithUnmaskN   n  ) ; \
   forkOnWithUnmask    i = liftedFork F (forkOnWithUnmask    i) ; \
   forkOnWithUnmaskN n i = liftedFork F (forkOnWithUnmaskN n i) ; \
+  forkOSWithUnmask      = liftedFork F forkOSWithUnmask        ; \
+  forkOSWithUnmaskN n   = liftedFork F (forkOSWithUnmaskN n  ) ; \
                                                                  \
   isCurrentThreadBound = lift isCurrentThreadBound             ; \
                                                                  \
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -30,9 +30,6 @@
 This used to be part of dejafu, but with the dejafu-0.4.0.0 release,
 it was split out into its own package.
 
-The documentation of the latest developmental version is
-[available online][docs].
-
 Why this and not something else?
 --------------------------------
 
@@ -61,6 +58,5 @@
 Feel free to contact me on GitHub, through IRC (#haskell on freenode),
 or email (mike@barrucadu.co.uk).
 
-[docs]:    https://docs.barrucadu.co.uk/concurrency/dejafu-0.4
 [async]:   https://hackage.haskell.org/package/async
 [parconc]: http://chimera.labs.oreilly.com/books/1230000000929
diff --git a/concurrency.cabal b/concurrency.cabal
--- a/concurrency.cabal
+++ b/concurrency.cabal
@@ -2,7 +2,7 @@
 -- documentation, see http://haskell.org/cabal/users-guide/
 
 name:                concurrency
-version:             1.4.0.2
+version:             1.5.0.0
 synopsis:            Typeclasses, functions, and data types for concurrency and STM.
 
 description:
@@ -32,7 +32,7 @@
 source-repository this
   type:     git
   location: https://github.com/barrucadu/dejafu.git
-  tag:      concurrency-1.4.0.2
+  tag:      concurrency-1.5.0.0
 
 library
   exposed-modules:     Control.Monad.Conc.Class
@@ -55,14 +55,14 @@
 
   -- other-modules:       
   -- other-extensions:    
-  build-depends:       base              >=4.8  && <5
-                     , array             >=0.5  && <0.6
+  build-depends:       base              >=4.9  && <5
+                     , array             >=0.5.1 && <0.6
                      , atomic-primops    >=0.8  && <0.9
                      , exceptions        >=0.7  && <0.11
                      , monad-control     >=1.0  && <1.1
                      , mtl               >=2.2  && <2.3
                      , stm               >=2.4  && <2.5
-                     , transformers      >=0.4  && <0.6
+                     , transformers      >=0.5  && <0.6
   -- hs-source-dirs:      
   default-language:    Haskell2010
   ghc-options:         -Wall
